-
Notifications
You must be signed in to change notification settings - Fork 1.1k
fix: no set/hmap expiration during serialization #5349
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
fix: no set/hmap expiration during serialization #5349
Conversation
55bd977
to
1d64bb1
Compare
There are counter examples towards both approaches, and the problem is not black and white, so it's important to identify "not well defined" issues and avoid arguing around them too much because it's not productive. Instead, once a not well defined issue is identified with cons and pros, the best course of actions is to list them in the PR in an objective way and ask the product owner (which is me) what's the best course of action. I prefer to limit the scope of this PR to the original issue and fix only the loader part. In the long run we probably should fix the algorithmics behind the expired set and introduce sorted queue of expired times but it's not a priority. |
If we decide to leave expiration, I need to remove a key (if set/hmap is zero size) during the serialization process (to me it looks quite strange) |
Talked to @BorysTheDev offline and it seems his solution is the only one possible at the moment without doing too much changes in the saving code. The reason for that is that we assume immutability of the entries at lease at the interface level (see SliceSnapshot::SerializeEntry). |
1d64bb1
to
8792be6
Compare
48574b8
to
37559e1
Compare
37559e1
to
44f18ff
Compare
src/server/rdb_load.cc
Outdated
} | ||
return; | ||
item->load_config.append = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do you set it to false? only to check if to return in line 2588? instead can you check if append_res is valid there?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This flag is also checked in CreateHMap and CreateSet. Unfortunately, the loading logic isn't straightforward, and it is hard to do changes.
src/server/rdb_load.cc
Outdated
// If the item has expired we may not find the key. Note if the key | ||
// is found, but expired since we started loading, we still append to | ||
// avoid an inconsistent state where only part of the key is loaded. | ||
if (item->expire_ms == 0 || db_cntx.time_now_ms < item->expire_ms) { | ||
// we avoid expiration for values inside RDB_TYPE_HASH_WITH_EXPIRY so the object can unexist | ||
if ((item->val.rdb_type != RDB_TYPE_HASH_WITH_EXPIRY && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure what is this check error, is it to detect internal error flow ?
anyway I think a better way to do this is instead of checking the rdb type is checking if items this item went through the errc::value_expired flow, so you can add to item a field to be set in the case where you have the expired items which is not error flow and than check if this filed is not set in this condition
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've tried this approach, but for one entity we can create a lot of items so this approach doesn;t work. This check helps detect the bugs, because during loading we shouldn't expire any streaming objects execpt hmap and sset
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- The condition is very complicated. lets factor out it to two variables for readability:
bool key_not_expired = item->expire_ms == 0 || db_cntx.time_now_ms < item->expire_ms
bool set_not_expired = item->val.rdb_type != RDB_TYPE_SET_WITH_EXPIRY && ...
then usingkey_not_expired && set_not_expired
is more clear - overriding
item->load_config.append
does not justify mutability. Create a temporary LoadConfig with overridden field and pass it toFromOpaque
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And add a comment of why you need to override it (i.e. to create a new key because the previous batches of items for that key were fully expired).
src/server/rdb_load.cc
Outdated
// If the item has expired we may not find the key. Note if the key | ||
// is found, but expired since we started loading, we still append to | ||
// avoid an inconsistent state where only part of the key is loaded. | ||
if (item->expire_ms == 0 || db_cntx.time_now_ms < item->expire_ms) { | ||
// we avoid expiration for values inside RDB_TYPE_HASH_WITH_EXPIRY so the object can unexist | ||
if ((item->val.rdb_type != RDB_TYPE_HASH_WITH_EXPIRY && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- The condition is very complicated. lets factor out it to two variables for readability:
bool key_not_expired = item->expire_ms == 0 || db_cntx.time_now_ms < item->expire_ms
bool set_not_expired = item->val.rdb_type != RDB_TYPE_SET_WITH_EXPIRY && ...
then usingkey_not_expired && set_not_expired
is more clear - overriding
item->load_config.append
does not justify mutability. Create a temporary LoadConfig with overridden field and pass it toFromOpaque
src/server/rdb_load.cc
Outdated
// If the item has expired we may not find the key. Note if the key | ||
// is found, but expired since we started loading, we still append to | ||
// avoid an inconsistent state where only part of the key is loaded. | ||
if (item->expire_ms == 0 || db_cntx.time_now_ms < item->expire_ms) { | ||
// we avoid expiration for values inside RDB_TYPE_HASH_WITH_EXPIRY so the object can unexist | ||
if ((item->val.rdb_type != RDB_TYPE_HASH_WITH_EXPIRY && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And add a comment of why you need to override it (i.e. to create a new key because the previous batches of items for that key were fully expired).
fixes: #5299
problem: we do expiration during serialization and save 0-size hmap or set that is incorrect
fix: avoid expiration during serialization and filter out expired hmap and set during loading