Skip to content

Refactor some of ASM and slot-stats functions#35

Open
tomerqodo wants to merge 3 commits into
qodo_claude_vs_qodo_base_refactor_some_of_asm_and_slot-stats_functions_pr4from
qodo_claude_vs_qodo_head_refactor_some_of_asm_and_slot-stats_functions_pr4
Open

Refactor some of ASM and slot-stats functions#35
tomerqodo wants to merge 3 commits into
qodo_claude_vs_qodo_base_refactor_some_of_asm_and_slot-stats_functions_pr4from
qodo_claude_vs_qodo_head_refactor_some_of_asm_and_slot-stats_functions_pr4

Conversation

@tomerqodo

Copy link
Copy Markdown

Benchmark PR from agentic-review-benchmarks#4

@qodo-code-review

Copy link
Copy Markdown

Review Summary by Qodo

Refactor cluster initialization and ASM integration across implementations

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Refactor cluster initialization to separate common and legacy-specific logic
• Move ASM (Atomic Slot Migration) calls to server cron and before-sleep hooks
• Extract slot verification logic into reusable functions for different cluster implementations
• Add support for migration and syncslots subcommands in cluster.c
Diagram
flowchart LR
  A["Cluster Init"] --> B["clusterCommonInit"]
  B --> C["Initialize Slot Stats"]
  B --> D["Reset Cluster Stats"]
  B --> E["ASM Init"]
  F["Server Cron"] --> G["ASM Cron"]
  G --> H["Cluster Cron"]
  I["Before Sleep"] --> J["Cluster Before Sleep"]
  J --> K["ASM Before Sleep"]
  L["Verify Config"] --> M["Delete Unowned Slots"]
  L --> N["Claim Unassigned Slots"]
Loading

Grey Divider

File Changes

1. src/cluster.c ✨ Enhancement +85/-0

Add cluster initialization and verification functions

• Add migration and syncslots subcommand handlers in clusterCommand
• Implement clusterCommonInit() to initialize shared cluster data structures
• Implement clusterDeleteKeysInUnownedSlots() to clean up keys in non-owned slots
• Implement verifyClusterConfigWithData() with simplified logic for data verification

src/cluster.c


2. src/cluster.h ✨ Enhancement +2/-0

Add function declarations for cluster operations

• Add function declarations for clusterCommonInit() and clusterClaimUnassignedSlots()
• Expose new cluster initialization and slot management functions

src/cluster.h


3. src/cluster_legacy.c Refactoring +27/-87

Refactor legacy cluster initialization and ASM integration

• Remove resetClusterStats() and asmInit() calls from clusterInit()
• Remove asmCron() call from clusterCron()
• Remove asmBeforeSleep() call from clusterBeforeSleep()
• Remove verifyClusterConfigWithData() implementation and replace with clusterClaimUnassignedSlots()
• Implement clusterClaimUnassignedSlots() to handle unassigned slot ownership

src/cluster_legacy.c


View more (1)
4. src/server.c Refactoring +10/-3

Integrate ASM calls into server event loop

• Call asmCron() before clusterCron() in serverCron event loop
• Call asmBeforeSleep() after clusterBeforeSleep() in beforeSleep hook
• Replace zmalloc with clusterCommonInit() call for cluster initialization
• Add comment explaining clusterCommonInit() initializes slot-stats

src/server.c


Grey Divider

Qodo Logo

@qodo-code-review

qodo-code-review Bot commented Mar 10, 2026

Copy link
Copy Markdown

Code Review by Qodo

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

Grey Divider


Action required

1. clusterCommonInit() uses malloc 📘 Rule violation ⛯ Reliability
Description
The new clusterCommonInit() allocates server.cluster_slot_stats via malloc(), bypassing Redis
memory tracking. This violates the requirement to use the zmalloc/zfree family for allocations
in src/.
Code

src/cluster.c[2138]

+    server.cluster_slot_stats = malloc(CLUSTER_SLOTS*sizeof(clusterSlotStat));
Evidence
PR Compliance ID 2 forbids direct malloc() usage in src/. The added line in
clusterCommonInit() calls malloc() to allocate server.cluster_slot_stats.

AGENTS.md
src/cluster.c[2137-2141]

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

## Issue description
`clusterCommonInit()` allocates memory with `malloc()`, which bypasses Redis's memory tracking and violates the requirement to use the `zmalloc`/`zfree` family in `src/`.

## Issue Context
`server.cluster_slot_stats` was previously allocated via `zmalloc()` in `main()`, but that allocation was replaced by a call to `clusterCommonInit()`, which now uses `malloc()`.

## Fix Focus Areas
- src/cluster.c[2137-2141]

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


2. clusterDeleteKeysInUnownedSlots() not static 📘 Rule violation ✓ Correctness
Description
The new helper clusterDeleteKeysInUnownedSlots() is defined without static, even though it
appears to be an internal-only function used within the same source file. This unnecessarily exports
a global symbol and violates the encapsulation requirement.
Code

src/cluster.c[2146]

+void clusterDeleteKeysInUnownedSlots(void) {
Evidence
PR Compliance ID 7 requires internal helper functions to be declared static. The added function
definition lacks static and is introduced as a local startup verification helper used by the same
file's logic.

AGENTS.md
src/cluster.c[2146-2168]

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

## Issue description
`clusterDeleteKeysInUnownedSlots()` is an internal helper but is declared as a global (non-`static`) function, which violates the requirement to keep internal helpers `static` to avoid symbol pollution.

## Issue Context
This function is newly introduced in `src/cluster.c` as part of refactoring the cluster startup verification flow and is intended as an internal helper.

## Fix Focus Areas
- src/cluster.c[2146-2168]

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


3. Unassigned slot keys deleted 🐞 Bug ✓ Correctness
Description
verifyClusterConfigWithData() calls clusterDeleteKeysInUnownedSlots() before
clusterClaimUnassignedSlots(), but the delete routine does not exclude unassigned slots, so keys
loaded from disk for unassigned slots can be deleted before they can be claimed. This causes
irreversible data loss at startup for nodes that have keys in slots with no owner in the cluster
config.
Code

src/cluster.c[R2209-2212]

+    /* Delete keys in unowned slots */
+    clusterDeleteKeysInUnownedSlots();
+    /* Take over slots that we have keys for, but are assigned to no one. */
+    clusterClaimUnassignedSlots();
Evidence
clusterDeleteKeysInUnownedSlots() deletes keys for any slot that has keys and is not "my slot" and
not importing; for unassigned slots, getNodeBySlot() returns NULL so clusterIsMySlot() is false, so
those keys will be deleted. verifyClusterConfigWithData() then calls clusterClaimUnassignedSlots(),
but that function only claims unassigned slots if keys still exist in the slot, which will no longer
be true after deletion. This contradicts the documented intent that unassigned-slot keys should lead
to taking ownership, not deletion.

src/cluster.c[2209-2213]
src/cluster.c[2151-2168]
src/cluster.c[1722-1724]
src/cluster_legacy.c[6499-6501]
src/cluster_legacy.c[5267-5271]
src/cluster.c[2172-2179]
src/server.c[7758-7769]

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

### Issue description
`verifyClusterConfigWithData()` currently deletes keys in slots that are not "my slot" before attempting to claim unassigned slots. Because `clusterDeleteKeysInUnownedSlots()` does not exclude unassigned slots, keys in unassigned slots can be deleted and then cannot be claimed.

### Issue Context
- Unassigned slot => `getNodeBySlot(slot)` is `NULL`, so `clusterIsMySlot(slot)` is false.
- `clusterClaimUnassignedSlots()` only claims when the slot is unassigned *and* still has keys.

### Fix Focus Areas
- src/cluster.c[2146-2168]
- src/cluster.c[2209-2213]
- src/cluster_legacy.c[5262-5284]

ⓘ 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

Qodo Logo

Comment thread src/cluster.c
/* This function is called at server startup in order to initialize cluster data
* structures that are shared between the different cluster implementations. */
void clusterCommonInit(void) {
server.cluster_slot_stats = malloc(CLUSTER_SLOTS*sizeof(clusterSlotStat));

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. clustercommoninit() uses malloc 📘 Rule violation ⛯ Reliability

The new clusterCommonInit() allocates server.cluster_slot_stats via malloc(), bypassing Redis
memory tracking. This violates the requirement to use the zmalloc/zfree family for allocations
in src/.
Agent Prompt
## Issue description
`clusterCommonInit()` allocates memory with `malloc()`, which bypasses Redis's memory tracking and violates the requirement to use the `zmalloc`/`zfree` family in `src/`.

## Issue Context
`server.cluster_slot_stats` was previously allocated via `zmalloc()` in `main()`, but that allocation was replaced by a call to `clusterCommonInit()`, which now uses `malloc()`.

## Fix Focus Areas
- src/cluster.c[2137-2141]

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

Comment thread src/cluster.c
/* This function is called after the node startup in order to check if there
* are any slots that we have keys for, but are not assigned to us. If so,
* we delete the keys. */
void clusterDeleteKeysInUnownedSlots(void) {

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. clusterdeletekeysinunownedslots() not static 📘 Rule violation ✓ Correctness

The new helper clusterDeleteKeysInUnownedSlots() is defined without static, even though it
appears to be an internal-only function used within the same source file. This unnecessarily exports
a global symbol and violates the encapsulation requirement.
Agent Prompt
## Issue description
`clusterDeleteKeysInUnownedSlots()` is an internal helper but is declared as a global (non-`static`) function, which violates the requirement to keep internal helpers `static` to avoid symbol pollution.

## Issue Context
This function is newly introduced in `src/cluster.c` as part of refactoring the cluster startup verification flow and is intended as an internal helper.

## Fix Focus Areas
- src/cluster.c[2146-2168]

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

Comment thread src/cluster.c
Comment on lines +2209 to +2212
/* Delete keys in unowned slots */
clusterDeleteKeysInUnownedSlots();
/* Take over slots that we have keys for, but are assigned to no one. */
clusterClaimUnassignedSlots();

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. Unassigned slot keys deleted 🐞 Bug ✓ Correctness

verifyClusterConfigWithData() calls clusterDeleteKeysInUnownedSlots() before
clusterClaimUnassignedSlots(), but the delete routine does not exclude unassigned slots, so keys
loaded from disk for unassigned slots can be deleted before they can be claimed. This causes
irreversible data loss at startup for nodes that have keys in slots with no owner in the cluster
config.
Agent Prompt
### Issue description
`verifyClusterConfigWithData()` currently deletes keys in slots that are not "my slot" before attempting to claim unassigned slots. Because `clusterDeleteKeysInUnownedSlots()` does not exclude unassigned slots, keys in unassigned slots can be deleted and then cannot be claimed.

### Issue Context
- Unassigned slot => `getNodeBySlot(slot)` is `NULL`, so `clusterIsMySlot(slot)` is false.
- `clusterClaimUnassignedSlots()` only claims when the slot is unassigned *and* still has keys.

### Fix Focus Areas
- src/cluster.c[2146-2168]
- src/cluster.c[2209-2213]
- src/cluster_legacy.c[5262-5284]

ⓘ 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