go.etcd.io/etcd@v3.3.27+incompatible/mvcc/index_test.go (about) 1 // Copyright 2015 The etcd Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package mvcc 16 17 import ( 18 "reflect" 19 "testing" 20 21 "github.com/google/btree" 22 ) 23 24 func TestIndexGet(t *testing.T) { 25 ti := newTreeIndex() 26 ti.Put([]byte("foo"), revision{main: 2}) 27 ti.Put([]byte("foo"), revision{main: 4}) 28 ti.Tombstone([]byte("foo"), revision{main: 6}) 29 30 tests := []struct { 31 rev int64 32 33 wrev revision 34 wcreated revision 35 wver int64 36 werr error 37 }{ 38 {0, revision{}, revision{}, 0, ErrRevisionNotFound}, 39 {1, revision{}, revision{}, 0, ErrRevisionNotFound}, 40 {2, revision{main: 2}, revision{main: 2}, 1, nil}, 41 {3, revision{main: 2}, revision{main: 2}, 1, nil}, 42 {4, revision{main: 4}, revision{main: 2}, 2, nil}, 43 {5, revision{main: 4}, revision{main: 2}, 2, nil}, 44 {6, revision{}, revision{}, 0, ErrRevisionNotFound}, 45 } 46 for i, tt := range tests { 47 rev, created, ver, err := ti.Get([]byte("foo"), tt.rev) 48 if err != tt.werr { 49 t.Errorf("#%d: err = %v, want %v", i, err, tt.werr) 50 } 51 if rev != tt.wrev { 52 t.Errorf("#%d: rev = %+v, want %+v", i, rev, tt.wrev) 53 } 54 if created != tt.wcreated { 55 t.Errorf("#%d: created = %+v, want %+v", i, created, tt.wcreated) 56 } 57 if ver != tt.wver { 58 t.Errorf("#%d: ver = %d, want %d", i, ver, tt.wver) 59 } 60 } 61 } 62 63 func TestIndexRange(t *testing.T) { 64 allKeys := [][]byte{[]byte("foo"), []byte("foo1"), []byte("foo2")} 65 allRevs := []revision{{main: 1}, {main: 2}, {main: 3}} 66 67 ti := newTreeIndex() 68 for i := range allKeys { 69 ti.Put(allKeys[i], allRevs[i]) 70 } 71 72 atRev := int64(3) 73 tests := []struct { 74 key, end []byte 75 wkeys [][]byte 76 wrevs []revision 77 }{ 78 // single key that not found 79 { 80 []byte("bar"), nil, nil, nil, 81 }, 82 // single key that found 83 { 84 []byte("foo"), nil, allKeys[:1], allRevs[:1], 85 }, 86 // range keys, return first member 87 { 88 []byte("foo"), []byte("foo1"), allKeys[:1], allRevs[:1], 89 }, 90 // range keys, return first two members 91 { 92 []byte("foo"), []byte("foo2"), allKeys[:2], allRevs[:2], 93 }, 94 // range keys, return all members 95 { 96 []byte("foo"), []byte("fop"), allKeys, allRevs, 97 }, 98 // range keys, return last two members 99 { 100 []byte("foo1"), []byte("fop"), allKeys[1:], allRevs[1:], 101 }, 102 // range keys, return last member 103 { 104 []byte("foo2"), []byte("fop"), allKeys[2:], allRevs[2:], 105 }, 106 // range keys, return nothing 107 { 108 []byte("foo3"), []byte("fop"), nil, nil, 109 }, 110 } 111 for i, tt := range tests { 112 keys, revs := ti.Range(tt.key, tt.end, atRev) 113 if !reflect.DeepEqual(keys, tt.wkeys) { 114 t.Errorf("#%d: keys = %+v, want %+v", i, keys, tt.wkeys) 115 } 116 if !reflect.DeepEqual(revs, tt.wrevs) { 117 t.Errorf("#%d: revs = %+v, want %+v", i, revs, tt.wrevs) 118 } 119 } 120 } 121 122 func TestIndexTombstone(t *testing.T) { 123 ti := newTreeIndex() 124 ti.Put([]byte("foo"), revision{main: 1}) 125 126 err := ti.Tombstone([]byte("foo"), revision{main: 2}) 127 if err != nil { 128 t.Errorf("tombstone error = %v, want nil", err) 129 } 130 131 _, _, _, err = ti.Get([]byte("foo"), 2) 132 if err != ErrRevisionNotFound { 133 t.Errorf("get error = %v, want nil", err) 134 } 135 err = ti.Tombstone([]byte("foo"), revision{main: 3}) 136 if err != ErrRevisionNotFound { 137 t.Errorf("tombstone error = %v, want %v", err, ErrRevisionNotFound) 138 } 139 } 140 141 func TestIndexRangeSince(t *testing.T) { 142 allKeys := [][]byte{[]byte("foo"), []byte("foo1"), []byte("foo2"), []byte("foo2"), []byte("foo1"), []byte("foo")} 143 allRevs := []revision{{main: 1}, {main: 2}, {main: 3}, {main: 4}, {main: 5}, {main: 6}} 144 145 ti := newTreeIndex() 146 for i := range allKeys { 147 ti.Put(allKeys[i], allRevs[i]) 148 } 149 150 atRev := int64(1) 151 tests := []struct { 152 key, end []byte 153 wrevs []revision 154 }{ 155 // single key that not found 156 { 157 []byte("bar"), nil, nil, 158 }, 159 // single key that found 160 { 161 []byte("foo"), nil, []revision{{main: 1}, {main: 6}}, 162 }, 163 // range keys, return first member 164 { 165 []byte("foo"), []byte("foo1"), []revision{{main: 1}, {main: 6}}, 166 }, 167 // range keys, return first two members 168 { 169 []byte("foo"), []byte("foo2"), []revision{{main: 1}, {main: 2}, {main: 5}, {main: 6}}, 170 }, 171 // range keys, return all members 172 { 173 []byte("foo"), []byte("fop"), allRevs, 174 }, 175 // range keys, return last two members 176 { 177 []byte("foo1"), []byte("fop"), []revision{{main: 2}, {main: 3}, {main: 4}, {main: 5}}, 178 }, 179 // range keys, return last member 180 { 181 []byte("foo2"), []byte("fop"), []revision{{main: 3}, {main: 4}}, 182 }, 183 // range keys, return nothing 184 { 185 []byte("foo3"), []byte("fop"), nil, 186 }, 187 } 188 for i, tt := range tests { 189 revs := ti.RangeSince(tt.key, tt.end, atRev) 190 if !reflect.DeepEqual(revs, tt.wrevs) { 191 t.Errorf("#%d: revs = %+v, want %+v", i, revs, tt.wrevs) 192 } 193 } 194 } 195 196 func TestIndexCompactAndKeep(t *testing.T) { 197 maxRev := int64(20) 198 tests := []struct { 199 key []byte 200 remove bool 201 rev revision 202 created revision 203 ver int64 204 }{ 205 {[]byte("foo"), false, revision{main: 1}, revision{main: 1}, 1}, 206 {[]byte("foo1"), false, revision{main: 2}, revision{main: 2}, 1}, 207 {[]byte("foo2"), false, revision{main: 3}, revision{main: 3}, 1}, 208 {[]byte("foo2"), false, revision{main: 4}, revision{main: 3}, 2}, 209 {[]byte("foo"), false, revision{main: 5}, revision{main: 1}, 2}, 210 {[]byte("foo1"), false, revision{main: 6}, revision{main: 2}, 2}, 211 {[]byte("foo1"), true, revision{main: 7}, revision{}, 0}, 212 {[]byte("foo2"), true, revision{main: 8}, revision{}, 0}, 213 {[]byte("foo"), true, revision{main: 9}, revision{}, 0}, 214 {[]byte("foo"), false, revision{10, 0}, revision{10, 0}, 1}, 215 {[]byte("foo1"), false, revision{10, 1}, revision{10, 1}, 1}, 216 } 217 218 // Continuous Compact and Keep 219 ti := newTreeIndex() 220 for _, tt := range tests { 221 if tt.remove { 222 ti.Tombstone(tt.key, tt.rev) 223 } else { 224 ti.Put(tt.key, tt.rev) 225 } 226 } 227 for i := int64(1); i < maxRev; i++ { 228 am := ti.Compact(i) 229 keep := ti.Keep(i) 230 if !(reflect.DeepEqual(am, keep)) { 231 t.Errorf("#%d: compact keep %v != Keep keep %v", i, am, keep) 232 } 233 wti := &treeIndex{tree: btree.New(32)} 234 for _, tt := range tests { 235 if _, ok := am[tt.rev]; ok || tt.rev.GreaterThan(revision{main: i}) { 236 if tt.remove { 237 wti.Tombstone(tt.key, tt.rev) 238 } else { 239 restore(wti, tt.key, tt.created, tt.rev, tt.ver) 240 } 241 } 242 } 243 if !ti.Equal(wti) { 244 t.Errorf("#%d: not equal ti", i) 245 } 246 } 247 248 // Once Compact and Keep 249 for i := int64(1); i < maxRev; i++ { 250 ti := newTreeIndex() 251 for _, tt := range tests { 252 if tt.remove { 253 ti.Tombstone(tt.key, tt.rev) 254 } else { 255 ti.Put(tt.key, tt.rev) 256 } 257 } 258 am := ti.Compact(i) 259 keep := ti.Keep(i) 260 if !(reflect.DeepEqual(am, keep)) { 261 t.Errorf("#%d: compact keep %v != Keep keep %v", i, am, keep) 262 } 263 wti := &treeIndex{tree: btree.New(32)} 264 for _, tt := range tests { 265 if _, ok := am[tt.rev]; ok || tt.rev.GreaterThan(revision{main: i}) { 266 if tt.remove { 267 wti.Tombstone(tt.key, tt.rev) 268 } else { 269 restore(wti, tt.key, tt.created, tt.rev, tt.ver) 270 } 271 } 272 } 273 if !ti.Equal(wti) { 274 t.Errorf("#%d: not equal ti", i) 275 } 276 } 277 } 278 279 func restore(ti *treeIndex, key []byte, created, modified revision, ver int64) { 280 keyi := &keyIndex{key: key} 281 282 ti.Lock() 283 defer ti.Unlock() 284 item := ti.tree.Get(keyi) 285 if item == nil { 286 keyi.restore(created, modified, ver) 287 ti.tree.ReplaceOrInsert(keyi) 288 return 289 } 290 okeyi := item.(*keyIndex) 291 okeyi.put(modified.main, modified.sub) 292 }