Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Partial context updates #93

Open
wants to merge 392 commits into
base: dev
Choose a base branch
from
Open

Partial context updates #93

wants to merge 392 commits into from

Conversation

pseusys
Copy link
Collaborator

@pseusys pseusys commented Mar 13, 2023

Description

Context storages are updated partially now instead of reading and writing whole data at once.

Checklist

  • I have covered the code with tests
  • I have added comments to my code to help others understand it
  • I have updated the documentation to reflect the changes
  • I have performed a self-review of the changes
  • Consider extending UpdateScheme from BaseModel
  • Decide how we want to use clear method.

@pseusys pseusys self-assigned this Mar 13, 2023
@pseusys pseusys requested review from kudep and RLKRo April 7, 2023 01:43
@pseusys pseusys added the enhancement New feature or request label Apr 7, 2023
@pseusys pseusys marked this pull request as ready for review April 7, 2023 01:43
@kudep kudep marked this pull request as draft April 24, 2023 16:41
dff/context_storages/database.py Outdated Show resolved Hide resolved
dff/context_storages/update_scheme.py Outdated Show resolved Hide resolved
dff/context_storages/update_scheme.py Outdated Show resolved Hide resolved
dff/context_storages/update_scheme.py Outdated Show resolved Hide resolved
dff/context_storages/update_scheme.py Outdated Show resolved Hide resolved
dff/context_storages/update_scheme.py Outdated Show resolved Hide resolved
dff/context_storages/update_scheme.py Outdated Show resolved Hide resolved
dff/context_storages/json.py Outdated Show resolved Hide resolved
dff/context_storages/update_scheme.py Outdated Show resolved Hide resolved
dff/context_storages/update_scheme.py Outdated Show resolved Hide resolved
dff/context_storages/update_scheme.py Outdated Show resolved Hide resolved
dff/context_storages/update_scheme.py Outdated Show resolved Hide resolved
@pseusys

This comment was marked as outdated.

RLKRo

This comment was marked as outdated.

@pseusys pseusys requested review from ruthenian8, kudep and RLKRo June 14, 2023 23:36
@kudep

This comment was marked as outdated.

@pseusys

This comment was marked as outdated.

@RLKRo RLKRo mentioned this pull request Jul 26, 2023
4 tasks
Comment on lines 305 to 306
async with self.engine.begin() as conn:
await conn.execute(update_stmt)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd be better to define a method for saving context in DBContextStorage (i.e. ContextStorage method that accepts Context and saves it).

That way we can send all changes in one commit because there'd be access to engine from ContextStorage.

Right now we basically do

COMMIT main_info
COMMIT labels_added_modified
COMMIT labels_removed
COMMIT requests_added_modified
COMMIT requests_removed

Instead of a single

COMMIT main_info, labels_added_modified, labels_removed, requests_added_modified, requests_removed

Why this might be relevant: in case one of the methods fails we don't want others to succeed (this will lead to a broken context). And we can also have one place where we can process the errors.

I think we should improve db context storage api as a patch after release.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we could. However, I am not sure that even for SQL databases executing many operations with one "connection" would protect us from breaking context structure (i.e. I don't think that writes will become atomic), however we can try.

del self._items[key]

def __iter__(self) -> Sequence[int]:
return iter(self.keys() if self._storage is not None else self._items.keys())
Copy link
Member

@RLKRo RLKRo Feb 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not yield from self.keys()?
I.e.:

  1. Why not use self.keys() regardless of the _storage?
  2. Why not use yield from?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just forgot yield from construction exists at all, it is not widely used...

node = self.framework_data.current_node
if node is None:
raise ContextError("Current node is not set.")
return node

async def turns(self, key: Union[int, slice]) -> Iterable[Tuple[AbsoluteNodeLabel, Message, Message]]:
Copy link
Member

@RLKRo RLKRo Feb 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make turns a property that returns an instance of a Turns class (needs to be defined) with async __getitem__.
So that the usage of turns is await ctx.turns[1:3] instead of await ctx.turns(slice(1, 3)).

Also, make it so that turns[1] is a single tuple while turns[1:2] is an iterable of tuples.

Comment on lines +175 to +178
if isinstance(key, slice):
return [self._items[k] for k in self.keys()[key]]
else:
return self._items[key]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I don't like about the way slices are processed now is that single key refers to a specific turn while a slice refers to a range of available turns.
So if there are only turns 1, 3, 5 available in ctx_dict, ctx_dict[1:2] == ctx_dict[3], ctx_dict[5], which is very confusing.

I think that there's little use case to getting ctx_dict items by their position in the keys.
So my proposal is:
Allow only

  1. ctx_dict[non-neg-int] -- return element on turn non-neg-int (turn number is a non-negative integer);
  2. ctx_dict[non-neg-int1:non-neg-int2:non-neg-int3] -- return elements starting from turn non-neg-int1 up to non-neg-int2 with a step of non-neg-int3.

(just in case: this proposal is for all the methods)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree

"""

try:
return await self[key]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will always fail if key is Iterable.
This should be rewritten as

await self.load_items(keys if isinstance(keys, Iterable) else [keys])
if isinstance(key, Iterable):
    return [self._items.get(k, default) for k in key]
else:
    return self._items.get(k, default)

Tests for using get with iterable key should be added.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants