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  }