github.com/andy-kimball/arenaskl@v0.0.0-20200617143215-f701008588b9/iterator.go (about) 1 /* 2 * Copyright 2017 Dgraph Labs, Inc. and Contributors 3 * Modifications copyright (C) 2017 Andy Kimball and Contributors 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package arenaskl 19 20 import ( 21 "runtime" 22 "sync/atomic" 23 "unsafe" 24 ) 25 26 type splice struct { 27 prev *node 28 next *node 29 } 30 31 func (s *splice) init(prev, next *node) { 32 s.prev = prev 33 s.next = next 34 } 35 36 // Iterator is an iterator over the skiplist object. Call Init to associate a 37 // skiplist with the iterator. The current state of the iterator can be cloned 38 // by simply value copying the struct. All iterator methods are thread-safe. 39 type Iterator struct { 40 list *Skiplist 41 arena *Arena 42 nd *node 43 value uint64 44 } 45 46 // Init associates the iterator with a skiplist and resets all state. 47 func (it *Iterator) Init(list *Skiplist) { 48 it.list = list 49 it.arena = list.arena 50 it.nd = nil 51 it.value = 0 52 } 53 54 // Valid returns true iff the iterator is positioned at a valid node. 55 func (it *Iterator) Valid() bool { return it.nd != nil } 56 57 // Key returns the key at the current position. 58 func (it *Iterator) Key() []byte { 59 return it.nd.getKey(it.arena) 60 } 61 62 // Value returns the value at the current position. 63 func (it *Iterator) Value() []byte { 64 valOffset, valSize := decodeValue(it.value) 65 return it.arena.GetBytes(valOffset, uint32(valSize)) 66 } 67 68 // Meta returns the metadata at the current position. 69 func (it *Iterator) Meta() uint16 { 70 return decodeMeta(it.value) 71 } 72 73 // Next advances to the next position. If there are no following nodes, then 74 // Valid() will be false after this call. 75 func (it *Iterator) Next() { 76 next := it.list.getNext(it.nd, 0) 77 it.setNode(next, false) 78 } 79 80 // Prev moves to the previous position. If there are no previous nodes, then 81 // Valid() will be false after this call. 82 func (it *Iterator) Prev() { 83 prev := it.list.getPrev(it.nd, 0) 84 it.setNode(prev, true) 85 } 86 87 // Seek searches for the record with the given key. If it is present in the 88 // skiplist, then Seek positions the iterator on that record and returns true. 89 // If the record is not present, then Seek positions the iterator on the 90 // following node (if it exists) and returns false. 91 func (it *Iterator) Seek(key []byte) (found bool) { 92 var next *node 93 _, next, found = it.seekForBaseSplice(key) 94 present := it.setNode(next, false) 95 return found && present 96 } 97 98 // SeekForPrev searches for the record with the given key. If it is present in 99 // the skiplist, then SeekForPrev positions the iterator on that record and 100 // returns true. If the record is not present, then SeekForPrev positions the 101 // iterator on the preceding node (if it exists) and returns false. 102 func (it *Iterator) SeekForPrev(key []byte) (found bool) { 103 var prev, next *node 104 prev, next, found = it.seekForBaseSplice(key) 105 106 var present bool 107 if found { 108 present = it.setNode(next, true) 109 } else { 110 present = it.setNode(prev, true) 111 } 112 113 return found && present 114 } 115 116 // Add creates a new key/value record if it does not yet exist and positions the 117 // iterator on it. If the record already exists, then Add positions the iterator 118 // on the most current value and returns ErrRecordExists. If there isn't enough 119 // room in the arena, then Add returns ErrArenaFull. 120 func (it *Iterator) Add(key []byte, val []byte, meta uint16) error { 121 var spl [maxHeight]splice 122 if it.seekForSplice(key, &spl) { 123 // Found a matching node, but handle case where it's been deleted. 124 return it.setValueIfDeleted(spl[0].next, val, meta) 125 } 126 127 if it.list.testing { 128 // Add delay to make it easier to test race between this thread 129 // and another thread that sees the intermediate state between 130 // finding the splice and using it. 131 runtime.Gosched() 132 } 133 134 nd, height, err := it.list.newNode(key, val, meta) 135 if err != nil { 136 return err 137 } 138 139 value := nd.value 140 ndOffset := it.arena.GetPointerOffset(unsafe.Pointer(nd)) 141 142 // We always insert from the base level and up. After you add a node in base 143 // level, we cannot create a node in the level above because it would have 144 // discovered the node in the base level. 145 var found bool 146 for i := 0; i < int(height); i++ { 147 prev := spl[i].prev 148 next := spl[i].next 149 150 if prev == nil { 151 // New node increased the height of the skiplist, so assume that the 152 // new level has not yet been populated. 153 if next != nil { 154 panic("next is expected to be nil, since prev is nil") 155 } 156 157 prev = it.list.head 158 next = it.list.tail 159 } 160 161 // +----------------+ +------------+ +----------------+ 162 // | prev | | nd | | next | 163 // | prevNextOffset |---->| | | | 164 // | |<----| prevOffset | | | 165 // | | | nextOffset |---->| | 166 // | | | |<----| nextPrevOffset | 167 // +----------------+ +------------+ +----------------+ 168 // 169 // 1. Initialize prevOffset and nextOffset to point to prev and next. 170 // 2. CAS prevNextOffset to repoint from next to nd. 171 // 3. CAS nextPrevOffset to repoint from prev to nd. 172 for { 173 prevOffset := it.arena.GetPointerOffset(unsafe.Pointer(prev)) 174 nextOffset := it.arena.GetPointerOffset(unsafe.Pointer(next)) 175 nd.tower[i].init(prevOffset, nextOffset) 176 177 // Check whether next has an updated link to prev. If it does not, 178 // that can mean one of two things: 179 // 1. The thread that added the next node hasn't yet had a chance 180 // to add the prev link (but will shortly). 181 // 2. Another thread has added a new node between prev and next. 182 nextPrevOffset := next.prevOffset(i) 183 if nextPrevOffset != prevOffset { 184 // Determine whether #1 or #2 is true by checking whether prev 185 // is still pointing to next. As long as the atomic operations 186 // have at least acquire/release semantics (no need for 187 // sequential consistency), this works, as it is equivalent to 188 // the "publication safety" pattern. 189 prevNextOffset := prev.nextOffset(i) 190 if prevNextOffset == nextOffset { 191 // Ok, case #1 is true, so help the other thread along by 192 // updating the next node's prev link. 193 next.casPrevOffset(i, nextPrevOffset, prevOffset) 194 } 195 } 196 197 if prev.casNextOffset(i, nextOffset, ndOffset) { 198 // Managed to insert nd between prev and next, so update the next 199 // node's prev link and go to the next level. 200 if it.list.testing { 201 // Add delay to make it easier to test race between this thread 202 // and another thread that sees the intermediate state between 203 // setting next and setting prev. 204 runtime.Gosched() 205 } 206 207 next.casPrevOffset(i, prevOffset, ndOffset) 208 break 209 } 210 211 // CAS failed. We need to recompute prev and next. It is unlikely to 212 // be helpful to try to use a different level as we redo the search, 213 // because it is unlikely that lots of nodes are inserted between prev 214 // and next. 215 prev, next, found = it.list.findSpliceForLevel(key, i, prev) 216 if found { 217 if i != 0 { 218 panic("how can another thread have inserted a node at a non-base level?") 219 } 220 221 return it.setValueIfDeleted(next, val, meta) 222 } 223 } 224 } 225 226 it.value = value 227 it.nd = nd 228 return nil 229 } 230 231 // Set updates the value of the current iteration record if it has not been 232 // updated or deleted since iterating or seeking to it. If the record has been 233 // updated, then Set positions the iterator on the most current value and 234 // returns ErrRecordUpdated. If the record has been deleted, then Set keeps 235 // the iterator positioned on the current record with the current value and 236 // returns ErrRecordDeleted. 237 func (it *Iterator) Set(val []byte, meta uint16) error { 238 new, err := it.list.allocVal(val, meta) 239 if err != nil { 240 return err 241 } 242 243 return it.trySetValue(new) 244 } 245 246 // SetMeta updates the meta value of the current iteration record if it has not 247 // been updated or deleted since iterating or seeking to it. If the record has 248 // been updated, then SetMeta positions the iterator on the most current value 249 // and returns ErrRecordUpdated. If the record has been deleted, then SetMeta 250 // keeps the iterator positioned on the current record with the current value 251 // and returns ErrRecordDeleted. 252 func (it *Iterator) SetMeta(meta uint16) error { 253 // Try to reuse the same value bytes. Do this only in the case where meta 254 // is increasing, in order to avoid cases where the meta is changed, then 255 // changed back to the original value, which would make it impossible to 256 // detect updates had occurred in the interim. 257 if meta > decodeMeta(it.value) { 258 valOffset, valSize := decodeValue(it.value) 259 new := encodeValue(valOffset, valSize, meta) 260 return it.trySetValue(new) 261 } 262 263 return it.Set(it.Value(), meta) 264 } 265 266 // Delete marks the current iterator record as deleted from the store if it 267 // has not been updated since iterating or seeking to it. If the record has 268 // been updated, then Delete positions the iterator on the most current value 269 // and returns ErrRecordUpdated. If the record is deleted, then Delete positions 270 // the iterator on the next record. 271 func (it *Iterator) Delete() error { 272 if !atomic.CompareAndSwapUint64(&it.nd.value, it.value, deletedVal) { 273 if it.setNode(it.nd, false) { 274 return ErrRecordUpdated 275 } 276 277 return nil 278 } 279 280 // Deletion succeeded, so position iterator on next non-deleted node. 281 next := it.list.getNext(it.nd, 0) 282 it.setNode(next, false) 283 return nil 284 } 285 286 // SeekToFirst seeks position at the first entry in list. 287 // Final state of iterator is Valid() iff list is not empty. 288 func (it *Iterator) SeekToFirst() { 289 it.setNode(it.list.getNext(it.list.head, 0), false) 290 } 291 292 // SeekToLast seeks position at the last entry in list. 293 // Final state of iterator is Valid() iff list is not empty. 294 func (it *Iterator) SeekToLast() { 295 it.setNode(it.list.getPrev(it.list.tail, 0), true) 296 } 297 298 func (it *Iterator) setNode(nd *node, reverse bool) bool { 299 var value uint64 300 301 success := true 302 for nd != nil { 303 // Skip past deleted nodes. 304 value = atomic.LoadUint64(&nd.value) 305 if value != deletedVal { 306 break 307 } 308 309 success = false 310 311 if reverse { 312 nd = it.list.getPrev(nd, 0) 313 } else { 314 nd = it.list.getNext(nd, 0) 315 } 316 } 317 318 it.value = value 319 it.nd = nd 320 return success 321 } 322 323 func (it *Iterator) trySetValue(new uint64) error { 324 if !atomic.CompareAndSwapUint64(&it.nd.value, it.value, new) { 325 old := atomic.LoadUint64(&it.nd.value) 326 if old == deletedVal { 327 return ErrRecordDeleted 328 } 329 330 it.value = old 331 return ErrRecordUpdated 332 } 333 334 it.value = new 335 return nil 336 } 337 338 func (it *Iterator) setValueIfDeleted(nd *node, val []byte, meta uint16) error { 339 var new uint64 340 var err error 341 342 for { 343 old := atomic.LoadUint64(&nd.value) 344 345 if old != deletedVal { 346 it.value = old 347 it.nd = nd 348 return ErrRecordExists 349 } 350 351 if new == 0 { 352 new, err = it.list.allocVal(val, meta) 353 if err != nil { 354 return err 355 } 356 } 357 358 if atomic.CompareAndSwapUint64(&nd.value, old, new) { 359 break 360 } 361 } 362 363 it.value = new 364 it.nd = nd 365 return err 366 } 367 368 func (it *Iterator) seekForSplice(key []byte, spl *[maxHeight]splice) (found bool) { 369 var prev, next *node 370 371 level := int(it.list.Height() - 1) 372 prev = it.list.head 373 374 for { 375 prev, next, found = it.list.findSpliceForLevel(key, level, prev) 376 if next == nil { 377 next = it.list.tail 378 } 379 380 spl[level].init(prev, next) 381 382 if level == 0 { 383 break 384 } 385 386 level-- 387 } 388 389 return 390 } 391 392 func (it *Iterator) seekForBaseSplice(key []byte) (prev, next *node, found bool) { 393 level := int(it.list.Height() - 1) 394 395 prev = it.list.head 396 for { 397 prev, next, found = it.list.findSpliceForLevel(key, level, prev) 398 399 if found { 400 break 401 } 402 403 if level == 0 { 404 break 405 } 406 407 level-- 408 } 409 410 return 411 } 412 413 // IsSameArray returns true if the slices are the same length and the array 414 // underlying the two slices is the same. Always returns false for empty arrays. 415 func isSameArray(val1, val2 []byte) bool { 416 if len(val1) == len(val2) && len(val1) > 0 { 417 return &val1[0] == &val2[0] 418 } 419 420 return false 421 }