Skip to content

Commit

Permalink
Trim free space from inline command argument strings to avoid excess …
Browse files Browse the repository at this point in the history
…memory usage (valkey-io#1213)

The command argument strings created while parsing inline commands (see
`processInlineBuffer()`) can contain free capacity. Since some commands
,such as `SET`, store these strings in the database, that free capacity
increases the memory usage. In the worst case, it could double the
memory usage.

This only occurs if the inline command format is used. The argument
strings are built by appending character by character in
`sdssplitargs()`. Regular RESP commands are not affected.

This change trims the strings within `processInlineBuffer()`.

### Why `trimStringObjectIfNeeded()` within `object.c` is not solving
this?

When the command argument string is packed into an object,
`trimStringObjectIfNeeded()` is called.

This does only trim the string if it is larger than
`PROTO_MBULK_BIG_ARG` (32kB), as only strings larger than this would
ever need trimming if the command it sent using the bulk string format.

We could modify this condition, but that would potentially have a
performance impact on commands using the bulk format. Since those make
up for the vast majority of executed commands, limiting this change to
inline commands seems prudent.

### Experiment Results

* 1 million `SET [key] [value]` commands
* Random keys (16 bytes)
* 600 bytes values

Memory usage without this change:

```
used_memory:1089327888
used_memory_human:1.01G
used_memory_rss:1131696128
used_memory_rss_human:1.05G
used_memory_peak:1089348264
used_memory_peak_human:1.01G
used_memory_peak_perc:100.00%
used_memory_overhead:49302800
used_memory_startup:911808
used_memory_dataset:1040025088
used_memory_dataset_perc:95.55%
```

Memory usage with this change:
```
used_memory:705327888
used_memory_human:672.65M
used_memory_rss:718802944
used_memory_rss_human:685.50M
used_memory_peak:705348256
used_memory_peak_human:672.67M
used_memory_peak_perc:100.00%
used_memory_overhead:49302800
used_memory_startup:911808
used_memory_dataset:656025088
used_memory_dataset_perc:93.13%
```

If the same experiment is repeated using the normal RESP array of bulk
string format (`*3\r\n$3\r\nSET\r\n...`) then the memory usage is 672MB
with and without of this change.

If a replica is attached, its memory usage is 672MB with and without
this change, since the replication link never uses inline commands.

Signed-off-by: Stefan Mueller <[email protected]>
  • Loading branch information
muelstefamzn authored Oct 23, 2024
1 parent c176de4 commit c419524
Showing 1 changed file with 2 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/networking.c
Original file line number Diff line number Diff line change
Expand Up @@ -2669,6 +2669,8 @@ void processInlineBuffer(client *c) {

/* Create an Object for all arguments. */
for (c->argc = 0, j = 0; j < argc; j++) {
/* Strings returned from sdssplitargs() may have unused capacity that we can trim. */
argv[j] = sdsRemoveFreeSpace(argv[j], 1);
c->argv[c->argc] = createObject(OBJ_STRING, argv[j]);
c->argc++;
c->argv_len_sum += sdslen(argv[j]);
Expand Down

0 comments on commit c419524

Please sign in to comment.