-
Notifications
You must be signed in to change notification settings - Fork 23.9k
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
Optimize SET/INCR*/DECR*/SETRANGE/APPEND by reducing duplicate computation #13505
Conversation
…void multiple sdslen calls with the same input on setrangeCommand and appendCommand.
… optional dictEntry input: Avoids the second dictFind in SET command
Automated performance analysis summaryThis comment was automatically generated given there is performance data available. Using platform named: intel64-ubuntu22.04-redis-icx1 to do the comparison. In summary:
You can check a comparison in detail via the grafana link Comparison between unstable and perf.incrby.Time Period from 5 months ago. (environment used: oss-standalone) Improvements Table
Improvements test regexp names: memtier_benchmark-1Mkeys-load-string-with-100B-values-pipeline-10|memtier_benchmark-1Mkeys-load-string-with-10B-values-pipeline-10|memtier_benchmark-1Mkeys-string-append-1-100B-pipeline-10|memtier_benchmark-1Mkeys-string-incrby-pipeline-10|memtier_benchmark-1Mkeys-string-incrbyfloat-pipeline-10|memtier_benchmark-1Mkeys-string-setex-100B-pipeline-10|memtier_benchmark-1Mkeys-string-setrange-100B-pipeline-10 Full Results table:
|
…ts an optional dictEntry input: Avoids the second kvstoreDictFind in SETEX command
Co-authored-by: debing.sun <[email protected]>
…UnshareStringValueWithDictEntry. Commented the dictEntry reference input in lookupKey()
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.
LGTM. (assuming all comments are addressed)
Co-authored-by: debing.sun <[email protected]>
Co-authored-by: debing.sun <[email protected]>
### New Features in binary distributions - 7 new data structures: JSON, Time series, Bloom filter, Cuckoo filter, Count-min sketch, Top-k, t-digest - Redis scalable query engine (including vector search) ### Potentially breaking changes - #12272 `GETRANGE` returns an empty bulk when the negative end index is out of range - #12395 Optimize `SCAN` command when matching data type ### Bug fixes - #13510 Fix `RM_RdbLoad` to enable AOF after RDB loading is completed - #13489 `ACL CAT` - return module commands - #13476 Fix a race condition in the `cache_memory` of `functionsLibCtx` - #13473 Fix incorrect lag due to trimming stream via `XTRIM` command - #13338 Fix incorrect lag field in `XINFO` when tombstone is after the `last_id` of the consume group - #13470 On `HDEL` of last field - update the global hash field expiration data structure - #13465 Cluster: Pass extensions to node if extension processing is handled by it - #13443 Cluster: Ensure validity of myself when loading cluster config - #13422 Cluster: Fix `CLUSTER SHARDS` command returns empty array ### Modules API - #13509 New API calls: `RM_DefragAllocRaw`, `RM_DefragFreeRaw`, and `RM_RegisterDefragCallbacks` - defrag API to allocate and free raw memory ### Performance and resource utilization improvements - #13503 Avoid overhead of comparison function pointer calls in listpack `lpFind` - #13505 Optimize `STRING` datatype write commands - #13499 Optimize `SMEMBERS` command - #13494 Optimize `GEO*` commands reply - #13490 Optimize `HELLO` command - #13488 Optimize client query buffer - #12395 Optimize `SCAN` command when matching data type - #13529 Optimize `LREM`, `LPOS`, `LINSERT`, and `LINDEX` commands - #13516 Optimize `LRANGE` and other commands that perform several writes to client buffers per call - #13431 Avoid `used_memory` contention when updating from multiple threads ### Other general improvements - #13495 Reply `-LOADING` on replica while flushing the db ### CLI tools - #13411 redis-cli: Fix wrong `dbnum` showed after the client reconnected ### Notes - No backward compatibility for replication or persistence. - Additional distributions, upgrade paths, features, and improvements will be introduced in upcoming pre-releases. - With the GA release of 8.0 we will deprecate Redis Stack.
} else { | ||
dbAdd(c->db,c->argv[1],new); | ||
} | ||
} | ||
signalModifiedKey(c,c->db,c->argv[1]); | ||
notifyKeyspaceEvent(NOTIFY_STRING,"incrby",c->argv[1],c->db->id); | ||
server.dirty++; | ||
addReplyLongLong(c, value); | ||
addReplyLongLongFromStr(c,new); |
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 change can cause use-after-free in the tests/unit/moduleapi/keyspace_events.tcl
test, when the test uses RM_StringDMA to modify the value from within the KSN, and this command uses it after it was released.
the reason it doesn't happen is because the eviction policy allows for shared integers, so despite "releasing" this object from within the KSN. it doesn't free the memory.
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 can be solved by moving the reply a few lines upwards.
we can also argue that the module is violating redis, but it used to work so far (specifically for INCR), and the optimization broke it, so shall we fix that?
WDYT?
in redis#13505, we changed the code to use the string value of the key rather than the integer value on the stack, but we have a test in unit/moduleapi/keyspace_events that uses keyspace notification hook to modify the value with RM_StringDMA, which can cause this value to be released before used. the reason it didn't happen so far is because we were using shared integers, so releasing the object doesn't free it.
in #13505, we changed the code to use the string value of the key rather than the integer value on the stack, but we have a test in unit/moduleapi/keyspace_events that uses keyspace notification hook to modify the value with RM_StringDMA, which can cause this value to be released before used. the reason it didn't happen so far is because we were using shared integers, so releasing the object doesn't free it.
TODO:
Hotspot data that triggered this effort
Hotspots sample on incrDecr* commands (we can save 3.3% on the 2nd dictFind)
Hotspots on set command (we can save 2.1% on the 2nd dictFind)

Measuring the improvements
Improvements on STRING SET command
Throughput
Avg. Latency
Improvements on INCRBY command
Baseline
Comparison