Skip to content

Fix HINCRBYFLOAT removes field expiration on replica#40

Open
tomerqodo wants to merge 2 commits into
qodo_claude_vs_qodo_base_fix_hincrbyfloat_removes_field_expiration_on_replica_pr9from
qodo_claude_vs_qodo_head_fix_hincrbyfloat_removes_field_expiration_on_replica_pr9
Open

Fix HINCRBYFLOAT removes field expiration on replica#40
tomerqodo wants to merge 2 commits into
qodo_claude_vs_qodo_base_fix_hincrbyfloat_removes_field_expiration_on_replica_pr9from
qodo_claude_vs_qodo_head_fix_hincrbyfloat_removes_field_expiration_on_replica_pr9

Conversation

@tomerqodo

Copy link
Copy Markdown

Benchmark PR from agentic-review-benchmarks#9

@qodo-code-review

Copy link
Copy Markdown

Review Summary by Qodo

Fix HINCRBYFLOAT field expiration removal on replica

🐞 Bug fix

Grey Divider

Walkthroughs

Description
• Fix HINCRBYFLOAT removing field expiration on replica
• Replicate HINCRBYFLOAT as HSETEX with KEEPTTL flag
• Add shared objects for HSETEX and FIELDS commands
• Add comprehensive test for field expiration preservation
Diagram
flowchart LR
  A["HINCRBYFLOAT command"] -->|Previously replicated as| B["HSET without TTL"]
  A -->|Now replicated as| C["HSETEX with KEEPTTL"]
  C -->|Preserves| D["Field expiration on replica"]
  E["Shared objects"] -->|Added| F["hsetex and fields"]
  G["Test coverage"] -->|Added| H["Replica expiration validation"]
Loading

Grey Divider

File Changes

1. src/server.c ✨ Enhancement +2/-0

Add shared objects for HSETEX and FIELDS

• Added shared.hsetex string object initialization for HSETEX command
• Added shared.fields string object initialization for FIELDS argument
• These shared objects are used in replication command construction

src/server.c


2. src/server.h ✨ Enhancement +2/-2

Declare new shared object pointers

• Added *hsetex pointer to sharedObjectsStruct for HSETEX command
• Added *fields pointer to sharedObjectsStruct for FIELDS argument
• Updated struct member declarations to include new shared objects

src/server.h


3. src/t_hash.c 🐞 Bug fix +7/-6

Replicate HINCRBYFLOAT as HSETEX with KEEPTTL

• Changed HINCRBYFLOAT replication from HSET to HSETEX with KEEPTTL flag
• Removed HASH_SET_KEEP_TTL flag from local hashTypeSet call
• Updated replication command construction to use rewriteClientCommandVector with HSETEX, KEEPTTL,
 and FIELDS arguments
• Changed addHashFieldToReply function from static to public
• Updated comments to document KEEPTTL flag usage for preserving field TTL

src/t_hash.c


View more (1)
4. tests/unit/type/hash-field-expire.tcl 🧪 Tests +46/-0

Add HINCRBYFLOAT expiration preservation test

• Added comprehensive test case for HINCRBYFLOAT field expiration preservation
• Tests that HINCRBYFLOAT replicates as HSETEX with KEEPTTL flag
• Validates field expiration is maintained on replica after HINCRBYFLOAT
• Tests both fields with and without initial expiration
• Verifies field values match between master and replica

tests/unit/type/hash-field-expire.tcl


Grey Divider

Qodo Logo

@qodo-code-review

qodo-code-review Bot commented Mar 10, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (1) 📎 Requirement gaps (0)

Grey Divider


Action required

1. addHashFieldToReply missing static 📘 Rule violation ⛯ Reliability
Description
addHashFieldToReply is now declared without static even though it is only used within
src/t_hash.c, unnecessarily exporting the symbol. This violates the internal-helper encapsulation
requirement and may also trigger -Wmissing-prototypes style warnings when building with -Werror.
Code

src/t_hash.c[2576]

+GetFieldRes addHashFieldToReply(client *c, kvobj *o, sds field, int hfeFlags) {
Evidence
Compliance ID 7 requires internal helper functions used only within a single source file to be
declared static. The PR changes addHashFieldToReply to a non-static function, while its usages
shown are within src/t_hash.c.

AGENTS.md
src/t_hash.c[2576-2576]
src/t_hash.c[2605-2622]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`addHashFieldToReply` was changed from `static` to non-static, which exports an internal helper symbol.

## Issue Context
Per compliance requirements, helper functions only used within a single `.c` file must be declared `static` to avoid symbol pollution and potential build warnings.

## Fix Focus Areas
- src/t_hash.c[2576-2576]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Malformed replicated HSETEX 🐞 Bug ✓ Correctness
Description
hincrbyfloatCommand rewrites propagation to HSETEX but calls rewriteClientCommandVector with argc=6
while providing 7 arguments, so the final value argument is not included in the rewritten command.
Replicas/AOF will receive an invalid HSETEX (missing the value) and fail with an arity error when
parsing FIELDS.
Code

src/t_hash.c[R2571-2572]

+    rewriteClientCommandVector(c, 6, shared.hsetex, c->argv[1], shared.keepttl,
+                        shared.fields, shared.integers[1], c->argv[2], newobj);
Evidence
rewriteClientCommandVector allocates/copies exactly argc arguments from varargs, so passing argc=6
constructs a 6-argument vector and drops the intended final value argument. With the resulting argv,
HSETEX parsing hits the FIELDS arity check (FIELDS must be followed by <numfields> and matching
field/value pairs) and errors.

src/t_hash.c[2569-2573]
src/networking.c[4158-4173]
src/t_hash.c[2214-2227]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`hincrbyfloatCommand` rewrites replication/AOF to `HSETEX ... KEEPTTL FIELDS 1 &lt;field&gt; &lt;value&gt;`, but currently calls `rewriteClientCommandVector` with `argc=6` while supplying 7 `robj*` arguments. Since `rewriteClientCommandVector` only copies `argc` objects, the last argument (the value) is dropped, producing a malformed `HSETEX` that fails parsing on replicas/AOF.

### Issue Context
`rewriteClientCommandVector(client *c, int argc, ...)` consumes exactly `argc` varargs.
`HSETEX` requires `FIELDS &lt;numfields&gt; field value ...`; omitting the value triggers an arity error.

### Fix Focus Areas
- src/t_hash.c[2569-2573]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. HINCRBYFLOAT drops field TTL 🐞 Bug ✓ Correctness
Description
hincrbyfloatCommand updates the field via hashTypeSet without HASH_SET_KEEP_TTL, which causes
existing per-field expiration metadata to be cleared when overwriting the value. This makes the
master’s field TTL behavior diverge (and can remove expirations) despite the intention to preserve
TTL via KEEPTTL in propagation.
Code

src/t_hash.c[2559]

+    hashTypeSet(c->db, o,c->argv[2]->ptr,new,HASH_SET_TAKE_VALUE);
Evidence
hashTypeSet explicitly removes an existing field TTL unless HASH_SET_KEEP_TTL is set (both for
listpack_ex and hash table encodings). HINCRBY (integer) still uses HASH_SET_KEEP_TTL, indicating
increment operations are intended to preserve field TTL; HINCRBYFLOAT should match that behavior but
no longer does.

src/t_hash.c[2556-2561]
src/t_hash.c[959-964]
src/t_hash.c[987-992]
src/t_hash.c[2504-2507]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`hincrbyfloatCommand` now calls `hashTypeSet(..., HASH_SET_TAKE_VALUE)` without `HASH_SET_KEEP_TTL`. In `hashTypeSet`, absence of `HASH_SET_KEEP_TTL` actively clears existing per-field TTL metadata. This means HINCRBYFLOAT can remove field expirations on the master during the local write.

### Issue Context
`hashTypeSet` clears attached field TTL when `HASH_SET_KEEP_TTL` is not set (listpack_ex and HT encodings).
`hincrbyCommand` still uses `HASH_SET_KEEP_TTL`, so increment-style updates are expected to preserve field TTL.

### Fix Focus Areas
- src/t_hash.c[2556-2561]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Grey Divider

Previous review results

Review updated until commit 355e36b

Results up to commit N/A


Grey Divider

Looking for bugs?

Check back in a few minutes. An AI review agent is analyzing this pull request. Grey Divider

Qodo Logo

@tomerqodo

Copy link
Copy Markdown
Author

/agentic_review

@qodo-code-review

qodo-code-review Bot commented Mar 10, 2026

Copy link
Copy Markdown

Persistent review updated to latest commit 355e36b

Comment thread src/t_hash.c
}

static GetFieldRes addHashFieldToReply(client *c, kvobj *o, sds field, int hfeFlags) {
GetFieldRes addHashFieldToReply(client *c, kvobj *o, sds field, int hfeFlags) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. addhashfieldtoreply missing static 📘 Rule violation ⛯ Reliability

addHashFieldToReply is now declared without static even though it is only used within
src/t_hash.c, unnecessarily exporting the symbol. This violates the internal-helper encapsulation
requirement and may also trigger -Wmissing-prototypes style warnings when building with -Werror.
Agent Prompt
## Issue description
`addHashFieldToReply` was changed from `static` to non-static, which exports an internal helper symbol.

## Issue Context
Per compliance requirements, helper functions only used within a single `.c` file must be declared `static` to avoid symbol pollution and potential build warnings.

## Fix Focus Areas
- src/t_hash.c[2576-2576]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread src/t_hash.c
Comment on lines +2571 to +2572
rewriteClientCommandVector(c, 6, shared.hsetex, c->argv[1], shared.keepttl,
shared.fields, shared.integers[1], c->argv[2], newobj);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. Malformed replicated hsetex 🐞 Bug ✓ Correctness

hincrbyfloatCommand rewrites propagation to HSETEX but calls rewriteClientCommandVector with argc=6
while providing 7 arguments, so the final value argument is not included in the rewritten command.
Replicas/AOF will receive an invalid HSETEX (missing the value) and fail with an arity error when
parsing FIELDS.
Agent Prompt
### Issue description
`hincrbyfloatCommand` rewrites replication/AOF to `HSETEX ... KEEPTTL FIELDS 1 <field> <value>`, but currently calls `rewriteClientCommandVector` with `argc=6` while supplying 7 `robj*` arguments. Since `rewriteClientCommandVector` only copies `argc` objects, the last argument (the value) is dropped, producing a malformed `HSETEX` that fails parsing on replicas/AOF.

### Issue Context
`rewriteClientCommandVector(client *c, int argc, ...)` consumes exactly `argc` varargs.
`HSETEX` requires `FIELDS <numfields> field value ...`; omitting the value triggers an arity error.

### Fix Focus Areas
- src/t_hash.c[2569-2573]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread src/t_hash.c
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);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

3. Hincrbyfloat drops field ttl 🐞 Bug ✓ Correctness

hincrbyfloatCommand updates the field via hashTypeSet without HASH_SET_KEEP_TTL, which causes
existing per-field expiration metadata to be cleared when overwriting the value. This makes the
master’s field TTL behavior diverge (and can remove expirations) despite the intention to preserve
TTL via KEEPTTL in propagation.
Agent Prompt
### Issue description
`hincrbyfloatCommand` now calls `hashTypeSet(..., HASH_SET_TAKE_VALUE)` without `HASH_SET_KEEP_TTL`. In `hashTypeSet`, absence of `HASH_SET_KEEP_TTL` actively clears existing per-field TTL metadata. This means HINCRBYFLOAT can remove field expirations on the master during the local write.

### Issue Context
`hashTypeSet` clears attached field TTL when `HASH_SET_KEEP_TTL` is not set (listpack_ex and HT encodings).
`hincrbyCommand` still uses `HASH_SET_KEEP_TTL`, so increment-style updates are expected to preserve field TTL.

### Fix Focus Areas
- src/t_hash.c[2556-2561]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants