15
15
package mvcc
16
16
17
17
import (
18
- "sync"
18
+ "bytes"
19
+ "fmt"
19
20
20
21
"github.com/google/btree"
21
22
"go.uber.org/zap"
@@ -30,103 +31,105 @@ type index interface {
30
31
Tombstone (key []byte , rev Revision ) error
31
32
Compact (rev int64 ) map [Revision ]struct {}
32
33
Keep (rev int64 ) map [Revision ]struct {}
33
- Equal (b index ) bool
34
-
35
- Insert (ki * keyIndex )
36
- KeyIndex (ki * keyIndex ) * keyIndex
37
34
}
38
35
39
36
type treeIndex struct {
40
- sync. RWMutex
41
- tree * btree.BTreeG [* keyIndex ]
42
- lg * zap.Logger
37
+ baseRev int64
38
+ revisionTree [] * btree.BTreeG [keyRev ]
39
+ lg * zap.Logger
43
40
}
44
41
45
- func newTreeIndex (lg * zap.Logger ) index {
46
- return & treeIndex {
47
- tree : btree .NewG (32 , func (aki * keyIndex , bki * keyIndex ) bool {
48
- return aki .Less (bki )
49
- }),
50
- lg : lg ,
51
- }
42
+ type keyRev struct {
43
+ key []byte
44
+ mod , created Revision
45
+ version int64
52
46
}
53
47
54
- func (ti * treeIndex ) Put (key []byte , rev Revision ) {
55
- keyi := & keyIndex {key : key }
56
-
57
- ti .Lock ()
58
- defer ti .Unlock ()
59
- okeyi , ok := ti .tree .Get (keyi )
60
- if ! ok {
61
- keyi .put (ti .lg , rev .Main , rev .Sub )
62
- ti .tree .ReplaceOrInsert (keyi )
63
- return
64
- }
65
- okeyi .put (ti .lg , rev .Main , rev .Sub )
48
+ var lessThen btree.LessFunc [keyRev ] = func (k keyRev , k2 keyRev ) bool {
49
+ return compare (k , k2 ) == - 1
66
50
}
67
51
68
- func (ti * treeIndex ) Get (key []byte , atRev int64 ) (modified , created Revision , ver int64 , err error ) {
69
- ti .RLock ()
70
- defer ti .RUnlock ()
71
- return ti .unsafeGet (key , atRev )
52
+ func compare (k keyRev , k2 keyRev ) int {
53
+ return bytes .Compare (k .key , k2 .key )
72
54
}
73
55
74
- func (ti * treeIndex ) unsafeGet (key []byte , atRev int64 ) (modified , created Revision , ver int64 , err error ) {
75
- keyi := & keyIndex {key : key }
76
- if keyi = ti .keyIndex (keyi ); keyi == nil {
77
- return Revision {}, Revision {}, 0 , ErrRevisionNotFound
56
+ func newTreeIndex (lg * zap.Logger ) index {
57
+ return & treeIndex {
58
+ baseRev : 1 ,
59
+ lg : lg ,
60
+ revisionTree : []* btree.BTreeG [keyRev ]{
61
+ btree .NewG (32 , lessThen ),
62
+ },
78
63
}
79
- return keyi .get (ti .lg , atRev )
80
64
}
81
65
82
- func (ti * treeIndex ) KeyIndex (keyi * keyIndex ) * keyIndex {
83
- ti .RLock ()
84
- defer ti .RUnlock ()
85
- return ti .keyIndex (keyi )
86
- }
87
-
88
- func (ti * treeIndex ) keyIndex (keyi * keyIndex ) * keyIndex {
89
- if ki , ok := ti .tree .Get (keyi ); ok {
90
- return ki
66
+ func (ti * treeIndex ) Put (key []byte , rev Revision ) {
67
+ prevTree := ti .revisionTree [len (ti .revisionTree )- 1 ]
68
+ item , found := prevTree .Get (keyRev {key : key })
69
+ created := rev
70
+ var version int64 = 1
71
+ if found {
72
+ created = item .created
73
+ version = item .version + 1
74
+ }
75
+ tirev := ti .rev ()
76
+ if rev .Main == tirev {
77
+ prevTree .ReplaceOrInsert (keyRev {
78
+ key : key ,
79
+ mod : rev ,
80
+ created : created ,
81
+ version : version ,
82
+ })
83
+ } else if rev .Main == tirev + 1 {
84
+ newTree := prevTree .Clone ()
85
+ newTree .ReplaceOrInsert (keyRev {
86
+ key : key ,
87
+ mod : rev ,
88
+ created : created ,
89
+ version : version ,
90
+ })
91
+ ti .revisionTree = append (ti .revisionTree , newTree )
92
+ } else {
93
+ panic (fmt .Sprintf ("append only, lastRev: %d, putRev: %d" , ti .rev (), rev .Main ))
91
94
}
92
- return nil
93
95
}
94
96
95
- func (ti * treeIndex ) unsafeVisit (key , end []byte , f func (ki * keyIndex ) bool ) {
96
- keyi , endi := & keyIndex {key : key }, & keyIndex {key : end }
97
+ func (ti * treeIndex ) rev () int64 {
98
+ return ti .baseRev + int64 (len (ti .revisionTree )) - 1
99
+ }
97
100
98
- ti .tree .AscendGreaterOrEqual (keyi , func (item * keyIndex ) bool {
99
- if len (endi .key ) > 0 && ! item .Less (endi ) {
100
- return false
101
- }
102
- if ! f (item ) {
103
- return false
104
- }
105
- return true
106
- })
101
+ func (ti * treeIndex ) Get (key []byte , atRev int64 ) (modified , created Revision , ver int64 , err error ) {
102
+ tree , err := ti .forRev (atRev )
103
+ if err != nil {
104
+ return modified , created , ver , err
105
+ }
106
+ keyRev , found := tree .Get (keyRev {key : key })
107
+ if ! found {
108
+ return Revision {}, Revision {}, 0 , ErrRevisionNotFound
109
+ }
110
+ return keyRev .mod , keyRev .created , keyRev .version , nil
107
111
}
108
112
109
113
// Revisions returns limited number of revisions from key(included) to end(excluded)
110
114
// at the given rev. The returned slice is sorted in the order of key. There is no limit if limit <= 0.
111
115
// The second return parameter isn't capped by the limit and reflects the total number of revisions.
112
116
func (ti * treeIndex ) Revisions (key , end []byte , atRev int64 , limit int ) (revs []Revision , total int ) {
113
- ti .RLock ()
114
- defer ti .RUnlock ()
115
-
116
117
if end == nil {
117
- rev , _ , _ , err := ti .unsafeGet (key , atRev )
118
+ rev , _ , _ , err := ti .Get (key , atRev )
118
119
if err != nil {
119
120
return nil , 0
120
121
}
121
122
return []Revision {rev }, 1
122
123
}
123
- ti .unsafeVisit (key , end , func (ki * keyIndex ) bool {
124
- if rev , _ , _ , err := ki .get (ti .lg , atRev ); err == nil {
125
- if limit <= 0 || len (revs ) < limit {
126
- revs = append (revs , rev )
127
- }
128
- total ++
124
+ tree , err := ti .forRev (atRev )
125
+ if err != nil {
126
+ return revs , total
127
+ }
128
+ tree .AscendRange (keyRev {key : key }, keyRev {key : end }, func (kr keyRev ) bool {
129
+ if limit <= 0 || len (revs ) < limit {
130
+ revs = append (revs , kr .mod )
129
131
}
132
+ total ++
130
133
return true
131
134
})
132
135
return revs , total
@@ -135,119 +138,95 @@ func (ti *treeIndex) Revisions(key, end []byte, atRev int64, limit int) (revs []
135
138
// CountRevisions returns the number of revisions
136
139
// from key(included) to end(excluded) at the given rev.
137
140
func (ti * treeIndex ) CountRevisions (key , end []byte , atRev int64 ) int {
138
- ti .RLock ()
139
- defer ti .RUnlock ()
140
-
141
141
if end == nil {
142
- _ , _ , _ , err := ti .unsafeGet (key , atRev )
142
+ _ , _ , _ , err := ti .Get (key , atRev )
143
143
if err != nil {
144
144
return 0
145
145
}
146
146
return 1
147
147
}
148
148
total := 0
149
- ti .unsafeVisit (key , end , func (ki * keyIndex ) bool {
150
- if _ , _ , _ , err := ki .get (ti .lg , atRev ); err == nil {
151
- total ++
152
- }
149
+ tree , err := ti .forRev (atRev )
150
+ if err != nil {
151
+ return total
152
+ }
153
+ tree .AscendRange (keyRev {key : key }, keyRev {key : end }, func (kr keyRev ) bool {
154
+ total ++
153
155
return true
154
156
})
155
157
return total
156
158
}
157
159
158
160
func (ti * treeIndex ) Range (key , end []byte , atRev int64 ) (keys [][]byte , revs []Revision ) {
159
- ti .RLock ()
160
- defer ti .RUnlock ()
161
-
162
161
if end == nil {
163
- rev , _ , _ , err := ti .unsafeGet (key , atRev )
162
+ rev , _ , _ , err := ti .Get (key , atRev )
164
163
if err != nil {
165
164
return nil , nil
166
165
}
167
166
return [][]byte {key }, []Revision {rev }
168
167
}
169
- ti .unsafeVisit (key , end , func (ki * keyIndex ) bool {
170
- if rev , _ , _ , err := ki .get (ti .lg , atRev ); err == nil {
171
- revs = append (revs , rev )
172
- keys = append (keys , ki .key )
173
- }
168
+ tree , err := ti .forRev (atRev )
169
+ if err != nil {
170
+ return keys , revs
171
+ }
172
+ tree .AscendRange (keyRev {key : key }, keyRev {key : end }, func (kr keyRev ) bool {
173
+ revs = append (revs , kr .mod )
174
+ keys = append (keys , kr .key )
174
175
return true
175
176
})
176
177
return keys , revs
177
178
}
178
179
179
180
func (ti * treeIndex ) Tombstone (key []byte , rev Revision ) error {
180
- keyi := & keyIndex {key : key }
181
-
182
- ti .Lock ()
183
- defer ti .Unlock ()
184
- ki , ok := ti .tree .Get (keyi )
185
- if ! ok {
181
+ prevTree := ti .revisionTree [len (ti .revisionTree )- 1 ]
182
+ tirev := ti .rev ()
183
+ var found bool
184
+ if rev .Main == tirev {
185
+ _ , found = prevTree .Delete (keyRev {
186
+ key : key ,
187
+ })
188
+ } else if rev .Main == tirev + 1 {
189
+ newTree := prevTree .Clone ()
190
+ _ , found = newTree .Delete (keyRev {
191
+ key : key ,
192
+ })
193
+ ti .revisionTree = append (ti .revisionTree , newTree )
194
+ } else {
195
+ panic (fmt .Sprintf ("append only, lastRev: %d, putRev: %d" , ti .rev (), rev .Main ))
196
+ }
197
+ if ! found {
186
198
return ErrRevisionNotFound
187
199
}
188
-
189
- return ki .tombstone (ti .lg , rev .Main , rev .Sub )
200
+ return nil
190
201
}
191
202
192
203
func (ti * treeIndex ) Compact (rev int64 ) map [Revision ]struct {} {
193
204
available := make (map [Revision ]struct {})
194
205
ti .lg .Info ("compact tree index" , zap .Int64 ("revision" , rev ))
195
- ti .Lock ()
196
- clone := ti .tree .Clone ()
197
- ti .Unlock ()
198
-
199
- clone .Ascend (func (keyi * keyIndex ) bool {
200
- // Lock is needed here to prevent modification to the keyIndex while
201
- // compaction is going on or revision added to empty before deletion
202
- ti .Lock ()
203
- keyi .compact (ti .lg , rev , available )
204
- if keyi .isEmpty () {
205
- _ , ok := ti .tree .Delete (keyi )
206
- if ! ok {
207
- ti .lg .Panic ("failed to delete during compaction" )
208
- }
209
- }
210
- ti .Unlock ()
211
- return true
212
- })
206
+ idx := rev - ti .baseRev
207
+ ti .revisionTree = ti .revisionTree [idx :]
208
+ ti .baseRev = rev
213
209
return available
214
210
}
215
211
216
212
// Keep finds all revisions to be kept for a Compaction at the given rev.
217
213
func (ti * treeIndex ) Keep (rev int64 ) map [Revision ]struct {} {
218
214
available := make (map [Revision ]struct {})
219
- ti .RLock ()
220
- defer ti .RUnlock ()
221
- ti .tree .Ascend (func (keyi * keyIndex ) bool {
222
- keyi .keep (rev , available )
215
+ tree , err := ti .forRev (rev )
216
+ if err != nil {
217
+ return available
218
+ }
219
+ tree .Ascend (func (item keyRev ) bool {
220
+ available [item .mod ] = struct {}{}
223
221
return true
224
222
})
225
223
return available
226
224
}
227
225
228
- func (ti * treeIndex ) Equal (bi index ) bool {
229
- b := bi .(* treeIndex )
230
-
231
- if ti .tree .Len () != b .tree .Len () {
232
- return false
226
+ func (ti * treeIndex ) forRev (rev int64 ) (* btree.BTreeG [keyRev ], error ) {
227
+ idx := rev - ti .baseRev
228
+ if idx < 0 || idx >= int64 (len (ti .revisionTree )) {
229
+ return nil , ErrRevisionNotFound
233
230
}
234
-
235
- equal := true
236
-
237
- ti .tree .Ascend (func (aki * keyIndex ) bool {
238
- bki , _ := b .tree .Get (aki )
239
- if ! aki .equal (bki ) {
240
- equal = false
241
- return false
242
- }
243
- return true
244
- })
245
-
246
- return equal
247
- }
248
-
249
- func (ti * treeIndex ) Insert (ki * keyIndex ) {
250
- ti .Lock ()
251
- defer ti .Unlock ()
252
- ti .tree .ReplaceOrInsert (ki )
231
+ return ti .revisionTree [idx ], nil
253
232
}
0 commit comments