-
Notifications
You must be signed in to change notification settings - Fork 492
/
Copy pathdatatest.go
140 lines (131 loc) · 3.56 KB
/
datatest.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// Copyright 2022 The LevelDB-Go and Pebble Authors. All rights reserved. Use
// of this source code is governed by a BSD-style license that can be found in
// the LICENSE file.
// Package datatest provides common datadriven test commands for use outside of
// the root Pebble package.
package datatest
import (
"strings"
"sync"
"github.com/cockroachdb/datadriven"
"github.com/cockroachdb/errors"
"github.com/cockroachdb/pebble"
)
// TODO(jackson): Consider a refactoring that can consolidate this package and
// the datadriven commands defined in pebble/data_test.go.
// DefineBatch interprets the provided datadriven command as a sequence of write
// operations, one-per-line, to apply to the provided batch.
func DefineBatch(d *datadriven.TestData, b *pebble.Batch) error {
for _, line := range strings.Split(d.Input, "\n") {
parts := strings.Fields(line)
if len(parts) == 0 {
continue
}
if parts[1] == `<nil>` {
parts[1] = ""
}
var err error
switch parts[0] {
case "set":
if len(parts) != 3 {
return errors.Errorf("%s expects 2 arguments", parts[0])
}
err = b.Set([]byte(parts[1]), []byte(parts[2]), nil)
case "del":
if len(parts) != 2 {
return errors.Errorf("%s expects 1 argument", parts[0])
}
err = b.Delete([]byte(parts[1]), nil)
case "singledel":
if len(parts) != 2 {
return errors.Errorf("%s expects 1 argument", parts[0])
}
err = b.SingleDelete([]byte(parts[1]), nil)
case "del-range":
if len(parts) != 3 {
return errors.Errorf("%s expects 2 arguments", parts[0])
}
err = b.DeleteRange([]byte(parts[1]), []byte(parts[2]), nil)
case "merge":
if len(parts) != 3 {
return errors.Errorf("%s expects 2 arguments", parts[0])
}
err = b.Merge([]byte(parts[1]), []byte(parts[2]), nil)
case "range-key-set":
if len(parts) != 5 {
return errors.Errorf("%s expects 4 arguments", parts[0])
}
err = b.RangeKeySet(
[]byte(parts[1]),
[]byte(parts[2]),
[]byte(parts[3]),
[]byte(parts[4]),
nil)
case "range-key-unset":
if len(parts) != 4 {
return errors.Errorf("%s expects 3 arguments", parts[0])
}
err = b.RangeKeyUnset(
[]byte(parts[1]),
[]byte(parts[2]),
[]byte(parts[3]),
nil)
case "range-key-del":
if len(parts) != 3 {
return errors.Errorf("%s expects 2 arguments", parts[0])
}
err = b.RangeKeyDelete(
[]byte(parts[1]),
[]byte(parts[2]),
nil)
default:
return errors.Errorf("unknown op: %s", parts[0])
}
if err != nil {
return err
}
}
return nil
}
// CompactionTracker is a listener that tracks the number of compactions.
type CompactionTracker struct {
sync.Cond
count int
attached bool
}
// NewCompactionTracker setups the necessary options to keep track of the
// compactions that are in flight.
func NewCompactionTracker(options *pebble.Options) *CompactionTracker {
ct := CompactionTracker{}
ct.Cond = sync.Cond{
L: &sync.Mutex{},
}
ct.attached = true
el := pebble.EventListener{
CompactionEnd: func(info pebble.CompactionInfo) {
ct.L.Lock()
ct.count--
ct.Broadcast()
ct.L.Unlock()
},
CompactionBegin: func(info pebble.CompactionInfo) {
ct.L.Lock()
ct.count++
ct.Broadcast()
ct.L.Unlock()
},
}
options.AddEventListener(el)
return &ct
}
// WaitForInflightCompactionsToEqual waits until compactions meet the specified target.
func (cql *CompactionTracker) WaitForInflightCompactionsToEqual(target int) {
cql.L.Lock()
if !cql.attached {
panic("Cannot wait for compactions if listener has not been attached")
}
for cql.count != target {
cql.Wait()
}
cql.L.Unlock()
}