Skip to content

Commit d95a5a0

Browse files
committed
fix slab bug
1 parent 4dbecf3 commit d95a5a0

2 files changed

Lines changed: 65 additions & 3 deletions

File tree

src/slabapi.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,14 @@ void slab_expireDelete(tairhash_zskiplist *zsl, RedisModuleString *key, long lon
212212

213213
if (update_findNode) { // update min value
214214
int smallest_subscript = slab_minExpireTimeIndex(find_slab);
215-
find_node->expire_min = find_slab->expires[smallest_subscript], find_node->key_min = find_slab->keys[smallest_subscript];
215+
long long new_expire_min = find_slab->expires[smallest_subscript];
216+
RedisModuleString *new_key_min = find_slab->keys[smallest_subscript];
217+
if (new_expire_min != find_node->expire_min || RedisModule_StringCompare(new_key_min, find_node->key_min) != 0) {
218+
Slab *slab = find_node->slab;
219+
int ret = tairhash_zslDelete(zsl, find_node->key_min, find_node->expire_min);
220+
assert(ret == 1);
221+
find_node = tairhash_zslInsertNode(zsl, slab, new_key_min, new_expire_min);
222+
}
216223
}
217224
slab_mergeIfNeed(zsl, find_node); // if need merge
218225
return;
@@ -268,7 +275,13 @@ void slab_deleteSlabExpire(tairhash_zskiplist *zsl, tairhash_zskiplistNode *zsl_
268275
}
269276
}
270277
slab->num_keys = effective_num;
271-
zsl_node->expire_min = slab->expires[min_index], zsl_node->key_min = slab->keys[min_index];
278+
long long new_expire_min = slab->expires[min_index];
279+
RedisModuleString *new_key_min = slab->keys[min_index];
280+
if (new_expire_min != zsl_node->expire_min || RedisModule_StringCompare(new_key_min, zsl_node->key_min) != 0) {
281+
int ret = tairhash_zslDelete(zsl, zsl_node->key_min, zsl_node->expire_min);
282+
assert(ret == 1);
283+
zsl_node = tairhash_zslInsertNode(zsl, slab, new_key_min, new_expire_min);
284+
}
272285
slab_mergeIfNeed(zsl, zsl_node);
273286
return;
274287
}

tests/tairhash.tcl

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2083,4 +2083,53 @@ start_server {tags {"tairhash"} overrides {bind 0.0.0.0}} {
20832083
# }
20842084
}
20852085
}
2086-
}
2086+
}
2087+
2088+
start_server {tags {"slab_bug_reproduce"}} {
2089+
test "Test Slab consistency after extensive delete" {
2090+
r module load $testmodule
2091+
2092+
set key "test_slab_key"
2093+
# 1. Fill multiple slabs (Slab size is 512)
2094+
# Insert 1500 items. Should create ~3-4 slabs.
2095+
for {set i 0} {$i < 1500} {incr i} {
2096+
r exhset $key field_$i val ex $i
2097+
}
2098+
2099+
# 2. Delete items from the beginning (Smallest expires/keys)
2100+
# This forces the First Slab's Min Value to increase repeatedly.
2101+
# This is where the potential order invariant violation happens.
2102+
for {set i 0} {$i < 1000} {incr i} {
2103+
r exhdel $key field_$i
2104+
}
2105+
2106+
# 3. Verify the remaining items are accessible.
2107+
# If the First Slab's Min increased but 'leapfrogged' the Second Slab,
2108+
# the Second Slab might become unreachable or data could be corrupted.
2109+
for {set i 1000} {$i < 1500} {incr i} {
2110+
assert_equal [r exhget $key field_$i] "val"
2111+
}
2112+
2113+
assert_equal [r exhlen $key] 500
2114+
}
2115+
2116+
test "Test Slab Split and Merge random operations" {
2117+
r del $key
2118+
# Random operations to trigger split/merge and potential race/logic errors
2119+
for {set i 0} {$i < 2000} {incr i} {
2120+
set action [expr {int(rand()*10)}]
2121+
set f_id [expr {int(rand()*1000)}]
2122+
set expire [expr {int(rand()*100000)}]
2123+
2124+
if {$action < 7} {
2125+
# 70% Set
2126+
r exhset $key f_$f_id val ex $expire
2127+
} else {
2128+
# 30% Del
2129+
r exhdel $key f_$f_id
2130+
}
2131+
}
2132+
# Just ensure it didn't crash
2133+
r ping
2134+
}
2135+
}

0 commit comments

Comments
 (0)