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