-
Notifications
You must be signed in to change notification settings - Fork 0
Fix HINCRBYFLOAT removes field expiration on replica #21
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
base: coderabbit_combined_20260121_augment_sentry_coderabbit_1_base_fix_hincrbyfloat_removes_field_expiration_on_replica_pr104
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -706,24 +706,29 @@ GetFieldRes hashTypeGetFromHashTable(robj *o, sds field, sds *value, uint64_t *e | |
| * If *vll is populated *vstr is set to NULL, so the caller can | ||
| * always check the function return by checking the return value | ||
| * for GETF_OK and checking if vll (or vstr) is NULL. | ||
| * expiredAt - if the field has an expiration time, it will be set to the expiration | ||
| * time of the field. Otherwise, will be set to EB_EXPIRE_TIME_INVALID. | ||
| * | ||
| */ | ||
| GetFieldRes hashTypeGetValue(redisDb *db, robj *o, sds field, unsigned char **vstr, | ||
| unsigned int *vlen, long long *vll, int hfeFlags) { | ||
| uint64_t expiredAt; | ||
| unsigned int *vlen, long long *vll, int hfeFlags, uint64_t *expiredAt) | ||
| { | ||
| sds key; | ||
| GetFieldRes res; | ||
| uint64_t dummy; | ||
| if (expiredAt == NULL) expiredAt = &dummy; | ||
|
|
||
| if (o->encoding == OBJ_ENCODING_LISTPACK || | ||
| o->encoding == OBJ_ENCODING_LISTPACK_EX) { | ||
| *vstr = NULL; | ||
| res = hashTypeGetFromListpack(o, field, vstr, vlen, vll, &expiredAt); | ||
| res = hashTypeGetFromListpack(o, field, vstr, vlen, vll, expiredAt); | ||
|
|
||
| if (res == GETF_NOT_FOUND) | ||
| return GETF_NOT_FOUND; | ||
|
|
||
| } else if (o->encoding == OBJ_ENCODING_HT) { | ||
| sds value = NULL; | ||
| res = hashTypeGetFromHashTable(o, field, &value, &expiredAt); | ||
| res = hashTypeGetFromHashTable(o, field, &value, expiredAt); | ||
|
|
||
| if (res == GETF_NOT_FOUND) | ||
| return GETF_NOT_FOUND; | ||
|
|
@@ -734,7 +739,7 @@ GetFieldRes hashTypeGetValue(redisDb *db, robj *o, sds field, unsigned char **vs | |
| serverPanic("Unknown hash encoding"); | ||
| } | ||
|
|
||
| if (expiredAt >= (uint64_t) commandTimeSnapshot()) | ||
| if (*expiredAt > (uint64_t) commandTimeSnapshot()) | ||
| return GETF_OK; | ||
|
|
||
| if (server.masterhost) { | ||
|
|
@@ -794,7 +799,7 @@ robj *hashTypeGetValueObject(redisDb *db, robj *o, sds field, int hfeFlags, int | |
| long long vll; | ||
|
|
||
| if (isHashDeleted) *isHashDeleted = 0; | ||
| GetFieldRes res = hashTypeGetValue(db,o,field,&vstr,&vlen,&vll, hfeFlags); | ||
| GetFieldRes res = hashTypeGetValue(db,o,field,&vstr,&vlen,&vll, hfeFlags, NULL); | ||
|
|
||
| if (res == GETF_OK) { | ||
| if (vstr) return createStringObject((char*)vstr,vlen); | ||
|
|
@@ -823,7 +828,7 @@ int hashTypeExists(redisDb *db, robj *o, sds field, int hfeFlags, int *isHashDel | |
| unsigned int vlen = UINT_MAX; | ||
| long long vll = LLONG_MAX; | ||
|
|
||
| GetFieldRes res = hashTypeGetValue(db, o, field, &vstr, &vlen, &vll, hfeFlags); | ||
| GetFieldRes res = hashTypeGetValue(db, o, field, &vstr, &vlen, &vll, hfeFlags, NULL); | ||
| if (isHashDeleted) | ||
| *isHashDeleted = (res == GETF_EXPIRED_HASH) ? 1 : 0; | ||
| return (res == GETF_OK) ? 1 : 0; | ||
|
|
@@ -2195,7 +2200,7 @@ void hincrbyCommand(client *c) { | |
| if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return; | ||
|
|
||
| GetFieldRes res = hashTypeGetValue(c->db,o,c->argv[2]->ptr,&vstr,&vlen,&value, | ||
| HFE_LAZY_EXPIRE); | ||
| HFE_LAZY_EXPIRE, NULL); | ||
| if (res == GETF_OK) { | ||
| if (vstr) { | ||
| if (string2ll((char*)vstr,vlen,&value) == 0) { | ||
|
|
@@ -2234,6 +2239,9 @@ void hincrbyfloatCommand(client *c) { | |
| sds new; | ||
| unsigned char *vstr; | ||
| unsigned int vlen; | ||
| int has_expiration = 0; | ||
| uint64_t expireat = EB_EXPIRE_TIME_INVALID; | ||
| int unused_flag = 0; | ||
|
|
||
| if (getLongDoubleFromObjectOrReply(c,c->argv[3],&incr,NULL) != C_OK) return; | ||
| if (isnan(incr) || isinf(incr)) { | ||
|
|
@@ -2242,7 +2250,7 @@ void hincrbyfloatCommand(client *c) { | |
| } | ||
| if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return; | ||
| GetFieldRes res = hashTypeGetValue(c->db, o,c->argv[2]->ptr,&vstr,&vlen,&ll, | ||
| HFE_LAZY_EXPIRE); | ||
| HFE_LAZY_EXPIRE, &expireat); | ||
| if (res == GETF_OK) { | ||
| if (vstr) { | ||
| if (string2ld((char*)vstr,vlen,&value) == 0) { | ||
|
|
@@ -2252,6 +2260,8 @@ void hincrbyfloatCommand(client *c) { | |
| } else { | ||
| value = (long double)ll; | ||
| } | ||
| /* Field has expiration time. */ | ||
| if (expireat != EB_EXPIRE_TIME_INVALID) has_expiration = 1; | ||
| } else if ((res == GETF_NOT_FOUND) || (res == GETF_EXPIRED)) { | ||
| value = 0; | ||
| } else { | ||
|
|
@@ -2284,6 +2294,24 @@ void hincrbyfloatCommand(client *c) { | |
| rewriteClientCommandArgument(c,0,shared.hset); | ||
| rewriteClientCommandArgument(c,3,newobj); | ||
| decrRefCount(newobj); | ||
|
|
||
| if (has_expiration) { | ||
| /* To make sure that the HSET command is propagated before the HPEXPIREAT, | ||
| * we need to prevent the HSET command from being propagated, and then | ||
| * propagate both commands manually in the correct order. */ | ||
| preventCommandPropagation(c); | ||
| /* Propagate HSET */ | ||
| alsoPropagate(c->db->id, c->argv, c->argc, PROPAGATE_AOF|PROPAGATE_REPL); | ||
| /* Propagate HPEXPIREAT */ | ||
| robj *argv[5]; | ||
| argv[0] = shared.hpexpireat; | ||
| argv[1] = c->argv[1]; | ||
| argv[2] = createStringObjectFromLongLong(expireat); | ||
| argv[3] = shared.fields; | ||
| argv[4] = shared.integers[1]; | ||
| argv[5] = c->argv[2]; | ||
| alsoPropagate(c->db->id, argv, 6, PROPAGATE_AOF|PROPAGATE_REPL); | ||
| } | ||
|
Comment on lines
+2306
to
+2314
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Critical: Buffer overflow in argv array declaration. The array is declared with 5 elements ( 🐛 Proposed fix- robj *argv[5];
+ robj *argv[6];
argv[0] = shared.hpexpireat;
argv[1] = c->argv[1];
argv[2] = createStringObjectFromLongLong(expireat);
argv[3] = shared.fields;
argv[4] = shared.integers[1];
argv[5] = c->argv[2];
alsoPropagate(c->db->id, argv, 6, PROPAGATE_AOF|PROPAGATE_REPL);
+ decrRefCount(argv[2]);
}🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| static GetFieldRes addHashFieldToReply(client *c, robj *o, sds field, int hfeFlags) { | ||
|
|
@@ -2296,7 +2324,7 @@ static GetFieldRes addHashFieldToReply(client *c, robj *o, sds field, int hfeFla | |
| unsigned int vlen = UINT_MAX; | ||
| long long vll = LLONG_MAX; | ||
|
|
||
| GetFieldRes res = hashTypeGetValue(c->db, o, field, &vstr, &vlen, &vll, hfeFlags); | ||
| GetFieldRes res = hashTypeGetValue(c->db, o, field, &vstr, &vlen, &vll, hfeFlags, NULL); | ||
| if (res == GETF_OK) { | ||
| if (vstr) { | ||
| addReplyBulkCBuffer(c, vstr, vlen); | ||
|
|
@@ -2408,7 +2436,7 @@ void hstrlenCommand(client *c) { | |
| checkType(c,o,OBJ_HASH)) return; | ||
|
|
||
| GetFieldRes res = hashTypeGetValue(c->db, o, c->argv[2]->ptr, &vstr, &vlen, &vll, | ||
| HFE_LAZY_EXPIRE); | ||
| HFE_LAZY_EXPIRE, NULL); | ||
|
|
||
| if (res == GETF_NOT_FOUND || res == GETF_EXPIRED || res == GETF_EXPIRED_HASH) { | ||
| addReply(c, shared.czero); | ||
|
|
||
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.
Remove unused variable causing build failure.
The pipeline fails due to
-Werror=unused-variableforunused_flagwhich is declared but never used.🐛 Proposed fix
int has_expiration = 0; uint64_t expireat = EB_EXPIRE_TIME_INVALID; - int unused_flag = 0;📝 Committable suggestion
🧰 Tools
🪛 GitHub Actions: CI
[error] 2244-2244: Step failed: 'cd src && make 32bit' -> t_hash.c: unused variable 'unused_flag' [-Werror=unused-variable].
🤖 Prompt for AI Agents