mirror of
https://github.com/redis/redis.git
synced 2026-02-03 20:39:54 -05:00
Change reply schema for hotkeys get to use map instead of flat array (#14749)
Follow #14680 Reply of `HOTKEYS GET` is an unordered collection of key-value pairs. It is more reasonable to be a map in resp3 instead of flat array.
This commit is contained in:
parent
319153fe46
commit
591fc90263
3 changed files with 141 additions and 33 deletions
|
|
@ -14,31 +14,98 @@
|
|||
"reply_schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"description": "Flat array with various metrics(tracking-activated, sample-ratio, selected-slots, time/network statistics), collection info (collection-start-time-unix-ms, collection-duration-ms, total-cpu-time-user-ms, total-cpu-time-sys-ms, total-net-bytes), and the requested lists of Top-K hotkeys (available metrics: by-cpu-time-us, by-net-bytes) where at most K hotkeys are returned.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"description": "Map with various metrics (tracking-active, sample-ratio, selected-slots, time/network statistics), collection info (collection-start-time-unix-ms, collection-duration-ms, total-cpu-time-user-ms, total-cpu-time-sys-ms, total-net-bytes), and the requested lists of Top-K hotkeys (available metrics: by-cpu-time-us, by-net-bytes) where at most K hotkeys are returned.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"tracking-active": {
|
||||
"type": "integer",
|
||||
"description": "Whether hotkey tracking is currently active (1) or stopped (0)."
|
||||
},
|
||||
"sample-ratio": {
|
||||
"type": "integer",
|
||||
"description": "The sampling ratio used for tracking."
|
||||
},
|
||||
"selected-slots": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "integer"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
"description": "Array of slot numbers being tracked (empty if tracking all slots)."
|
||||
},
|
||||
"sampled-command-selected-slots-us": {
|
||||
"type": "integer",
|
||||
"description": "CPU time in microseconds for sampled commands in selected slots (only present when sampling and slots are configured)."
|
||||
},
|
||||
"all-commands-selected-slots-us": {
|
||||
"type": "integer",
|
||||
"description": "CPU time in microseconds for all commands in selected slots (only present when slots are configured)."
|
||||
},
|
||||
"all-commands-all-slots-us": {
|
||||
"type": "integer",
|
||||
"description": "CPU time in microseconds for all commands across all slots."
|
||||
},
|
||||
"net-bytes-sampled-commands-selected-slots": {
|
||||
"type": "integer",
|
||||
"description": "Network bytes for sampled commands in selected slots (only present when sampling and slots are configured)."
|
||||
},
|
||||
"net-bytes-all-commands-selected-slots": {
|
||||
"type": "integer",
|
||||
"description": "Network bytes for all commands in selected slots (only present when slots are configured)."
|
||||
},
|
||||
"net-bytes-all-commands-all-slots": {
|
||||
"type": "integer",
|
||||
"description": "Network bytes for all commands across all slots."
|
||||
},
|
||||
"collection-start-time-unix-ms": {
|
||||
"type": "integer",
|
||||
"description": "Unix timestamp in milliseconds when collection started."
|
||||
},
|
||||
"collection-duration-ms": {
|
||||
"type": "integer",
|
||||
"description": "Duration of collection in milliseconds."
|
||||
},
|
||||
"total-cpu-time-user-ms": {
|
||||
"type": "integer",
|
||||
"description": "Total user CPU time in milliseconds (only present when CPU tracking is enabled)."
|
||||
},
|
||||
"total-cpu-time-sys-ms": {
|
||||
"type": "integer",
|
||||
"description": "Total system CPU time in milliseconds (only present when CPU tracking is enabled)."
|
||||
},
|
||||
"total-net-bytes": {
|
||||
"type": "integer",
|
||||
"description": "Total network bytes (only present when NET tracking is enabled)."
|
||||
},
|
||||
"by-cpu-time-us": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "integer"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "Flat array of key-value pairs (key1, cpu_time1, key2, cpu_time2, ...) for top-K hotkeys by CPU time in microseconds (only present when CPU tracking is enabled)."
|
||||
},
|
||||
"by-net-bytes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "integer"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "Flat array of key-value pairs (key1, bytes1, key2, bytes2, ...) for top-K hotkeys by network bytes (only present when NET tracking is enabled)."
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"description": "If no tracking is started",
|
||||
|
|
|
|||
|
|
@ -474,7 +474,7 @@ void hotkeysCommand(client *c) {
|
|||
int has_selected_slots = (server.hotkeys->numslots > 0);
|
||||
int has_sampling = (server.hotkeys->sample_ratio > 1);
|
||||
|
||||
int total_len = 14;
|
||||
int total_len = 7;
|
||||
void *arraylenptr = addReplyDeferredLen(c);
|
||||
|
||||
/* tracking-active */
|
||||
|
|
@ -497,7 +497,7 @@ void hotkeysCommand(client *c) {
|
|||
addReplyBulkCString(c, "sampled-command-selected-slots-us");
|
||||
addReplyLongLong(c, server.hotkeys->time_sampled_commands_selected_slots);
|
||||
|
||||
total_len += 2;
|
||||
total_len++;
|
||||
}
|
||||
|
||||
/* all-commands-selected-slots-us (conditional) */
|
||||
|
|
@ -505,7 +505,7 @@ void hotkeysCommand(client *c) {
|
|||
addReplyBulkCString(c, "all-commands-selected-slots-us");
|
||||
addReplyLongLong(c, server.hotkeys->time_all_commands_selected_slots);
|
||||
|
||||
total_len += 2;
|
||||
++total_len;
|
||||
}
|
||||
|
||||
/* all-commands-all-slots-us */
|
||||
|
|
@ -517,7 +517,7 @@ void hotkeysCommand(client *c) {
|
|||
addReplyBulkCString(c, "net-bytes-sampled-commands-selected-slots");
|
||||
addReplyLongLong(c, server.hotkeys->net_bytes_sampled_commands_selected_slots);
|
||||
|
||||
total_len += 2;
|
||||
++total_len;
|
||||
}
|
||||
|
||||
/* net-bytes-all-commands-selected-slots (conditional) */
|
||||
|
|
@ -526,7 +526,7 @@ void hotkeysCommand(client *c) {
|
|||
addReplyLongLong(c,
|
||||
server.hotkeys->net_bytes_all_commands_selected_slots);
|
||||
|
||||
total_len += 2;
|
||||
++total_len;
|
||||
}
|
||||
|
||||
/* net-bytes-all-commands-all-slots */
|
||||
|
|
@ -550,7 +550,7 @@ void hotkeysCommand(client *c) {
|
|||
addReplyBulkCString(c, "total-cpu-time-sys-ms");
|
||||
addReplyLongLong(c, total_cpu_sys_msec);
|
||||
|
||||
total_len += 4;
|
||||
total_len += 2;
|
||||
}
|
||||
|
||||
/* total-net-bytes - only if NET tracking is enabled */
|
||||
|
|
@ -558,7 +558,7 @@ void hotkeysCommand(client *c) {
|
|||
addReplyBulkCString(c, "total-net-bytes");
|
||||
addReplyLongLong(c, total_net_bytes);
|
||||
|
||||
total_len += 2;
|
||||
++total_len;
|
||||
}
|
||||
|
||||
/* by-cpu-time-us - only if CPU tracking is enabled */
|
||||
|
|
@ -573,7 +573,7 @@ void hotkeysCommand(client *c) {
|
|||
}
|
||||
zfree(cpu);
|
||||
|
||||
total_len += 2;
|
||||
++total_len;
|
||||
}
|
||||
|
||||
/* by-net-bytes - only if NET tracking is enabled */
|
||||
|
|
@ -588,10 +588,10 @@ void hotkeysCommand(client *c) {
|
|||
}
|
||||
zfree(net);
|
||||
|
||||
total_len += 2;
|
||||
++total_len;
|
||||
}
|
||||
|
||||
setDeferredArrayLen(c, arraylenptr, total_len);
|
||||
setDeferredMapLen(c, arraylenptr, total_len);
|
||||
|
||||
} else if (!strcasecmp(sub, "RESET")) {
|
||||
/* HOTKEYS RESET */
|
||||
|
|
|
|||
|
|
@ -351,6 +351,47 @@ start_server {tags {"hotkeys"}} {
|
|||
}
|
||||
}
|
||||
|
||||
start_server {tags {"hotkeys"}} {
|
||||
test {HOTKEYS GET - RESP3 returns map with flat array values for hotkeys} {
|
||||
r hello 3
|
||||
|
||||
assert_equal {OK} [r hotkeys start METRICS 2 CPU NET]
|
||||
r set testkey testvalue
|
||||
assert_equal {OK} [r hotkeys stop]
|
||||
|
||||
set result [r hotkeys get]
|
||||
|
||||
# In RESP3, the outer result is a native map (dict)
|
||||
assert [dict exists $result "tracking-active"]
|
||||
assert [dict exists $result "sample-ratio"]
|
||||
assert [dict exists $result "selected-slots"]
|
||||
assert [dict exists $result "by-cpu-time-us"]
|
||||
assert [dict exists $result "by-net-bytes"]
|
||||
|
||||
# Verify by-cpu-time-us is a flat array [key1, val1, key2, val2, ...]
|
||||
set cpu_array [dict get $result "by-cpu-time-us"]
|
||||
# Flat array length should be even (key-value pairs)
|
||||
assert {[llength $cpu_array] % 2 == 0}
|
||||
# First element is the key name (string), second is the value (integer)
|
||||
set first_key [lindex $cpu_array 0]
|
||||
set first_val [lindex $cpu_array 1]
|
||||
assert_equal "testkey" $first_key
|
||||
assert {[string is integer $first_val]}
|
||||
|
||||
# Verify by-net-bytes is a flat array [key1, val1, key2, val2, ...]
|
||||
set net_array [dict get $result "by-net-bytes"]
|
||||
# Flat array length should be even (key-value pairs)
|
||||
assert {[llength $net_array] % 2 == 0}
|
||||
# First element is the key name (string), second is the value (integer)
|
||||
set first_key [lindex $net_array 0]
|
||||
set first_val [lindex $net_array 1]
|
||||
assert_equal "testkey" $first_key
|
||||
assert {[string is integer $first_val]}
|
||||
|
||||
assert_equal {OK} [r hotkeys reset]
|
||||
}
|
||||
}
|
||||
|
||||
start_cluster 1 0 {tags {external:skip cluster hotkeys}} {
|
||||
|
||||
test {HOTKEYS START - with SLOTS parameter in cluster mode} {
|
||||
|
|
|
|||
Loading…
Reference in a new issue