Discussed in https://github.com/redis/redis/discussions/11523
Comment From: gkorland
@baytekink I'm not sure I get the issue, what would you expect?
Comment From: baytekink
@baytekink I'm not sure I get the issue, what would you expect?
I expect that, i can not read while written to redis db in a transaction. After the transaction finished, i can read all data. But current behaviour is when 100 hash key is writing to db, I can read 95 of them and cursor return 0 after 95 hash keys. But actual data is 100 hash keys. So I missed 5 hash keys.
Comment From: oranagra
expect that, i can not read while written to redis db in a transaction. After the transaction finished, i can read all data
that's what actually happening, the MULTI-EXEC "transaction", is executed as a whole, and part of your SCAN calls are running before it, and some after it (the SCAN command doesn't run in the middle of the "transaction"). however, because SCAN / HSCAN is iterative (unlike KEYS or HKEYS), part of your iteration sweep runs before the transaction and part of it after, and this way some hash slots where new keys are inserted by HSET were already covered by earlier calls to HSCAN and therefore they won't be visible for that sweep, while after are added to hash buckets that HSCAN didn't reach yet, and they'll be returned.
You may refer to the Scan guarantees section in https://redis.io/commands/scan/
Comment From: baytekink
Thx for the explanation, but the hash keys are in same transaction scope. If it happens as you wrote here, it is ok for me. But in transaction, there are 10 hash keys trying to write, and scan reads 1 of them or 3 of them while other 7 is trying to write in same transaction. If you can generate a test you will see what i mean. Just in a for loop write new 10 hash keys to same main key, and in another thread try to read main key by hscan. You will see that you will read 33 keys, or 51 keys which is can not divide by 10. If it happens as you suggest, hscan must return 30, 40, 50, ... keys.
Comment From: oranagra
i'm not sure i follow your last message, but i'll try to give an example:
| client 1 | client 2 | comments |
| --- | --- | --- |
| | hset k 1 a 2 a 3 a 4 a | set all fields to 'a'|
|hscan k 0| | scans several buckets, e.g. return 1 and 3 with their value 'a'|
| | hset k 1 b 2 b 3 b 4 b | set all fields to 'b'|
| hscan k <cursor> | | returns the more dict buckets. e.g. return 2 and 4 with the value 'b'|
| hscan k <cursor> | | returns a cursor of 0 to indicate the iteration ended.
so a single sweep though the hash doesn't cover a single point in time, but it does guarantee that all the keys that existed for the entire duration of the scan will be emitted exactly once. but once added or deleted during the scan, can be either emitted or missing.