Skip to content

Commit ba92ae1

Browse files
findleyrgopherbot
authored andcommitted
internal/persistent: avoid incorrect map validation due to multiple keys
Fix the test failure demonstrated in the following failed builder: https://build.golang.org/log/d0511c583201e8701e72066985ebf950d9f5511d It should be OK to set multiple keys in the validated map. Support this by keeping track of seen and deletion clock time. There are still potential problems with this analysis (specifically, if a map is constructed via SetAll), but we ignore those problems for now. Change-Id: I5940d25f18afe31e13bc71f74d4eea7d737d593d Reviewed-on: https://go-review.googlesource.com/c/tools/+/448696 Reviewed-by: Alan Donovan <[email protected]> Auto-Submit: Robert Findley <[email protected]> Run-TryBot: Robert Findley <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
1 parent 9474ca3 commit ba92ae1

File tree

1 file changed

+40
-27
lines changed

1 file changed

+40
-27
lines changed

internal/persistent/map_test.go

+40-27
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,15 @@ type mapEntry struct {
1919

2020
type validatedMap struct {
2121
impl *Map
22-
expected map[int]int
23-
deleted map[mapEntry]struct{}
24-
seen map[mapEntry]struct{}
22+
expected map[int]int // current key-value mapping.
23+
deleted map[mapEntry]int // maps deleted entries to their clock time of last deletion
24+
seen map[mapEntry]int // maps seen entries to their clock time of last insertion
25+
clock int
2526
}
2627

2728
func TestSimpleMap(t *testing.T) {
28-
deletedEntries := make(map[mapEntry]struct{})
29-
seenEntries := make(map[mapEntry]struct{})
29+
deletedEntries := make(map[mapEntry]int)
30+
seenEntries := make(map[mapEntry]int)
3031

3132
m1 := &validatedMap{
3233
impl: NewMap(func(a, b interface{}) bool {
@@ -43,7 +44,7 @@ func TestSimpleMap(t *testing.T) {
4344
validateRef(t, m1, m3)
4445
m3.destroy()
4546

46-
assertSameMap(t, deletedEntries, map[mapEntry]struct{}{
47+
assertSameMap(t, entrySet(deletedEntries), map[mapEntry]struct{}{
4748
{key: 8, value: 8}: {},
4849
})
4950

@@ -59,7 +60,7 @@ func TestSimpleMap(t *testing.T) {
5960
m1.set(t, 6, 6)
6061
validateRef(t, m1)
6162

62-
assertSameMap(t, deletedEntries, map[mapEntry]struct{}{
63+
assertSameMap(t, entrySet(deletedEntries), map[mapEntry]struct{}{
6364
{key: 2, value: 2}: {},
6465
{key: 8, value: 8}: {},
6566
})
@@ -98,7 +99,7 @@ func TestSimpleMap(t *testing.T) {
9899

99100
m1.destroy()
100101

101-
assertSameMap(t, deletedEntries, map[mapEntry]struct{}{
102+
assertSameMap(t, entrySet(deletedEntries), map[mapEntry]struct{}{
102103
{key: 2, value: 2}: {},
103104
{key: 6, value: 60}: {},
104105
{key: 8, value: 8}: {},
@@ -114,12 +115,12 @@ func TestSimpleMap(t *testing.T) {
114115

115116
m2.destroy()
116117

117-
assertSameMap(t, seenEntries, deletedEntries)
118+
assertSameMap(t, entrySet(seenEntries), entrySet(deletedEntries))
118119
}
119120

120121
func TestRandomMap(t *testing.T) {
121-
deletedEntries := make(map[mapEntry]struct{})
122-
seenEntries := make(map[mapEntry]struct{})
122+
deletedEntries := make(map[mapEntry]int)
123+
seenEntries := make(map[mapEntry]int)
123124

124125
m := &validatedMap{
125126
impl: NewMap(func(a, b interface{}) bool {
@@ -132,7 +133,7 @@ func TestRandomMap(t *testing.T) {
132133

133134
keys := make([]int, 0, 1000)
134135
for i := 0; i < 1000; i++ {
135-
key := rand.Int()
136+
key := rand.Intn(10000)
136137
m.set(t, key, key)
137138
keys = append(keys, key)
138139

@@ -148,12 +149,20 @@ func TestRandomMap(t *testing.T) {
148149
}
149150

150151
m.destroy()
151-
assertSameMap(t, seenEntries, deletedEntries)
152+
assertSameMap(t, entrySet(seenEntries), entrySet(deletedEntries))
153+
}
154+
155+
func entrySet(m map[mapEntry]int) map[mapEntry]struct{} {
156+
set := make(map[mapEntry]struct{})
157+
for k := range m {
158+
set[k] = struct{}{}
159+
}
160+
return set
152161
}
153162

154163
func TestUpdate(t *testing.T) {
155-
deletedEntries := make(map[mapEntry]struct{})
156-
seenEntries := make(map[mapEntry]struct{})
164+
deletedEntries := make(map[mapEntry]int)
165+
seenEntries := make(map[mapEntry]int)
157166

158167
m1 := &validatedMap{
159168
impl: NewMap(func(a, b interface{}) bool {
@@ -173,15 +182,7 @@ func TestUpdate(t *testing.T) {
173182

174183
m1.destroy()
175184
m2.destroy()
176-
assertSameMap(t, seenEntries, deletedEntries)
177-
}
178-
179-
func (vm *validatedMap) onDelete(t *testing.T, key, value int) {
180-
entry := mapEntry{key: key, value: value}
181-
if _, ok := vm.deleted[entry]; ok {
182-
t.Fatalf("tried to delete entry twice, key: %d, value: %d", key, value)
183-
}
184-
vm.deleted[entry] = struct{}{}
185+
assertSameMap(t, entrySet(seenEntries), entrySet(deletedEntries))
185186
}
186187

187188
func validateRef(t *testing.T, maps ...*validatedMap) {
@@ -234,9 +235,12 @@ func (vm *validatedMap) validate(t *testing.T) {
234235

235236
validateNode(t, vm.impl.root, vm.impl.less)
236237

238+
// Note: this validation may not make sense if maps were constructed using
239+
// SetAll operations. If this proves to be problematic, remove the clock,
240+
// deleted, and seen fields.
237241
for key, value := range vm.expected {
238242
entry := mapEntry{key: key, value: value}
239-
if _, ok := vm.deleted[entry]; ok {
243+
if deleteAt := vm.deleted[entry]; deleteAt > vm.seen[entry] {
240244
t.Fatalf("entry is deleted prematurely, key: %d, value: %d", key, value)
241245
}
242246
}
@@ -281,19 +285,27 @@ func validateNode(t *testing.T, node *mapNode, less func(a, b interface{}) bool)
281285

282286
func (vm *validatedMap) setAll(t *testing.T, other *validatedMap) {
283287
vm.impl.SetAll(other.impl)
288+
289+
// Note: this is buggy because we are not updating vm.clock, vm.deleted, or
290+
// vm.seen.
284291
for key, value := range other.expected {
285292
vm.expected[key] = value
286293
}
287294
vm.validate(t)
288295
}
289296

290297
func (vm *validatedMap) set(t *testing.T, key, value int) {
291-
vm.seen[mapEntry{key: key, value: value}] = struct{}{}
298+
entry := mapEntry{key: key, value: value}
299+
300+
vm.clock++
301+
vm.seen[entry] = vm.clock
302+
292303
vm.impl.Set(key, value, func(deletedKey, deletedValue interface{}) {
293304
if deletedKey != key || deletedValue != value {
294305
t.Fatalf("unexpected passed in deleted entry: %v/%v, expected: %v/%v", deletedKey, deletedValue, key, value)
295306
}
296-
vm.onDelete(t, key, value)
307+
// Not safe if closure shared between two validatedMaps.
308+
vm.deleted[entry] = vm.clock
297309
})
298310
vm.expected[key] = value
299311
vm.validate(t)
@@ -305,6 +317,7 @@ func (vm *validatedMap) set(t *testing.T, key, value int) {
305317
}
306318

307319
func (vm *validatedMap) remove(t *testing.T, key int) {
320+
vm.clock++
308321
vm.impl.Delete(key)
309322
delete(vm.expected, key)
310323
vm.validate(t)

0 commit comments

Comments
 (0)