propagate changes for hsetex with PXAT absolute timestamps#8
Conversation
|
@frostzt PTAL. I changed the implementation foir hincr/hset/hsetnx to not propagate hdel. Still in our case ONLY when |
|
@ranshid can you check once? I am now doing it in 3 stages:
|
hsetex with PXAT absolute timestamps
|
@frostzt this is a big change you placed there :) I am not even sure why you need to go that far.
we need to run a loop calling propagateFieldsDeletion on the collected items and loop to the next collected items based on the value it returned. That is it :) |
Ah forgive me for that I kinda thought of it in a sequential way lemme update this, and thanks a lot for bearing with me 😭 |
src/t_hash.c
Outdated
| } else { | ||
| if (expired_overriten) { | ||
| /* Propagate deletions for expired/non-existent fields in batches */ | ||
| if (keepttl_count > 0) { |
There was a problem hiding this comment.
so keepttl_count and expired_overriten are always identical (if we decide to increment the expired_overriten whenever expired is set by hashTypeSet). I think we need not use 2 different values and we can simply use expired_overriten. I think the propagation logic should be applied here, but only in case keepttl_fields is not NULL.
The reason is that when KEEPTTL is provided the flag is set for ALL fields.
|
@frostzt mostly LGTM. can you please add a test in hashexopire.tcl (you can do something in the inspiration of valkey-io#3036 and place it in the same place I placed all the other tests in valkey-io#3060 |
src/t_hash.c
Outdated
| if (expired) expired_overriten++; | ||
| changes++; | ||
| if (need_rewrite_argv) { | ||
|
|
||
| /* When KEEPTTL is used, we need to track all fields to propagate them | ||
| * individually with their actual timestamps */ | ||
| if ((flags & ARGS_KEEPTTL) && expired) { | ||
| if (keepttl_fields == NULL) { | ||
| keepttl_fields = zmalloc(sizeof(robj *) * num_fields); | ||
| } | ||
| keepttl_fields[expired_overriten] = c->argv[i]; | ||
| incrRefCount(c->argv[i]); |
There was a problem hiding this comment.
@ranshid I think I messed up here! Caught it while running tests locally I increased expired_overriten however we're using that as index which is causing the server to panic, I think a simple post increase should be good?
There was a problem hiding this comment.
Yeh it should be increased after we use it to index the position
|
@frostzt 2 issues:
we should do: this is in order to make sure replicas/import mode and slot migration are operating correctly by forcing the logic instructed by the replication/import/migration stream
I suggest 2 tests for each of the cases a/b: |
|
@frostzt for time constraints I made some of the changes I suggested in my PR. please merge it to yours and focus on the new |
…e-expired-element' into fix-propagate-hsetex-when-expired
Thanks @ranshid just took a pull! is_expired = entry_expiry != EXPIRY_NONE && checkAlreadyExpired(entry_expiry);This essentially is for fields that don't define a TTL. My question now is for |
src/t_hash.c
Outdated
| } | ||
| keepttl_fields[expired_overriten] = c->argv[i]; | ||
| incrRefCount(c->argv[i]); | ||
| } else if (need_rewrite_argv) { |
There was a problem hiding this comment.
we also rewrite the argv when we have the FXX/FNX and NX/XX flags, so we cannot "else if" here
There was a problem hiding this comment.
ok this fixed the test, @ranshid if you don't mind (I'll push the changes) but can you explain this to me a little more?
Your currently implemented logic is fine. In hsetex when we got an indication that we overwritten an expired field and KEEPTTL is used (ONLY THEN) we should ALSO propagate |
src/t_hash.c
Outdated
| } else { | ||
| if (expired_overriten) { | ||
| /* Propagate deletions for expired/non-existent fields in batches */ | ||
| if (keepttl_fields != NULL) { |
There was a problem hiding this comment.
this will mask the next 2 lines which SHOULD be executed even if keepttl_fields is null. keepttl_fields is not NULL only when we overwritten expired fields AND KEEPTTL flag was provided. however even if KEEPTTL was not provided, we might have overwritten some fields which were found to be expired
There was a problem hiding this comment.
I think I just attached my thinking that overritten == overritten with KEEPTTL
There was a problem hiding this comment.
no, so this is why I split the effort. the overwriting of expired keys is a general problem/bug I fixed in my PR. the specific case of KEEPTTL is another issue
|
Thank you sooooo much @frostzt ! |
src/t_hash.c
Outdated
| for (int i = 0; i < expired_overriten; i++) { | ||
| decrRefCount(keepttl_fields[i]); | ||
| } |
There was a problem hiding this comment.
still not sure why this is needed?
There was a problem hiding this comment.
oh checking the code for propagateFieldDeletion I get it my bad again I didn't knew that it does that already!
There was a problem hiding this comment.
yes, the ref count ownership is passed to this function.
I suggest always compile and test with ASAN:
make -j noopt SANITIZER=address OPTIMIZATION=-O0
|
Great @frostzt I will now merge it and take it from here! much much Thank you! |
I honestly don't know if I deserve that but all thanks to you I really wanted to work in Valkey and have been just mesmerizing its code I can assure you the effort you put in to help me means a lot honestly I learned so much I'll keep up and keep contributing into this and hopefully will be able to write much better PRs (that will be easier for you to review 😛 ) |
7faa9a2
into
ranshid:fix-propagate-hdel-when-override-expired-element
…lkey-io#3174) I was working on ASAN large memory tests when I countered this issue. The issue was that the hardcoded `999` key could land in an early bucket. Then shrink rehash could finish early, and later inserts could trigger a new expansion rehash, resetting rehash_idx low. The test now picks the survivor key dynamically as the key mapped to the highest bucket index. ``` [test_hashtable.c] Memory leak detected of 336 bytes ================================================================= ==3901==ERROR: LeakSanitizer: detected memory leaks Direct leak of 80 byte(s) in 1 object(s) allocated from: #0 0x7fb0556fd9c7 in malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69 #1 0x563bfdf4c47d in ztrymalloc_usable_internal /home/runner/work/valkey/valkey/src/zmalloc.c:156 #2 0x563bfdf4c47d in valkey_malloc /home/runner/work/valkey/valkey/src/zmalloc.c:185 #3 0x563bfdd42eaf in hashtableCreate /home/runner/work/valkey/valkey/src/hashtable.c:1217 #4 0x563bfdaa1cbf in test_empty_buckets_rehashing unit/test_hashtable.c:232 #5 0x563bfdae772b in runTestSuite unit/test_main.c:36 #6 0x563bfda86b20 in main unit/test_main.c:108 #7 0x7fb05522a1c9 (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e) #8 0x7fb05522a28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e) valkey-io#9 0x563bfda8a5c4 in _start (/home/runner/work/valkey/valkey/src/valkey-unit-tests+0x17c5c4) (BuildId: 44cfc183e6e82e499bcc9f6adc094d7f774ee9d2) Indirect leak of 128 byte(s) in 1 object(s) allocated from: #0 0x7fb0556fd340 in calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:77 #1 0x563bfdf4c922 in ztrycalloc_usable_internal /home/runner/work/valkey/valkey/src/zmalloc.c:214 #2 0x563bfdf4c922 in valkey_calloc /home/runner/work/valkey/valkey/src/zmalloc.c:257 #3 0x563bfdd40967 in resize /home/runner/work/valkey/valkey/src/hashtable.c:741 #4 0x563bfdd45eb1 in hashtableExpandIfNeeded /home/runner/work/valkey/valkey/src/hashtable.c:1446 #5 0x563bfdd45eb1 in hashtableExpandIfNeeded /home/runner/work/valkey/valkey/src/hashtable.c:1433 #6 0x563bfdd45eb1 in insert /home/runner/work/valkey/valkey/src/hashtable.c:1041 #7 0x563bfdd45eb1 in hashtableAddOrFind /home/runner/work/valkey/valkey/src/hashtable.c:1554 #8 0x563bfdd45eb1 in hashtableAdd /home/runner/work/valkey/valkey/src/hashtable.c:1539 valkey-io#9 0x563bfdaa1e3b in test_empty_buckets_rehashing unit/test_hashtable.c:254 valkey-io#10 0x563bfdae772b in runTestSuite unit/test_main.c:36 valkey-io#11 0x563bfda86b20 in main unit/test_main.c:108 valkey-io#12 0x7fb05522a1c9 (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e) valkey-io#13 0x7fb05522a28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e) valkey-io#14 0x563bfda8a5c4 in _start (/home/runner/work/valkey/valkey/src/valkey-unit-tests+0x17c5c4) (BuildId: 44cfc183e6e82e499bcc9f6adc094d7f774ee9d2) Indirect leak of 64 byte(s) in 1 object(s) allocated from: #0 0x7fb0556fd340 in calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:77 #1 0x563bfdf4c922 in ztrycalloc_usable_internal /home/runner/work/valkey/valkey/src/zmalloc.c:214 #2 0x563bfdf4c922 in valkey_calloc /home/runner/work/valkey/valkey/src/zmalloc.c:257 #3 0x563bfdd3f553 in bucketConvertToChained /home/runner/work/valkey/valkey/src/hashtable.c:908 #4 0x563bfdd3f553 in findBucketForInsert /home/runner/work/valkey/valkey/src/hashtable.c:1021 #5 0x563bfdd45d9e in insert /home/runner/work/valkey/valkey/src/hashtable.c:1045 #6 0x563bfdd45d9e in hashtableAddOrFind /home/runner/work/valkey/valkey/src/hashtable.c:1554 #7 0x563bfdd45d9e in hashtableAdd /home/runner/work/valkey/valkey/src/hashtable.c:1539 #8 0x563bfdaa1e3b in test_empty_buckets_rehashing unit/test_hashtable.c:254 valkey-io#9 0x563bfdae772b in runTestSuite unit/test_main.c:36 valkey-io#10 0x563bfda86b20 in main unit/test_main.c:108 valkey-io#11 0x7fb05522a1c9 (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e) valkey-io#12 0x7fb05522a28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e) valkey-io#13 0x563bfda8a5c4 in _start (/home/runner/work/valkey/valkey/src/valkey-unit-tests+0x17c5c4) (BuildId: 44cfc183e6e82e499bcc9f6adc094d7f774ee9d2) Indirect leak of 64 byte(s) in 1 object(s) allocated from: #0 0x7fb0556fd340 in calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:77 #1 0x563bfdf4c922 in ztrycalloc_usable_internal /home/runner/work/valkey/valkey/src/zmalloc.c:214 #2 0x563bfdf4c922 in valkey_calloc /home/runner/work/valkey/valkey/src/zmalloc.c:257 #3 0x563bfdd40967 in resize /home/runner/work/valkey/valkey/src/hashtable.c:741 #4 0x563bfdaa1df8 in test_empty_buckets_rehashing unit/test_hashtable.c:248 #5 0x563bfdae772b in runTestSuite unit/test_main.c:36 #6 0x563bfda86b20 in main unit/test_main.c:108 #7 0x7fb05522a1c9 (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e) #8 0x7fb05522a28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e) valkey-io#9 0x563bfda8a5c4 in _start (/home/runner/work/valkey/valkey/src/valkey-unit-tests+0x17c5c4) (BuildId: 44cfc183e6e82e499bcc9f6adc094d7f774ee9d2) SUMMARY: AddressSanitizer: 336 byte(s) leaked in 4 allocation(s). ``` Signed-off-by: Sarthak Aggarwal <sarthagg@amazon.com>
Created this so that you can actively review this @ranshid