问题就出在这里,假如Copy组成新链表的同一时刻,暂未更新链表头。这时候别的线程操作,更新,或者删除这个bucket链表段中的元素,那么当前copy的这段链表段就不是最新的数据了,然后用这条脏的链表段,更新表头,会覆盖了之前的操作,导致之前别的线程操作的丢失。
func TestBucketDelaySecDeleteNoLocker(t *testing.T) {
b := newBucket()
wg := sync.WaitGroup{}
wg.Add(2)
p, _ := newPair("A", "a")
b.Put(p, nil)
p, _ = newPair("B", "b")
b.Put(p, nil)
p, _ = newPair("C", "c")
b.Put(p, nil)
//c b a
t.Logf("before bucket:\n%v\n", b)
go func() {
defer wg.Done()
p, _ := newPair("D", "d")
_, err := b.Put(p, nil)
if err != nil {
t.Fatalf("An error occurs when putting a pair to the bucket: %s (pair: %#v)", b, p)
}
// bucket should be D C B A
t.Logf("after put item D, bucket:\n%v\n", b)
}()
go func() {
defer wg.Done()
// delete item C
b.Delete("C", nil)
}()
wg.Wait()
expected := []string{"D", "B", "A"}
actual := make([]string, 0)
for curr := b.GetFirstPair(); curr != nil; curr = curr.Next() {
actual = append(actual, curr.Key())
}
t.Logf("after delete C , bucket:\n%v\n", b)
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("expected %v , but %v", expected, actual)
}
}
=== RUN TestBucketDelaySecDeleteNoLocker
bucket_test.go:323: before bucket:
[ pair{key:C, hash:67, element:c, nextKey:B} pair{key:B, hash:66, element:b, nextKey:A} pair{key:A, hash:65, element:a, nextKey:} ]
bucket_test.go:333: after put item D, bucket:
[ pair{key:D, hash:68, element:d, nextKey:C} pair{key:C, hash:67, element:c, nextKey:B} pair{key:B, hash:66, element:b, nextKey:A} pair{key:A, hash:65, element:a, nextKey:} ]
bucket_test.go:349: after delete C , bucket:
[ pair{key:B, hash:66, element:b, nextKey:A} pair{key:A, hash:65, element:a, nextKey:} ]
bucket_test.go:352: expected [D B A] , but [B A]
--- FAIL: TestBucketDelaySecDeleteNoLocker (1.01s)
FAIL