listpack: add lpFindInteger() to avoid string conversion in set integ…#3410
listpack: add lpFindInteger() to avoid string conversion in set integ…#3410liveprasad wants to merge 4 commits into
Conversation
…er search When a set command like SADD receives an integer value and the set is listpack-encoded, the previous code converted the integer to a string to call lpFind(), which then converted it back to an integer internally. Add lpFindInteger() that accepts a long long directly and compares against integer-encoded listpack entries without any string conversion. Use it in setTypeAdd() when the value arrived as an integer (str == tmpbuf). Fixes valkey-io#3408 Signed-off-by: liveprasad <prasad.shetkar093@gmail.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## unstable #3410 +/- ##
============================================
- Coverage 76.72% 76.52% -0.20%
============================================
Files 159 159
Lines 79681 79715 +34
============================================
- Hits 61135 61003 -132
- Misses 18546 18712 +166
🚀 New features to boost your workflow:
|
dvkashapov
left a comment
There was a problem hiding this comment.
Not an expert in listpacks, just took a look at lpFind() for comparison and have a couple of questions.
| p += skip_entry_size; | ||
| } | ||
| /* Safety: ensure we don't walk past the end */ | ||
| if (p >= lp + lp_bytes) break; |
There was a problem hiding this comment.
lpFind() has this guard after every add to p:
if (p + 8 >= lp + lp_bytes)
lpAssertValidEntry(lp, lp_bytes, p);
else
assert(p >= lp + LP_HDR_SIZE && p < lp + lp_bytes);
if (unlikely(p[0] == LP_EOF)) {
/* EOF must only appear at the end of a listpack. */
assert(p + 1 == lp + lp_bytes);
break;
}Do we also need LP_EOF check in lpFindInteger()?
| skipcnt--; | ||
| uint64_t skip_entry_size; | ||
| lpGetWithSize(p, &ll, NULL, &skip_entry_size); | ||
| p += skip_entry_size; |
There was a problem hiding this comment.
lpFind() uses lpSkip(p) with the explicit comment:
/* Move to next entry, avoid use `lpNext` due to `lpAssertValidEntry` in
* `lpNext` will call `lpBytes`, will cause performance degradation */
p = lpSkip(p);Do we need to do the same here to not do a full get? Looks like lpSkip() reads only the encoding to determine entry length.
| lpFree(lp); | ||
| } | ||
|
|
||
| TEST_F(ListpackTest, listpackLpFindInteger) { |
- Use lpSkip() in the skip branch instead of lpGetWithSize() to avoid unnecessary entry decoding when skipping entries - Add LP_EOF check matching lpFind() pattern for safe listpack traversal - Add test case verifying string "42" and integer 42 find the same entry Fixes valkey-io#3408 Signed-off-by: liveprasad <prasad.shetkar093@gmail.com>
| if (str == tmpbuf) { | ||
| p = lpFindInteger(lp, p, llval, 0); |
There was a problem hiding this comment.
When we lookup by integer, can we even avoid converting to string above?
/* Convert int to string. */
len = ll2string(tmpbuf, sizeof tmpbuf, llval);I don't know how to structur this in a nice way. Maybe move the listpack-with-integer handlig to the if (!str) { ... } block above?
There was a problem hiding this comment.
Good point. To avoid ll2string() entirely for the listpack path,
we'd need to handle listpack inside the if (!str) block before
line 137. Would you prefer that restructuring(Not completely trivial though), or is the current
approach (avoiding the re-conversion inside lpFind) acceptable?
Signed-off-by: liveprasad <prasad.shetkar093@gmail.com>
sarthakaggarwal97
left a comment
There was a problem hiding this comment.
Thanks! @liveprasad

Summary
Add
lpFindInteger()tolistpack.cto avoid an integer→string→integerround-trip when searching for integers in listpack-encoded sets.
Previously,
setTypeAdd()converted integers to strings to calllpFind(),which then called
string2ll()internally to convert back. This resolvesthe existing TODO comment at
src/t_set.c:168.Changes
src/listpack.c— addlpFindInteger(lp, p, v, skip)src/listpack.h— declare itsrc/t_set.c— use it whenstr == tmpbuf; remove TODO commentsrc/unit/test_listpack.cpp— addlistpackLpFindIntegertestFixes #3408