-
Notifications
You must be signed in to change notification settings - Fork 0
Code Review Bench PR #14587 - Refactor some of ASM and slot-stats functions #4
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
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 | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -1089,6 +1089,10 @@ void clusterCommand(client *c) { | |||||||||||||||||
| addReplyBulkCString(c,ni); | ||||||||||||||||||
| sdsfree(ni); | ||||||||||||||||||
| } | ||||||||||||||||||
| } else if (!strcasecmp(c->argv[1]->ptr, "migration")) { | ||||||||||||||||||
| clusterMigrationCommand(c); | ||||||||||||||||||
| } else if (!strcasecmp(c->argv[1]->ptr,"syncslots") && c->argc >= 3) { | ||||||||||||||||||
| clusterSyncSlotsCommand(c); | ||||||||||||||||||
| } else if(!clusterCommandSpecial(c)) { | ||||||||||||||||||
| addReplySubcommandSyntaxError(c); | ||||||||||||||||||
| return; | ||||||||||||||||||
|
|
@@ -2127,3 +2131,84 @@ void resetClusterStats(void) { | |||||||||||||||||
|
|
||||||||||||||||||
| clusterSlotStatResetAll(); | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| /* 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)); | ||||||||||||||||||
| resetClusterStats(); | ||||||||||||||||||
| asmInit(); | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| /* 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) { | ||||||||||||||||||
| if (clusterNodeIsSlave(getMyClusterNode())) return; | ||||||||||||||||||
|
|
||||||||||||||||||
| /* Check that all the slots we have keys for are assigned to us. Otherwise, | ||||||||||||||||||
| * delete the keys. */ | ||||||||||||||||||
| for (int i = 0; i < CLUSTER_SLOTS; i++) { | ||||||||||||||||||
| /* Skip if: no keys in the slot, it's our slot, or we are importing it. */ | ||||||||||||||||||
| if (!countKeysInSlot(i) || | ||||||||||||||||||
| clusterIsMySlot(i) || | ||||||||||||||||||
| getImportingSlotSource(i)) | ||||||||||||||||||
| { | ||||||||||||||||||
| continue; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| serverLog(LL_NOTICE, "I have keys for slot %d, but the slot is " | ||||||||||||||||||
| "assigned to another node. " | ||||||||||||||||||
| "Deleting keys in the slot.", i); | ||||||||||||||||||
| /* With atomic slot migration, it is safe to drop keys from slots | ||||||||||||||||||
| * that are not owned. This will not result in data loss under the | ||||||||||||||||||
| * legacy slot migration approach either, since the importing state | ||||||||||||||||||
| * has already been persisted in node.conf. */ | ||||||||||||||||||
| clusterDelKeysInSlot(i, 0); | ||||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| /* This function is called after the node startup in order to verify that data | ||||||||||||||||||
| * loaded from disk is in agreement with the cluster configuration: | ||||||||||||||||||
| * | ||||||||||||||||||
| * 1) If we find keys about hash slots we have no responsibility for, the | ||||||||||||||||||
| * following happens: | ||||||||||||||||||
| * A) If no other node is in charge according to the current cluster | ||||||||||||||||||
| * configuration, we add these slots to our node. | ||||||||||||||||||
| * B) If according to our config other nodes are already in charge for | ||||||||||||||||||
| * this slots, we set the slots as IMPORTING from our point of view | ||||||||||||||||||
| * in order to justify we have those slots, and in order to make | ||||||||||||||||||
| * redis-cli aware of the issue, so that it can try to fix it. | ||||||||||||||||||
| * 2) If we find data in a DB different than DB0 we return C_ERR to | ||||||||||||||||||
| * signal the caller it should quit the server with an error message | ||||||||||||||||||
| * or take other actions. | ||||||||||||||||||
| * | ||||||||||||||||||
| * The function always returns C_OK even if it will try to correct | ||||||||||||||||||
| * the error described in "1". However if data is found in DB different | ||||||||||||||||||
| * from DB0, C_ERR is returned. | ||||||||||||||||||
| * | ||||||||||||||||||
| * The function also uses the logging facility in order to warn the user | ||||||||||||||||||
| * about desynchronizations between the data we have in memory and the | ||||||||||||||||||
| * cluster configuration. */ | ||||||||||||||||||
| int verifyClusterConfigWithData(void) { | ||||||||||||||||||
| /* Return ASAP if a module disabled cluster redirections. In that case | ||||||||||||||||||
| * every master can store keys about every possible hash slot. */ | ||||||||||||||||||
| if (server.cluster_module_flags & CLUSTER_MODULE_FLAG_NO_REDIRECTION) | ||||||||||||||||||
| return C_OK; | ||||||||||||||||||
|
|
||||||||||||||||||
| /* If this node is a slave, don't perform the check at all as we | ||||||||||||||||||
| * completely depend on the replication stream. */ | ||||||||||||||||||
| if (clusterNodeIsSlave(getMyClusterNode())) return C_OK; | ||||||||||||||||||
|
|
||||||||||||||||||
| /* Make sure we only have keys in DB0. */ | ||||||||||||||||||
| for (int i = 1; i < server.dbnum; i++) { | ||||||||||||||||||
| if (kvstoreSize(server.db[i].keys)) return C_ERR; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| /* Delete keys in unowned slots */ | ||||||||||||||||||
| clusterDeleteKeysInUnownedSlots(); | ||||||||||||||||||
| /* Take over slots that we have keys for, but are assigned to no one. */ | ||||||||||||||||||
| clusterClaimUnassignedSlots(); | ||||||||||||||||||
|
Comment on lines
+2209
to
+2212
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. 🚨 Bug: Two-pass refactor causes data loss for keys in unassigned slotsThe original Was this helpful? React with 👍 / 👎
Suggested change
|
||||||||||||||||||
| return C_OK; | ||||||||||||||||||
| } | ||||||||||||||||||
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.
mallocinstead ofzmallocbreaks memory trackingThe original code in
server.c:main()usedzmalloc()to allocatecluster_slot_stats. The newclusterCommonInit()uses rawmalloc()instead. This means:\n\n1. The allocation is invisible to Redis'sINFO memoryreporting andused_memorytracking\n2. Memory fragmentation metrics will be inaccurate\n3. If Redis is configured withmaxmemory, this allocation won't count toward the limit\n4. It's inconsistent with every other allocation in cluster.c (all usezmalloc)\n\nThe PR context notes mention "Use malloc instead of zmalloc for allocation (consistent with pattern)" but this appears incorrect — no other allocation incluster.cuses rawmalloc.\n\nFix: Changemalloctozmallocto match the original code and Redis conventions.Was this helpful? React with 👍 / 👎