-
Notifications
You must be signed in to change notification settings - Fork 0
Code Review Bench PR #14637 - Fix adjacent slot range behavior in ASM operations #2
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
deabeea
0bb1647
98943f5
a6db339
3129018
55e9331
f32efc8
0443e9f
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 | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -1731,15 +1731,19 @@ void replySlotsFlushAndFree(client *c, slotRangeArray *slots) { | |||||||||||||||||||||||||
| slotRangeArrayFree(slots); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| /* Checks that slot ranges are well-formed and non-overlapping. */ | ||||||||||||||||||||||||||
| int validateSlotRanges(slotRangeArray *slots, sds *err) { | ||||||||||||||||||||||||||
| /* Normalizes (sorts and merges adjacent ranges), checks that slot ranges are | ||||||||||||||||||||||||||
| * well-formed and non-overlapping. */ | ||||||||||||||||||||||||||
| int slotRangeArrayNormalizeAndValidate(slotRangeArray *slots, sds *err) { | ||||||||||||||||||||||||||
| unsigned char used_slots[CLUSTER_SLOTS] = {0}; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| if (slots->num_ranges <= 0 || slots->num_ranges >= CLUSTER_SLOTS) { | ||||||||||||||||||||||||||
| *err = sdscatprintf(sdsempty(), "invalid number of slot ranges: %d", slots->num_ranges); | ||||||||||||||||||||||||||
| return C_ERR; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| /* Sort and merge adjacent slot ranges. */ | ||||||||||||||||||||||||||
| slotRangeArraySortAndMerge(slots); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| for (int i = 0; i < slots->num_ranges; i++) { | ||||||||||||||||||||||||||
| if (slots->ranges[i].start >= CLUSTER_SLOTS || | ||||||||||||||||||||||||||
| slots->ranges[i].end >= CLUSTER_SLOTS) | ||||||||||||||||||||||||||
|
|
@@ -1789,6 +1793,7 @@ void slotRangeArraySet(slotRangeArray *slots, int idx, int start, int end) { | |||||||||||||||||||||||||
| /* Create a slot range string in the format of: "1000-2000 3000-4000 ..." */ | ||||||||||||||||||||||||||
| sds slotRangeArrayToString(slotRangeArray *slots) { | ||||||||||||||||||||||||||
| sds s = sdsempty(); | ||||||||||||||||||||||||||
| if (slots == NULL || slots->num_ranges == 0) return s; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| for (int i = 0; i < slots->num_ranges; i++) { | ||||||||||||||||||||||||||
| slotRange *sr = &slots->ranges[i]; | ||||||||||||||||||||||||||
|
|
@@ -1826,7 +1831,7 @@ slotRangeArray *slotRangeArrayFromString(sds data) { | |||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| /* Validate all ranges */ | ||||||||||||||||||||||||||
| sds err_msg = NULL; | ||||||||||||||||||||||||||
| if (validateSlotRanges(slots, &err_msg) != C_OK) { | ||||||||||||||||||||||||||
| if (slotRangeArrayNormalizeAndValidate(slots, &err_msg) != C_OK) { | ||||||||||||||||||||||||||
| if (err_msg) sdsfree(err_msg); | ||||||||||||||||||||||||||
| goto err; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
@@ -1847,13 +1852,32 @@ static int compareSlotRange(const void *a, const void *b) { | |||||||||||||||||||||||||
| return 0; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| /* Sort slot ranges by start slot and merge adjacent ranges. | ||||||||||||||||||||||||||
| * Adjacent means: prev.end + 1 == next.start. | ||||||||||||||||||||||||||
| * e.g. 1000-2000 2001-3000 0-100 => 0-100 1000-3000 | ||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||
| * Note: Overlapping ranges are not merged.*/ | ||||||||||||||||||||||||||
| void slotRangeArraySortAndMerge(slotRangeArray *slots) { | ||||||||||||||||||||||||||
| if (!slots || slots->num_ranges <= 1) return; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| qsort(slots->ranges, slots->num_ranges, sizeof(slotRange), compareSlotRange); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| int idx = 0; | ||||||||||||||||||||||||||
| for (int i = 1; i < slots->num_ranges; i++) { | ||||||||||||||||||||||||||
| if (slots->ranges[idx].end + 1 == slots->ranges[i].start) | ||||||||||||||||||||||||||
| slots->ranges[idx].end = slots->ranges[i].end; | ||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||
| slots->ranges[++idx] = slots->ranges[i]; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| slots->num_ranges = idx + 1; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| /* Compare two slot range arrays, return 1 if equal, 0 otherwise */ | ||||||||||||||||||||||||||
| int slotRangeArrayIsEqual(slotRangeArray *slots1, slotRangeArray *slots2) { | ||||||||||||||||||||||||||
| if (slots1->num_ranges != slots2->num_ranges) return 0; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| /* Sort slot ranges first */ | ||||||||||||||||||||||||||
| qsort(slots1->ranges, slots1->num_ranges, sizeof(slotRange), compareSlotRange); | ||||||||||||||||||||||||||
| qsort(slots2->ranges, slots2->num_ranges, sizeof(slotRange), compareSlotRange); | ||||||||||||||||||||||||||
| slotRangeArraySortAndMerge(slots1); | ||||||||||||||||||||||||||
| slotRangeArraySortAndMerge(slots2); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| for (int i = 0; i < slots1->num_ranges; i++) { | ||||||||||||||||||||||||||
| if (slots1->ranges[i].start != slots2->ranges[i].start || | ||||||||||||||||||||||||||
|
|
@@ -1959,13 +1983,18 @@ void slotRangeArrayIteratorFree(slotRangeArrayIter *it) { | |||||||||||||||||||||||||
| zfree(it); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| /* Parse slot ranges from the command arguments. Returns NULL on error. */ | ||||||||||||||||||||||||||
| /* Parse slot range pairs from argv starting at `pos`. | ||||||||||||||||||||||||||
| * `argc` is the argument count, `pos` is the first slot argument index. | ||||||||||||||||||||||||||
| * Returns a slotRangeArray or NULL on error. */ | ||||||||||||||||||||||||||
| slotRangeArray *parseSlotRangesOrReply(client *c, int argc, int pos) { | ||||||||||||||||||||||||||
| int start, end, count; | ||||||||||||||||||||||||||
| slotRangeArray *slots; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| serverAssert(pos <= argc); | ||||||||||||||||||||||||||
| serverAssert((argc - pos) % 2 == 0); | ||||||||||||||||||||||||||
| /* Ensure there is at least one (start,end) slot range pairs. */ | ||||||||||||||||||||||||||
| if (argc < 0 || pos < 0 || pos >= argc || (argc - pos) < 2 || ((argc - pos) % 2) != 0) { | ||||||||||||||||||||||||||
| addReplyErrorArity(c); | ||||||||||||||||||||||||||
| return NULL; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| count = (argc - pos) / 2; | ||||||||||||||||||||||||||
| slots = slotRangeArrayCreate(count); | ||||||||||||||||||||||||||
|
|
@@ -1983,8 +2012,8 @@ slotRangeArray *parseSlotRangesOrReply(client *c, int argc, int pos) { | |||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| sds err = NULL; | ||||||||||||||||||||||||||
| if (validateSlotRanges(slots, &err) != C_OK) { | ||||||||||||||||||||||||||
| addReplyErrorSds(c, err); | ||||||||||||||||||||||||||
| if (slotRangeArrayNormalizeAndValidate(slots, &err) != C_OK) { | ||||||||||||||||||||||||||
| sdsfree(err); | ||||||||||||||||||||||||||
| slotRangeArrayFree(slots); | ||||||||||||||||||||||||||
| return NULL; | ||||||||||||||||||||||||||
|
Comment on lines
2014
to
2018
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.
|
||||||||||||||||||||||||||
| sds err = NULL; | |
| if (validateSlotRanges(slots, &err) != C_OK) { | |
| addReplyErrorSds(c, err); | |
| if (slotRangeArrayNormalizeAndValidate(slots, &err) != C_OK) { | |
| sdsfree(err); | |
| slotRangeArrayFree(slots); | |
| return NULL; | |
| if (slotRangeArrayNormalizeAndValidate(slots, &err) != C_OK) { | |
| addReplyErrorSds(c, err); | |
| slotRangeArrayFree(slots); | |
| return NULL; | |
| } |
- Apply suggested fix
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.
slotRangeArrayIsEqualchecks count before mergingThe
num_rangescomparison at line 1877 happens beforeslotRangeArraySortAndMerge()is called at lines 1879-1880. This means two slot range arrays that represent the same set of slots but have different pre-mergenum_rangeswill incorrectly be reported as not equal.For example:
{7000-7001, 7002-7003}→ num_ranges = 2, merges to{7000-7003}(num_ranges = 1){7000-7003}→ num_ranges = 1slotRangeArrayIsEqual(A, B)would return 0 at line 1877 before ever merging, even though both arrays represent slots 7000-7003.The fix is to move the
num_rangescomparison after bothslotRangeArraySortAndMerge()calls.Was this helpful? React with 👍 / 👎