-
Notifications
You must be signed in to change notification settings - Fork 702
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
Directly store score as double in the dict of zset. #959
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## unstable #959 +/- ##
============================================
- Coverage 70.70% 70.51% -0.20%
============================================
Files 114 114
Lines 63157 63163 +6
============================================
- Hits 44653 44537 -116
- Misses 18504 18626 +122
|
cad722d
to
bb97035
Compare
src/dict.c
Outdated
/* Add an element with double value to the target hash table */ | ||
int dictAddDoubleVal(dict *d, void *key, double val) { | ||
dictEntry *entry = dictAddRaw(d, key, NULL); | ||
|
||
if (!entry) return DICT_ERR; | ||
if (!d->type->no_value) dictSetDoubleVal(entry, val); | ||
return DICT_OK; | ||
} | ||
|
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.
You don't need to introduce this new method and expose it. Rather you could do it in a pair of operation, create a dict entry and set the value.
dictAddRaw(...);
dictSetDoubleVal(...);
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.
Thanks for your advice, the dictSetDoubleVal
function has been removed.
@RayaCoo Could you run some benchmark around this to check if there is any performance gain? |
I don't see any performance gain/drop with valkey-benchmark |
eb7cbc3
to
6ba3019
Compare
Due to personal reasons, I haven't completed the tests and replied on time and I'm sorry about that. Simple summary:For Considering measurement variance, the performance improvements may fluctuate, but it does enhance the performance of certain commands. For code readability, I think maybe directly use double field to store score is more intuitive for humans. Test Method and ResultZADDtest method
result
ZSCOREtest method
ps: The addDataToZset script is used to add elements in the format {member_n: n} to a specific key's zset, n is a value between the specified min and max. result
ZRANKtest method
result
This PR
ZINTER[STORE]test method
result
ZUNION[STORE]test method
result
ZDIFF[STORE]test method
result
|
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 suppose a downside of this is now there is more room for error.
src/defrag.c
Outdated
if (newscore) { | ||
dictSetVal(zs->dict, de, newscore); | ||
dictSetDoubleVal(de, *newscore); | ||
} |
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.
We no longer need to do this defragmentation in your proposal, since the value at newscore will be the same as before. You should be able to delete this whole if statement and change the return type of zslDefrag.
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.
Yeah, You're right, I've fixed that as you suggested.
6ba3019
to
faf87c9
Compare
Signed-off-by: Ray Cao <[email protected]>
faf87c9
to
22db305
Compare
Signed-off-by: Ray Cao <[email protected]>
7434c64
to
49cad34
Compare
Could you explain this a bit more? |
Sorry. I meant that we are now independently maintaining the double value in two places as opposed to a pointer to a value. There is more risk for them diverging. If the pointer is wrong it'll probably crash, if the double is wrong it'll just be a silent divergent. |
I have simply changed the way we modify and retrieve the score in zset to use the double value directly. The modifications are always made in pairs (first updating the skiplist, then the dict). Additionally, our current tests have not revealed any issues with this approach. |
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'm going to merge this, any other suggestions?
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.
It's a clever optimization, but it blocks some other optimizations that are in the making. See my previous comment.
Closing this PR as the underlying structure has been changed. Nevertheless thanks for your work though @RayaCoo. |
In the past, we used
void *
for dict to store the score of elements in zset. This mean we had to dereference the score ervey time we accesse it. For example,*(double *)dictGetVal(de)
. This added extra dereference overhead, and forzunion[store]
command, value of dict has been set twice. like this :Since double field has been add in dictEntry value union by commit, and for zset, the value stored in dict will always be double type, we can directly store score as double, which can improves the code's readability and reduces extra dereferencing overhead.