github.com/bhojpur/cache@v0.0.4/pkg/memory/cursor.go (about)

     1  package memory
     2  
     3  // Copyright (c) 2018 Bhojpur Consulting Private Limited, India. All rights reserved.
     4  
     5  // Permission is hereby granted, free of charge, to any person obtaining a copy
     6  // of this software and associated documentation files (the "Software"), to deal
     7  // in the Software without restriction, including without limitation the rights
     8  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     9  // copies of the Software, and to permit persons to whom the Software is
    10  // furnished to do so, subject to the following conditions:
    11  
    12  // The above copyright notice and this permission notice shall be included in
    13  // all copies or substantial portions of the Software.
    14  
    15  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    16  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    17  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    18  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    19  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    20  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    21  // THE SOFTWARE.
    22  
    23  import (
    24  	"bytes"
    25  	"fmt"
    26  	"sort"
    27  )
    28  
    29  // Cursor represents an iterator that can traverse over all key/value pairs
    30  // in a bucket in sorted order.
    31  //
    32  // Cursors see nested buckets with value == nil.
    33  //
    34  // Cursors can be obtained from a transaction and are valid as long as the
    35  // transaction is open.
    36  //
    37  // Keys and values returned from the cursor are only valid for the life of
    38  // the transaction.
    39  //
    40  // Changing data while traversing with a cursor may cause it to be invalidated
    41  // and return unexpected keys and/or values. You must reposition your cursor
    42  // after mutating data.
    43  type Cursor struct {
    44  	bucket *Bucket
    45  	stack  []elemRef
    46  }
    47  
    48  // Bucket returns the bucket that this cursor was created from.
    49  func (c *Cursor) Bucket() *Bucket {
    50  	return c.bucket
    51  }
    52  
    53  // First moves the cursor to the first item in the bucket and returns its key and value.
    54  // If the bucket is empty then a nil key and value are returned.
    55  // The returned key and value are only valid for the life of the transaction.
    56  func (c *Cursor) First() (key []byte, value []byte) {
    57  	_assert(c.bucket.tx.db != nil, "tx closed")
    58  	c.stack = c.stack[:0]
    59  	p, n := c.bucket.pageNode(c.bucket.root)
    60  	c.stack = append(c.stack, elemRef{page: p, node: n, index: 0})
    61  	c.first()
    62  
    63  	// If we land on an empty page then move to the next value.
    64  	if c.stack[len(c.stack)-1].count() == 0 {
    65  		c.next()
    66  	}
    67  
    68  	k, v, flags := c.keyValue()
    69  	if (flags & uint32(bucketLeafFlag)) != 0 {
    70  		return k, nil
    71  	}
    72  	return k, v
    73  
    74  }
    75  
    76  // Last moves the cursor to the last item in the bucket and returns its key and value.
    77  // If the bucket is empty then a nil key and value are returned.
    78  // The returned key and value are only valid for the life of the transaction.
    79  func (c *Cursor) Last() (key []byte, value []byte) {
    80  	_assert(c.bucket.tx.db != nil, "tx closed")
    81  	c.stack = c.stack[:0]
    82  	p, n := c.bucket.pageNode(c.bucket.root)
    83  	ref := elemRef{page: p, node: n}
    84  	ref.index = ref.count() - 1
    85  	c.stack = append(c.stack, ref)
    86  	c.last()
    87  	k, v, flags := c.keyValue()
    88  	if (flags & uint32(bucketLeafFlag)) != 0 {
    89  		return k, nil
    90  	}
    91  	return k, v
    92  }
    93  
    94  // Next moves the cursor to the next item in the bucket and returns its key and value.
    95  // If the cursor is at the end of the bucket then a nil key and value are returned.
    96  // The returned key and value are only valid for the life of the transaction.
    97  func (c *Cursor) Next() (key []byte, value []byte) {
    98  	_assert(c.bucket.tx.db != nil, "tx closed")
    99  	k, v, flags := c.next()
   100  	if (flags & uint32(bucketLeafFlag)) != 0 {
   101  		return k, nil
   102  	}
   103  	return k, v
   104  }
   105  
   106  // Prev moves the cursor to the previous item in the bucket and returns its key and value.
   107  // If the cursor is at the beginning of the bucket then a nil key and value are returned.
   108  // The returned key and value are only valid for the life of the transaction.
   109  func (c *Cursor) Prev() (key []byte, value []byte) {
   110  	_assert(c.bucket.tx.db != nil, "tx closed")
   111  
   112  	// Attempt to move back one element until we're successful.
   113  	// Move up the stack as we hit the beginning of each page in our stack.
   114  	for i := len(c.stack) - 1; i >= 0; i-- {
   115  		elem := &c.stack[i]
   116  		if elem.index > 0 {
   117  			elem.index--
   118  			break
   119  		}
   120  		c.stack = c.stack[:i]
   121  	}
   122  
   123  	// If we've hit the end then return nil.
   124  	if len(c.stack) == 0 {
   125  		return nil, nil
   126  	}
   127  
   128  	// Move down the stack to find the last element of the last leaf under this branch.
   129  	c.last()
   130  	k, v, flags := c.keyValue()
   131  	if (flags & uint32(bucketLeafFlag)) != 0 {
   132  		return k, nil
   133  	}
   134  	return k, v
   135  }
   136  
   137  // Seek moves the cursor to a given key and returns it.
   138  // If the key does not exist then the next key is used. If no keys
   139  // follow, a nil key is returned.
   140  // The returned key and value are only valid for the life of the transaction.
   141  func (c *Cursor) Seek(seek []byte) (key []byte, value []byte) {
   142  	k, v, flags := c.seek(seek)
   143  
   144  	// If we ended up after the last element of a page then move to the next one.
   145  	if ref := &c.stack[len(c.stack)-1]; ref.index >= ref.count() {
   146  		k, v, flags = c.next()
   147  	}
   148  
   149  	if k == nil {
   150  		return nil, nil
   151  	} else if (flags & uint32(bucketLeafFlag)) != 0 {
   152  		return k, nil
   153  	}
   154  	return k, v
   155  }
   156  
   157  // Delete removes the current key/value under the cursor from the bucket.
   158  // Delete fails if current key/value is a bucket or if the transaction is not writable.
   159  func (c *Cursor) Delete() error {
   160  	if c.bucket.tx.db == nil {
   161  		return ErrTxClosed
   162  	} else if !c.bucket.Writable() {
   163  		return ErrTxNotWritable
   164  	}
   165  
   166  	key, _, flags := c.keyValue()
   167  	// Return an error if current value is a bucket.
   168  	if (flags & bucketLeafFlag) != 0 {
   169  		return ErrIncompatibleValue
   170  	}
   171  	c.node().del(key)
   172  
   173  	return nil
   174  }
   175  
   176  // seek moves the cursor to a given key and returns it.
   177  // If the key does not exist then the next key is used.
   178  func (c *Cursor) seek(seek []byte) (key []byte, value []byte, flags uint32) {
   179  	_assert(c.bucket.tx.db != nil, "tx closed")
   180  
   181  	// Start from root page/node and traverse to correct page.
   182  	c.stack = c.stack[:0]
   183  	c.search(seek, c.bucket.root)
   184  	ref := &c.stack[len(c.stack)-1]
   185  
   186  	// If the cursor is pointing to the end of page/node then return nil.
   187  	if ref.index >= ref.count() {
   188  		return nil, nil, 0
   189  	}
   190  
   191  	// If this is a bucket then return a nil value.
   192  	return c.keyValue()
   193  }
   194  
   195  // first moves the cursor to the first leaf element under the last page in the stack.
   196  func (c *Cursor) first() {
   197  	for {
   198  		// Exit when we hit a leaf page.
   199  		var ref = &c.stack[len(c.stack)-1]
   200  		if ref.isLeaf() {
   201  			break
   202  		}
   203  
   204  		// Keep adding pages pointing to the first element to the stack.
   205  		var pgid pgid
   206  		if ref.node != nil {
   207  			pgid = ref.node.inodes[ref.index].pgid
   208  		} else {
   209  			pgid = ref.page.branchPageElement(uint16(ref.index)).pgid
   210  		}
   211  		p, n := c.bucket.pageNode(pgid)
   212  		c.stack = append(c.stack, elemRef{page: p, node: n, index: 0})
   213  	}
   214  }
   215  
   216  // last moves the cursor to the last leaf element under the last page in the stack.
   217  func (c *Cursor) last() {
   218  	for {
   219  		// Exit when we hit a leaf page.
   220  		ref := &c.stack[len(c.stack)-1]
   221  		if ref.isLeaf() {
   222  			break
   223  		}
   224  
   225  		// Keep adding pages pointing to the last element in the stack.
   226  		var pgid pgid
   227  		if ref.node != nil {
   228  			pgid = ref.node.inodes[ref.index].pgid
   229  		} else {
   230  			pgid = ref.page.branchPageElement(uint16(ref.index)).pgid
   231  		}
   232  		p, n := c.bucket.pageNode(pgid)
   233  
   234  		var nextRef = elemRef{page: p, node: n}
   235  		nextRef.index = nextRef.count() - 1
   236  		c.stack = append(c.stack, nextRef)
   237  	}
   238  }
   239  
   240  // next moves to the next leaf element and returns the key and value.
   241  // If the cursor is at the last leaf element then it stays there and returns nil.
   242  func (c *Cursor) next() (key []byte, value []byte, flags uint32) {
   243  	for {
   244  		// Attempt to move over one element until we're successful.
   245  		// Move up the stack as we hit the end of each page in our stack.
   246  		var i int
   247  		for i = len(c.stack) - 1; i >= 0; i-- {
   248  			elem := &c.stack[i]
   249  			if elem.index < elem.count()-1 {
   250  				elem.index++
   251  				break
   252  			}
   253  		}
   254  
   255  		// If we've hit the root page then stop and return. This will leave the
   256  		// cursor on the last element of the last page.
   257  		if i == -1 {
   258  			return nil, nil, 0
   259  		}
   260  
   261  		// Otherwise start from where we left off in the stack and find the
   262  		// first element of the first leaf page.
   263  		c.stack = c.stack[:i+1]
   264  		c.first()
   265  
   266  		// If this is an empty page then restart and move back up the stack.
   267  		if c.stack[len(c.stack)-1].count() == 0 {
   268  			continue
   269  		}
   270  
   271  		return c.keyValue()
   272  	}
   273  }
   274  
   275  // search recursively performs a binary search against a given page/node until it finds a given key.
   276  func (c *Cursor) search(key []byte, pgid pgid) {
   277  	p, n := c.bucket.pageNode(pgid)
   278  	if p != nil && (p.flags&(branchPageFlag|leafPageFlag)) == 0 {
   279  		panic(fmt.Sprintf("invalid page type: %d: %x", p.id, p.flags))
   280  	}
   281  	e := elemRef{page: p, node: n}
   282  	c.stack = append(c.stack, e)
   283  
   284  	// If we're on a leaf page/node then find the specific node.
   285  	if e.isLeaf() {
   286  		c.nsearch(key)
   287  		return
   288  	}
   289  
   290  	if n != nil {
   291  		c.searchNode(key, n)
   292  		return
   293  	}
   294  	c.searchPage(key, p)
   295  }
   296  
   297  func (c *Cursor) searchNode(key []byte, n *node) {
   298  	var exact bool
   299  	index := sort.Search(len(n.inodes), func(i int) bool {
   300  		// TODO(benbjohnson): Optimize this range search. It's a bit hacky right now.
   301  		// sort.Search() finds the lowest index where f() != -1 but we need the highest index.
   302  		ret := bytes.Compare(n.inodes[i].key, key)
   303  		if ret == 0 {
   304  			exact = true
   305  		}
   306  		return ret != -1
   307  	})
   308  	if !exact && index > 0 {
   309  		index--
   310  	}
   311  	c.stack[len(c.stack)-1].index = index
   312  
   313  	// Recursively search to the next page.
   314  	c.search(key, n.inodes[index].pgid)
   315  }
   316  
   317  func (c *Cursor) searchPage(key []byte, p *page) {
   318  	// Binary search for the correct range.
   319  	inodes := p.branchPageElements()
   320  
   321  	var exact bool
   322  	index := sort.Search(int(p.count), func(i int) bool {
   323  		// TODO(benbjohnson): Optimize this range search. It's a bit hacky right now.
   324  		// sort.Search() finds the lowest index where f() != -1 but we need the highest index.
   325  		ret := bytes.Compare(inodes[i].key(), key)
   326  		if ret == 0 {
   327  			exact = true
   328  		}
   329  		return ret != -1
   330  	})
   331  	if !exact && index > 0 {
   332  		index--
   333  	}
   334  	c.stack[len(c.stack)-1].index = index
   335  
   336  	// Recursively search to the next page.
   337  	c.search(key, inodes[index].pgid)
   338  }
   339  
   340  // nsearch searches the leaf node on the top of the stack for a key.
   341  func (c *Cursor) nsearch(key []byte) {
   342  	e := &c.stack[len(c.stack)-1]
   343  	p, n := e.page, e.node
   344  
   345  	// If we have a node then search its inodes.
   346  	if n != nil {
   347  		index := sort.Search(len(n.inodes), func(i int) bool {
   348  			return bytes.Compare(n.inodes[i].key, key) != -1
   349  		})
   350  		e.index = index
   351  		return
   352  	}
   353  
   354  	// If we have a page then search its leaf elements.
   355  	inodes := p.leafPageElements()
   356  	index := sort.Search(int(p.count), func(i int) bool {
   357  		return bytes.Compare(inodes[i].key(), key) != -1
   358  	})
   359  	e.index = index
   360  }
   361  
   362  // keyValue returns the key and value of the current leaf element.
   363  func (c *Cursor) keyValue() ([]byte, []byte, uint32) {
   364  	ref := &c.stack[len(c.stack)-1]
   365  	if ref.count() == 0 || ref.index >= ref.count() {
   366  		return nil, nil, 0
   367  	}
   368  
   369  	// Retrieve value from node.
   370  	if ref.node != nil {
   371  		inode := &ref.node.inodes[ref.index]
   372  		return inode.key, inode.value, inode.flags
   373  	}
   374  
   375  	// Or retrieve value from page.
   376  	elem := ref.page.leafPageElement(uint16(ref.index))
   377  	return elem.key(), elem.value(), elem.flags
   378  }
   379  
   380  // node returns the node that the cursor is currently positioned on.
   381  func (c *Cursor) node() *node {
   382  	_assert(len(c.stack) > 0, "accessing a node with a zero-length cursor stack")
   383  
   384  	// If the top of the stack is a leaf node then just return it.
   385  	if ref := &c.stack[len(c.stack)-1]; ref.node != nil && ref.isLeaf() {
   386  		return ref.node
   387  	}
   388  
   389  	// Start from root and traverse down the hierarchy.
   390  	var n = c.stack[0].node
   391  	if n == nil {
   392  		n = c.bucket.node(c.stack[0].page.id, nil)
   393  	}
   394  	for _, ref := range c.stack[:len(c.stack)-1] {
   395  		_assert(!n.isLeaf, "expected branch node")
   396  		n = n.childAt(int(ref.index))
   397  	}
   398  	_assert(n.isLeaf, "expected leaf node")
   399  	return n
   400  }
   401  
   402  // elemRef represents a reference to an element on a given page/node.
   403  type elemRef struct {
   404  	page  *page
   405  	node  *node
   406  	index int
   407  }
   408  
   409  // isLeaf returns whether the ref is pointing at a leaf page/node.
   410  func (r *elemRef) isLeaf() bool {
   411  	if r.node != nil {
   412  		return r.node.isLeaf
   413  	}
   414  	return (r.page.flags & leafPageFlag) != 0
   415  }
   416  
   417  // count returns the number of inodes or page elements.
   418  func (r *elemRef) count() int {
   419  	if r.node != nil {
   420  		return len(r.node.inodes)
   421  	}
   422  	return int(r.page.count)
   423  }