-
Notifications
You must be signed in to change notification settings - Fork 0
Fix HINCRBYFLOAT removes field expiration on replica #9
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: claude_claude_vs_qodo_base_fix_hincrbyfloat_removes_field_expiration_on_replica_pr9
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 |
|---|---|---|
|
|
@@ -2556,23 +2556,24 @@ void hincrbyfloatCommand(client *c) { | |
| char buf[MAX_LONG_DOUBLE_CHARS]; | ||
| int len = ld2string(buf,sizeof(buf),value,LD_STR_HUMAN); | ||
| new = sdsnewlen(buf,len); | ||
| hashTypeSet(c->db, o,c->argv[2]->ptr,new,HASH_SET_TAKE_VALUE | HASH_SET_KEEP_TTL); | ||
| hashTypeSet(c->db, o,c->argv[2]->ptr,new,HASH_SET_TAKE_VALUE); | ||
| addReplyBulkCBuffer(c,buf,len); | ||
| signalModifiedKey(c,c->db,c->argv[1]); | ||
| notifyKeyspaceEvent(NOTIFY_HASH,"hincrbyfloat",c->argv[1],c->db->id); | ||
| server.dirty++; | ||
|
|
||
| /* Always replicate HINCRBYFLOAT as an HSET command with the final value | ||
| /* Always replicate HINCRBYFLOAT as an HSETEX command with the final value | ||
| * in order to make sure that differences in float precision or formatting | ||
| * will not create differences in replicas or after an AOF restart. */ | ||
| * will not create differences in replicas or after an AOF restart. | ||
| * The KEEPTTL flag is used to make sure the field TTL is preserved. */ | ||
| robj *newobj; | ||
| newobj = createRawStringObject(buf,len); | ||
| rewriteClientCommandArgument(c,0,shared.hset); | ||
| rewriteClientCommandArgument(c,3,newobj); | ||
| rewriteClientCommandVector(c, 6, shared.hsetex, c->argv[1], shared.keepttl, | ||
| shared.fields, shared.integers[1], c->argv[2], newobj); | ||
|
Comment on lines
+2571
to
+2572
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. 🔴 Extended reasoning...What the bug isThe rewriteClientCommandVector(c, 6, shared.hsetex, c->argv[1], shared.keepttl,
shared.fields, shared.integers[1], c->argv[2], newobj);How
|
||
| decrRefCount(newobj); | ||
| } | ||
|
|
||
| static GetFieldRes addHashFieldToReply(client *c, kvobj *o, sds field, int hfeFlags) { | ||
| GetFieldRes addHashFieldToReply(client *c, kvobj *o, sds field, int hfeFlags) { | ||
| if (o == NULL) { | ||
| addReplyNull(c); | ||
| return GETF_NOT_FOUND; | ||
|
|
||
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.
🔴 Bug:
HASH_SET_KEEP_TTLwas removed from thehashTypeSetcall inhincrbyfloatCommand(line 2559), causing field TTL to be cleared on the primary. Since replication now usesHSETEX KEEPTTLwhich preserves TTL on replicas, this creates primary-replica divergence. The fix is to restore the flag:HASH_SET_TAKE_VALUE | HASH_SET_KEEP_TTL.Extended reasoning...
What the bug is
The PR changes the
hashTypeSetcall inhincrbyfloatCommandfrom:to:
Without
HASH_SET_KEEP_TTL,hashTypeSetactively removes any existing field TTL. For listpack encoding (lines 959-964), it callslistpackExUpdateExpirywithHASH_LP_NO_TTL, removing the TTL. For hashtable encoding (lines 989-992), it callshfieldPersist(o, oldField)which explicitly removes the TTL from the field.How primary-replica divergence occurs
On the primary,
HINCRBYFLOATnow clears the field TTL viahashTypeSet(becauseHASH_SET_KEEP_TTLis missing). However, the replication is rewritten asHSETEX h1 KEEPTTL FIELDS 1 f1 <value>, which preserves the TTL on replicas. This means afterHINCRBYFLOATon a field with TTL:This is a data consistency violation between primary and replica.
Step-by-step proof
HSETEX h1 EX 100 FIELDS 1 f1 10HINCRBYFLOAT h1 f1 1.5on the primaryhashTypeSetis called withoutHASH_SET_KEEP_TTL→ field TTL is cleared →HPTTL h1 FIELDS 1 f1returns-1HSETEX h1 KEEPTTL FIELDS 1 f1 11.5→ on the replica, TTL is preserved →HPTTL h1 FIELDS 1 f1returns a value in[1, 100000]Evidence from the codebase
The analogous
hincrbyCommandat line 2506 correctly retainsHASH_SET_KEEP_TTL:The existing test
{HINCRBYFLOAT - preserve expiration time of the field}would fail with this change, as it sets a 20msHPEXPIRE, runsHINCRBYFLOAT, then assertsHPTTLis in range[1, 20]— but withoutHASH_SET_KEEP_TTL, the TTL is cleared andHPTTLreturns-1.Fix
Restore
HASH_SET_KEEP_TTLin thehashTypeSetcall while keeping the newHSETEX KEEPTTLreplication: