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 }