fix scan parse buf

This commit is contained in:
denniszgyu 2026-01-15 14:26:21 +08:00
parent b059744c5f
commit 83e887fc77

View File

@ -841,53 +841,77 @@ void Handler::handleResponse(ConnectConnection* s, Request* req, Response* res)
} }
} else if (req->type() == Command::Scan && s && res->type() == Reply::Array) { } else if (req->type() == Command::Scan && s && res->type() == Reply::Array) {
SegmentStr<64> str(res->body()); SegmentStr<64> str(res->body());
if (const char* p = strchr(str.data() + sizeof("*2\r\n$"), '\n')) { // SCAN response format: *2\r\n$<len>\r\n<cursor>\r\n*<count>\r\n...
// Use 128-bit integer to handle large cursor values (Kvrocks may return cursor close to 64-bit limit) // Skip "*2\r\n$" (5 bytes) and find the first '\n' after the length number
__uint128_t cursor = 0; // Add boundary check to prevent buffer overflow
const char* cursorStr = p + 1; const char* start = str.data();
const char* cursorStart = cursorStr; int len = str.length();
while (*cursorStr >= '0' && *cursorStr <= '9') { if (len >= 5) {
cursor = cursor * 10 + (*cursorStr - '0'); const char* end = start + len;
cursorStr++; const char* p = start + 5; // Skip "*2\r\n$" (5 bytes, not sizeof which returns 8!)
// Find '\n' within buffer boundary (safer than strchr)
while (p < end && *p != '\n') {
p++;
} }
// Debug log: cursor received from backend server if (p < end) { // Found '\n'
char serverCursorBuf[64]; // Use 128-bit integer to handle large cursor values (Kvrocks may return cursor close to 64-bit limit)
int serverCursorLen = cursorStr - cursorStart; __uint128_t cursor = 0;
if (serverCursorLen > 0 && serverCursorLen < 64) { const char* cursorStr = p + 1;
memcpy(serverCursorBuf, cursorStart, serverCursorLen); const char* cursorStart = cursorStr;
serverCursorBuf[serverCursorLen] = '\0';
} else { // Parse cursor digits within buffer boundary
strcpy(serverCursorBuf, "0"); while (cursorStr < end && *cursorStr >= '0' && *cursorStr <= '9') {
} cursor = cursor * 10 + (*cursorStr - '0');
cursorStr++;
auto g = s->server()->group(); }
int currentGroupId = g ? g->id() : -1;
// Debug log: cursor received from backend server
if (cursor != 0 || (g = sp->getGroup(g->id() + 1)) != nullptr) { char serverCursorBuf[64];
// Use 128-bit integer for left shift, will not overflow int serverCursorLen = cursorStr - cursorStart;
cursor <<= Const::ServGroupBits; if (serverCursorLen > 0 && serverCursorLen < 64) {
cursor |= g->id(); memcpy(serverCursorBuf, cursorStart, serverCursorLen);
if ((p = strchr(p, '*')) != nullptr) { serverCursorBuf[serverCursorLen] = '\0';
// Convert 128-bit integer to string } else {
char buf[64]; // 128-bit needs at most 39 decimal digits strcpy(serverCursorBuf, "0");
int n = Util::uint128ToString(cursor, buf); }
// Debug log: cursor to be sent to client auto g = s->server()->group();
logDebug("h %d SCAN cursor from server: %s, group: %d, cursor to client: %s", int currentGroupId = g ? g->id() : -1;
id(), serverCursorBuf, g->id(), buf);
if (cursor != 0 || (g = sp->getGroup(g->id() + 1)) != nullptr) {
res->head().fset(nullptr, // Use 128-bit integer for left shift, will not overflow
"*2\r\n" cursor <<= Const::ServGroupBits;
"$%d\r\n" cursor |= g->id();
"%s\r\n",
n, buf); // Find '*' within buffer boundary
res->body().cut(p - str.data()); const char* asteriskPos = p + 1;
while (asteriskPos < end && *asteriskPos != '*') {
asteriskPos++;
}
if (asteriskPos < end) { // Found '*'
// Convert 128-bit integer to string
char buf[64]; // 128-bit needs at most 39 decimal digits
int n = Util::uint128ToString(cursor, buf);
// Debug log: cursor to be sent to client
logDebug("h %d SCAN cursor from server: %s, group: %d, cursor to client: %s",
id(), serverCursorBuf, g->id(), buf);
res->head().fset(nullptr,
"*2\r\n"
"$%d\r\n"
"%s\r\n",
n, buf);
res->body().cut(asteriskPos - start);
}
} else {
// Scan completed, return 0 to client
logDebug("h %d SCAN cursor from server: %s, group: %d, cursor to client: 0 (scan complete)",
id(), serverCursorBuf, currentGroupId);
} }
} else {
// Scan completed, return 0 to client
logDebug("h %d SCAN cursor from server: %s, group: %d, cursor to client: 0 (scan complete)",
id(), serverCursorBuf, currentGroupId);
} }
} }
} }