github.com/cockroachdb/pebble@v0.0.0-20231214172447-ab4952c5f87b/internal/keyspan/interleaving_iter.go (about) 1 // Copyright 2021 The LevelDB-Go and Pebble Authors. All rights reserved. Use 2 // of this source code is governed by a BSD-style license that can be found in 3 // the LICENSE file. 4 5 package keyspan 6 7 import ( 8 "context" 9 "fmt" 10 11 "github.com/cockroachdb/errors" 12 "github.com/cockroachdb/pebble/internal/base" 13 "github.com/cockroachdb/pebble/internal/invariants" 14 ) 15 16 // A SpanMask may be used to configure an interleaving iterator to skip point 17 // keys that fall within the bounds of some spans. 18 type SpanMask interface { 19 // SpanChanged is invoked by an interleaving iterator whenever the current 20 // span changes. As the iterator passes into or out of a Span, it invokes 21 // SpanChanged, passing the new Span. When the iterator passes out of a 22 // span's boundaries and is no longer covered by any span, SpanChanged is 23 // invoked with a nil span. 24 // 25 // SpanChanged is invoked before SkipPoint, and callers may use SpanChanged 26 // to recalculate state used by SkipPoint for masking. 27 // 28 // SpanChanged may be invoked consecutively with identical spans under some 29 // circumstances, such as repeatedly absolutely positioning an iterator to 30 // positions covered by the same span, or while changing directions. 31 SpanChanged(*Span) 32 // SkipPoint is invoked by the interleaving iterator whenever the iterator 33 // encounters a point key covered by a Span. If SkipPoint returns true, the 34 // interleaving iterator skips the point key and all larger keys with the 35 // same prefix. This is used during range key iteration to skip over point 36 // keys 'masked' by range keys. 37 SkipPoint(userKey []byte) bool 38 } 39 40 // InterleavingIter combines an iterator over point keys with an iterator over 41 // key spans. 42 // 43 // Throughout Pebble, some keys apply at single discrete points within the user 44 // keyspace. Other keys apply over continuous spans of the user key space. 45 // Internally, iterators over point keys adhere to the base.InternalIterator 46 // interface, and iterators over spans adhere to the keyspan.FragmentIterator 47 // interface. The InterleavingIterator wraps a point iterator and span iterator, 48 // providing access to all the elements of both iterators. 49 // 50 // The InterleavingIterator implements the point base.InternalIterator 51 // interface. After any of the iterator's methods return a key, a caller may 52 // call Span to retrieve the span covering the returned key, if any. A span is 53 // considered to 'cover' a returned key if the span's [start, end) bounds 54 // include the key's user key. 55 // 56 // In addition to tracking the current covering span, InterleavingIter returns a 57 // special InternalKey at span start boundaries. Start boundaries are surfaced 58 // as a synthetic span marker: an InternalKey with the boundary as the user key, 59 // the infinite sequence number and a key kind selected from an arbitrary key 60 // the infinite sequence number and an arbitrary contained key's kind. Since 61 // which of the Span's key's kind is surfaced is undefined, the caller should 62 // not use the InternalKey's kind. The caller should only rely on the `Span` 63 // method for retrieving information about spanning keys. The interleaved 64 // synthetic keys have the infinite sequence number so that they're interleaved 65 // before any point keys with the same user key when iterating forward and after 66 // when iterating backward. 67 // 68 // Interleaving the synthetic start key boundaries at the maximum sequence 69 // number provides an opportunity for the higher-level, public Iterator to 70 // observe the Span, even if no live points keys exist within the boudns of the 71 // Span. 72 // 73 // When returning a synthetic marker key for a start boundary, InterleavingIter 74 // will truncate the span's start bound to the SeekGE or SeekPrefixGE search 75 // key. For example, a SeekGE("d") that finds a span [a, z) may return a 76 // synthetic span marker key `d#72057594037927935,21`. 77 // 78 // If bounds have been applied to the iterator through SetBounds, 79 // InterleavingIter will truncate the bounds of spans returned through Span to 80 // the set bounds. The bounds returned through Span are not truncated by a 81 // SeekGE or SeekPrefixGE search key. Consider, for example SetBounds('c', 'e'), 82 // with an iterator containing the Span [a,z): 83 // 84 // First() = `c#72057594037927935,21` Span() = [c,e) 85 // SeekGE('d') = `d#72057594037927935,21` Span() = [c,e) 86 // 87 // InterleavedIter does not interleave synthetic markers for spans that do not 88 // contain any keys. 89 // 90 // # SpanMask 91 // 92 // InterelavingIter takes a SpanMask parameter that may be used to configure the 93 // behavior of the iterator. See the documentation on the SpanMask type. 94 // 95 // All spans containing keys are exposed during iteration. 96 type InterleavingIter struct { 97 cmp base.Compare 98 comparer *base.Comparer 99 pointIter base.InternalIterator 100 keyspanIter FragmentIterator 101 mask SpanMask 102 103 // lower and upper hold the iteration bounds set through SetBounds. 104 lower, upper []byte 105 // keyBuf is used to copy SeekGE or SeekPrefixGE arguments when they're used 106 // to truncate a span. The byte slices backing a SeekGE/SeekPrefixGE search 107 // keys can come directly from the end user, so they're copied into keyBuf 108 // to ensure key stability. 109 keyBuf []byte 110 // nextPrefixBuf is used during SeekPrefixGE calls to store the truncated 111 // upper bound of the returned spans. SeekPrefixGE truncates the returned 112 // spans to an upper bound of the seeked prefix's immediate successor. 113 nextPrefixBuf []byte 114 pointKey *base.InternalKey 115 pointVal base.LazyValue 116 // err holds an iterator error from either pointIter or keyspanIter. It's 117 // reset to nil on seeks. An overview of error-handling mechanics: 118 // 119 // Whenever either pointIter or keyspanIter is respositioned and a nil 120 // key/span is returned, the code performing the positioning is responsible 121 // for checking the iterator's Error() value. This happens in savePoint and 122 // saveSpan[Forward,Backward]. 123 // 124 // Once i.err is non-nil, the computation of i.pos must set i.pos = 125 // posExhausted. This happens in compute[Smallest|Largest]Pos and 126 // [next|prev]Pos. Setting i.pos to posExhausted ensures we'll yield nil to 127 // the caller, which they'll interpret as a signal they must check Error(). 128 // 129 // INVARIANTS: 130 // i.err != nil => i.pos = posExhausted 131 err error 132 // prefix records the iterator's current prefix if the iterator is in prefix 133 // mode. During prefix mode, Pebble will truncate spans to the next prefix. 134 // If the iterator subsequently leaves prefix mode, the existing span cached 135 // in i.span must be invalidated because its bounds do not reflect the 136 // original span's true bounds. 137 prefix []byte 138 // span holds the span at the keyspanIter's current position. If the span is 139 // wholly contained within the iterator bounds, this span is directly 140 // returned to the iterator consumer through Span(). If either bound needed 141 // to be truncated to the iterator bounds, then truncated is set to true and 142 // Span() must return a pointer to truncatedSpan. 143 span *Span 144 // spanMarker holds the synthetic key that is returned when the iterator 145 // passes over a key span's start bound. 146 spanMarker base.InternalKey 147 // truncated indicates whether or not the span at the current position 148 // needed to be truncated. If it did, truncatedSpan holds the truncated 149 // span that should be returned. 150 truncatedSpan Span 151 truncated bool 152 153 // Keeping all of the bools/uint8s together reduces the sizeof the struct. 154 155 // pos encodes the current position of the iterator: exhausted, on the point 156 // key, on a keyspan start, or on a keyspan end. 157 pos interleavePos 158 // withinSpan indicates whether the iterator is currently positioned within 159 // the bounds of the current span (i.span). withinSpan must be updated 160 // whenever the interleaving iterator's position enters or exits the bounds 161 // of a span. 162 withinSpan bool 163 // spanMarkerTruncated is set by SeekGE/SeekPrefixGE calls that truncate a 164 // span's start bound marker to the search key. It's returned to false on 165 // the next repositioning of the keyspan iterator. 166 spanMarkerTruncated bool 167 // maskSpanChangedCalled records whether or not the last call to 168 // SpanMask.SpanChanged provided the current span (i.span) or not. 169 maskSpanChangedCalled bool 170 // dir indicates the direction of iteration: forward (+1) or backward (-1) 171 dir int8 172 } 173 174 // interleavePos indicates the iterator's current position. Note that both 175 // keyspanStart and keyspanEnd positions correspond to their user key boundaries 176 // with maximal sequence numbers. This means in the forward direction 177 // posKeyspanStart and posKeyspanEnd are always interleaved before a posPointKey 178 // with the same user key. 179 type interleavePos int8 180 181 const ( 182 posUninitialized interleavePos = iota 183 posExhausted 184 posPointKey 185 posKeyspanStart 186 posKeyspanEnd 187 ) 188 189 // Assert that *InterleavingIter implements the InternalIterator interface. 190 var _ base.InternalIterator = &InterleavingIter{} 191 192 // InterleavingIterOpts holds options configuring the behavior of a 193 // InterleavingIter. 194 type InterleavingIterOpts struct { 195 Mask SpanMask 196 LowerBound, UpperBound []byte 197 } 198 199 // Init initializes the InterleavingIter to interleave point keys from pointIter 200 // with key spans from keyspanIter. 201 // 202 // The point iterator must already have the bounds provided on opts. Init does 203 // not propagate the bounds down the iterator stack. 204 func (i *InterleavingIter) Init( 205 comparer *base.Comparer, 206 pointIter base.InternalIterator, 207 keyspanIter FragmentIterator, 208 opts InterleavingIterOpts, 209 ) { 210 *i = InterleavingIter{ 211 cmp: comparer.Compare, 212 comparer: comparer, 213 pointIter: pointIter, 214 keyspanIter: keyspanIter, 215 mask: opts.Mask, 216 lower: opts.LowerBound, 217 upper: opts.UpperBound, 218 } 219 } 220 221 // InitSeekGE may be called after Init but before any positioning method. 222 // InitSeekGE initializes the current position of the point iterator and then 223 // performs a SeekGE on the keyspan iterator using the provided key. InitSeekGE 224 // returns whichever point or keyspan key is smaller. After InitSeekGE, the 225 // iterator is positioned and may be repositioned using relative positioning 226 // methods. 227 // 228 // This method is used specifically for lazily constructing combined iterators. 229 // It allows for seeding the iterator with the current position of the point 230 // iterator. 231 func (i *InterleavingIter) InitSeekGE( 232 prefix, key []byte, pointKey *base.InternalKey, pointValue base.LazyValue, 233 ) (*base.InternalKey, base.LazyValue) { 234 i.dir = +1 235 i.clearMask() 236 i.prefix = prefix 237 i.savePoint(pointKey, pointValue) 238 // NB: This keyspanSeekGE call will truncate the span to the seek key if 239 // necessary. This truncation is important for cases where a switch to 240 // combined iteration is made during a user-initiated SeekGE. 241 i.keyspanSeekGE(key, prefix) 242 i.computeSmallestPos() 243 return i.yieldPosition(key, i.nextPos) 244 } 245 246 // InitSeekLT may be called after Init but before any positioning method. 247 // InitSeekLT initializes the current position of the point iterator and then 248 // performs a SeekLT on the keyspan iterator using the provided key. InitSeekLT 249 // returns whichever point or keyspan key is larger. After InitSeekLT, the 250 // iterator is positioned and may be repositioned using relative positioning 251 // methods. 252 // 253 // This method is used specifically for lazily constructing combined iterators. 254 // It allows for seeding the iterator with the current position of the point 255 // iterator. 256 func (i *InterleavingIter) InitSeekLT( 257 key []byte, pointKey *base.InternalKey, pointValue base.LazyValue, 258 ) (*base.InternalKey, base.LazyValue) { 259 i.dir = -1 260 i.clearMask() 261 i.savePoint(pointKey, pointValue) 262 i.keyspanSeekLT(key) 263 i.computeLargestPos() 264 return i.yieldPosition(i.lower, i.prevPos) 265 } 266 267 // SeekGE implements (base.InternalIterator).SeekGE. 268 // 269 // If there exists a span with a start key ≤ the first matching point key, 270 // SeekGE will return a synthetic span marker key for the span. If this span's 271 // start key is less than key, the returned marker will be truncated to key. 272 // Note that this search-key truncation of the marker's key is not applied to 273 // the span returned by Span. 274 // 275 // NB: In accordance with the base.InternalIterator contract: 276 // 277 // i.lower ≤ key 278 func (i *InterleavingIter) SeekGE( 279 key []byte, flags base.SeekGEFlags, 280 ) (*base.InternalKey, base.LazyValue) { 281 i.err = nil 282 i.clearMask() 283 i.disablePrefixMode() 284 i.savePoint(i.pointIter.SeekGE(key, flags)) 285 286 // We need to seek the keyspan iterator too. If the keyspan iterator was 287 // already positioned at a span, we might be able to avoid the seek if the 288 // seek key falls within the existing span's bounds. 289 if i.span != nil && i.cmp(key, i.span.End) < 0 && i.cmp(key, i.span.Start) >= 0 { 290 // We're seeking within the existing span's bounds. We still might need 291 // truncate the span to the iterator's bounds. 292 i.saveSpanForward(i.span) 293 i.savedKeyspan() 294 } else { 295 i.keyspanSeekGE(key, nil /* prefix */) 296 } 297 298 i.dir = +1 299 i.computeSmallestPos() 300 return i.yieldPosition(key, i.nextPos) 301 } 302 303 // SeekPrefixGE implements (base.InternalIterator).SeekPrefixGE. 304 // 305 // If there exists a span with a start key ≤ the first matching point key, 306 // SeekPrefixGE will return a synthetic span marker key for the span. If this 307 // span's start key is less than key, the returned marker will be truncated to 308 // key. Note that this search-key truncation of the marker's key is not applied 309 // to the span returned by Span. 310 // 311 // NB: In accordance with the base.InternalIterator contract: 312 // 313 // i.lower ≤ key 314 func (i *InterleavingIter) SeekPrefixGE( 315 prefix, key []byte, flags base.SeekGEFlags, 316 ) (*base.InternalKey, base.LazyValue) { 317 i.err = nil 318 i.clearMask() 319 i.prefix = prefix 320 i.savePoint(i.pointIter.SeekPrefixGE(prefix, key, flags)) 321 322 // We need to seek the keyspan iterator too. If the keyspan iterator was 323 // already positioned at a span, we might be able to avoid the seek if the 324 // entire seek prefix key falls within the existing span's bounds. 325 // 326 // During a SeekPrefixGE, Pebble defragments range keys within the bounds of 327 // the prefix. For example, a SeekPrefixGE('c', 'c@8') must defragment the 328 // any overlapping range keys within the bounds of [c,c\00). 329 // 330 // If range keys are fragmented within a prefix (eg, because a version 331 // within a prefix was chosen as an sstable boundary), then it's possible 332 // the seek key falls into the current i.span, but the current i.span does 333 // not wholly cover the seek prefix. 334 // 335 // For example, a SeekPrefixGE('d@5') may only defragment a range key to 336 // the bounds of [c@2,e). A subsequent SeekPrefixGE('c@0') must re-seek the 337 // keyspan iterator, because although 'c@0' is contained within [c@2,e), the 338 // full span of the prefix is not. 339 // 340 // Similarly, a SeekPrefixGE('a@3') may only defragment a range key to the 341 // bounds [a,c@8). A subsequent SeekPrefixGE('c@10') must re-seek the 342 // keyspan iterator, because although 'c@10' is contained within [a,c@8), 343 // the full span of the prefix is not. 344 seekKeyspanIter := true 345 if i.span != nil && i.cmp(prefix, i.span.Start) >= 0 { 346 if ei := i.comparer.Split(i.span.End); i.cmp(prefix, i.span.End[:ei]) < 0 { 347 // We're seeking within the existing span's bounds. We still might need 348 // truncate the span to the iterator's bounds. 349 i.saveSpanForward(i.span) 350 i.savedKeyspan() 351 seekKeyspanIter = false 352 } 353 } 354 if seekKeyspanIter { 355 i.keyspanSeekGE(key, prefix) 356 } 357 358 i.dir = +1 359 i.computeSmallestPos() 360 return i.yieldPosition(key, i.nextPos) 361 } 362 363 // SeekLT implements (base.InternalIterator).SeekLT. 364 func (i *InterleavingIter) SeekLT( 365 key []byte, flags base.SeekLTFlags, 366 ) (*base.InternalKey, base.LazyValue) { 367 i.err = nil 368 i.clearMask() 369 i.disablePrefixMode() 370 i.savePoint(i.pointIter.SeekLT(key, flags)) 371 372 // We need to seek the keyspan iterator too. If the keyspan iterator was 373 // already positioned at a span, we might be able to avoid the seek if the 374 // seek key falls within the existing span's bounds. 375 if i.span != nil && i.cmp(key, i.span.Start) > 0 && i.cmp(key, i.span.End) < 0 { 376 // We're seeking within the existing span's bounds. We still might need 377 // truncate the span to the iterator's bounds. 378 i.saveSpanBackward(i.span) 379 // The span's start key is still not guaranteed to be less than key, 380 // because of the bounds enforcement. Consider the following example: 381 // 382 // Bounds are set to [d,e). The user performs a SeekLT(d). The 383 // FragmentIterator.SeekLT lands on a span [b,f). This span has a start 384 // key less than d, as expected. Above, saveSpanBackward truncates the 385 // span to match the iterator's current bounds, modifying the span to 386 // [d,e), which does not overlap the search space of [-∞, d). 387 // 388 // This problem is a consequence of the SeekLT's exclusive search key 389 // and the fact that we don't perform bounds truncation at every leaf 390 // iterator. 391 if i.span != nil && i.truncated && i.cmp(i.truncatedSpan.Start, key) >= 0 { 392 i.span = nil 393 } 394 i.savedKeyspan() 395 } else { 396 i.keyspanSeekLT(key) 397 } 398 399 i.dir = -1 400 i.computeLargestPos() 401 return i.yieldPosition(i.lower, i.prevPos) 402 } 403 404 // First implements (base.InternalIterator).First. 405 func (i *InterleavingIter) First() (*base.InternalKey, base.LazyValue) { 406 i.err = nil 407 i.clearMask() 408 i.disablePrefixMode() 409 i.savePoint(i.pointIter.First()) 410 i.saveSpanForward(i.keyspanIter.First()) 411 i.savedKeyspan() 412 i.dir = +1 413 i.computeSmallestPos() 414 return i.yieldPosition(i.lower, i.nextPos) 415 } 416 417 // Last implements (base.InternalIterator).Last. 418 func (i *InterleavingIter) Last() (*base.InternalKey, base.LazyValue) { 419 i.err = nil 420 i.clearMask() 421 i.disablePrefixMode() 422 i.savePoint(i.pointIter.Last()) 423 i.saveSpanBackward(i.keyspanIter.Last()) 424 i.savedKeyspan() 425 i.dir = -1 426 i.computeLargestPos() 427 return i.yieldPosition(i.lower, i.prevPos) 428 } 429 430 // Next implements (base.InternalIterator).Next. 431 func (i *InterleavingIter) Next() (*base.InternalKey, base.LazyValue) { 432 if i.dir == -1 { 433 // Switching directions. 434 i.dir = +1 435 436 if i.mask != nil { 437 // Clear the mask while we reposition the point iterator. While 438 // switching directions, we may move the point iterator outside of 439 // i.span's bounds. 440 i.clearMask() 441 } 442 443 // When switching directions, iterator state corresponding to the 444 // current iterator position (as indicated by i.pos) is already correct. 445 // However any state that has yet to be interleaved describes a position 446 // behind the current iterator position and needs to be updated to 447 // describe the position ahead of the current iterator position. 448 switch i.pos { 449 case posExhausted: 450 // Nothing to do. The below nextPos call will move both the point 451 // key and span to their next positions and return 452 // MIN(point,s.Start). 453 case posPointKey: 454 // If we're currently on a point key, the below nextPos will 455 // correctly Next the point key iterator to the next point key. 456 // Do we need to move the span forwards? If the current span lies 457 // entirely behind the current key (!i.withinSpan), then we 458 // need to move it to the first span in the forward direction. 459 if !i.withinSpan { 460 i.saveSpanForward(i.keyspanIter.Next()) 461 i.savedKeyspan() 462 } 463 case posKeyspanStart: 464 i.withinSpan = true 465 // Since we're positioned on a Span, the pointIter is positioned 466 // entirely behind the current iterator position. Reposition it 467 // ahead of the current iterator position. 468 i.savePoint(i.pointIter.Next()) 469 case posKeyspanEnd: 470 // Since we're positioned on a Span, the pointIter is positioned 471 // entirely behind of the current iterator position. Reposition it 472 // ahead the current iterator position. 473 i.savePoint(i.pointIter.Next()) 474 } 475 // Fallthrough to calling i.nextPos. 476 } 477 i.nextPos() 478 return i.yieldPosition(i.lower, i.nextPos) 479 } 480 481 // NextPrefix implements (base.InternalIterator).NextPrefix. 482 func (i *InterleavingIter) NextPrefix(succKey []byte) (*base.InternalKey, base.LazyValue) { 483 if i.dir == -1 { 484 panic("pebble: cannot switch directions with NextPrefix") 485 } 486 487 switch i.pos { 488 case posExhausted: 489 return nil, base.LazyValue{} 490 case posPointKey: 491 i.savePoint(i.pointIter.NextPrefix(succKey)) 492 if i.withinSpan { 493 if i.pointKey == nil || i.cmp(i.span.End, i.pointKey.UserKey) <= 0 { 494 i.pos = posKeyspanEnd 495 } else { 496 i.pos = posPointKey 497 } 498 } else { 499 i.computeSmallestPos() 500 } 501 case posKeyspanStart, posKeyspanEnd: 502 i.nextPos() 503 } 504 return i.yieldPosition(i.lower, i.nextPos) 505 } 506 507 // Prev implements (base.InternalIterator).Prev. 508 func (i *InterleavingIter) Prev() (*base.InternalKey, base.LazyValue) { 509 if i.dir == +1 { 510 // Switching directions. 511 i.dir = -1 512 513 if i.mask != nil { 514 // Clear the mask while we reposition the point iterator. While 515 // switching directions, we may move the point iterator outside of 516 // i.span's bounds. 517 i.clearMask() 518 } 519 520 // When switching directions, iterator state corresponding to the 521 // current iterator position (as indicated by i.pos) is already correct. 522 // However any state that has yet to be interleaved describes a position 523 // ahead of the current iterator position and needs to be updated to 524 // describe the position behind the current iterator position. 525 switch i.pos { 526 case posExhausted: 527 // Nothing to do. The below prevPos call will move both the point 528 // key and span to previous positions and return MAX(point, s.End). 529 case posPointKey: 530 // If we're currently on a point key, the point iterator is in the 531 // right place and the call to prevPos will correctly Prev the point 532 // key iterator to the previous point key. Do we need to move the 533 // span backwards? If the current span lies entirely ahead of the 534 // current key (!i.withinSpan), then we need to move it to the first 535 // span in the reverse direction. 536 if !i.withinSpan { 537 i.saveSpanBackward(i.keyspanIter.Prev()) 538 i.savedKeyspan() 539 } 540 case posKeyspanStart: 541 // Since we're positioned on a Span, the pointIter is positioned 542 // entirely ahead of the current iterator position. Reposition it 543 // behind the current iterator position. 544 i.savePoint(i.pointIter.Prev()) 545 // Without considering truncation of spans to seek keys, the keyspan 546 // iterator is already in the right place. But consider span [a, z) 547 // and this sequence of iterator calls: 548 // 549 // SeekGE('c') = c.RANGEKEYSET#72057594037927935 550 // Prev() = a.RANGEKEYSET#72057594037927935 551 // 552 // If the current span's start key was last surfaced truncated due 553 // to a SeekGE or SeekPrefixGE call, then it's still relevant in the 554 // reverse direction with an untruncated start key. 555 if i.spanMarkerTruncated { 556 // When we fallthrough to calling prevPos, we want to move to 557 // MAX(point, span.Start). We cheat here by claiming we're 558 // currently on the end boundary, so that we'll move on to the 559 // untruncated start key if necessary. 560 i.pos = posKeyspanEnd 561 } 562 case posKeyspanEnd: 563 // Since we're positioned on a Span, the pointIter is positioned 564 // entirely ahead of the current iterator position. Reposition it 565 // behind the current iterator position. 566 i.savePoint(i.pointIter.Prev()) 567 } 568 569 if i.spanMarkerTruncated { 570 // Save the keyspan again to clear truncation. 571 i.savedKeyspan() 572 } 573 // Fallthrough to calling i.prevPos. 574 } 575 i.prevPos() 576 return i.yieldPosition(i.lower, i.prevPos) 577 } 578 579 // computeSmallestPos sets i.{pos,withinSpan} to: 580 // 581 // MIN(i.pointKey, i.span.Start) 582 func (i *InterleavingIter) computeSmallestPos() { 583 if i.err == nil { 584 if i.span != nil && (i.pointKey == nil || i.cmp(i.startKey(), i.pointKey.UserKey) <= 0) { 585 i.withinSpan = true 586 i.pos = posKeyspanStart 587 return 588 } 589 i.withinSpan = false 590 if i.pointKey != nil { 591 i.pos = posPointKey 592 return 593 } 594 } 595 i.pos = posExhausted 596 } 597 598 // computeLargestPos sets i.{pos,withinSpan} to: 599 // 600 // MAX(i.pointKey, i.span.End) 601 func (i *InterleavingIter) computeLargestPos() { 602 if i.err == nil { 603 if i.span != nil && (i.pointKey == nil || i.cmp(i.span.End, i.pointKey.UserKey) > 0) { 604 i.withinSpan = true 605 i.pos = posKeyspanEnd 606 return 607 } 608 i.withinSpan = false 609 if i.pointKey != nil { 610 i.pos = posPointKey 611 return 612 } 613 } 614 i.pos = posExhausted 615 } 616 617 // nextPos advances the iterator one position in the forward direction. 618 func (i *InterleavingIter) nextPos() { 619 if invariants.Enabled { 620 defer func() { 621 if i.err != nil && i.pos != posExhausted { 622 panic(errors.AssertionFailedf("iterator has accumulated error but i.pos = %d", i.pos)) 623 } 624 }() 625 } 626 // NB: If i.err != nil or any of the positioning methods performed in this 627 // function result in i.err != nil, we must set i.pos = posExhausted. We 628 // perform this check explicitly here, but if any of the branches below 629 // advance either iterator, they must also check i.err and set posExhausted 630 // if necessary. 631 if i.err != nil { 632 i.pos = posExhausted 633 return 634 } 635 636 switch i.pos { 637 case posExhausted: 638 i.savePoint(i.pointIter.Next()) 639 i.saveSpanForward(i.keyspanIter.Next()) 640 i.savedKeyspan() 641 i.computeSmallestPos() 642 case posPointKey: 643 i.savePoint(i.pointIter.Next()) 644 if i.err != nil { 645 i.pos = posExhausted 646 return 647 } 648 // If we're not currently within the span, we want to chose the 649 // MIN(pointKey,span.Start), which is exactly the calculation performed 650 // by computeSmallestPos. 651 if !i.withinSpan { 652 i.computeSmallestPos() 653 return 654 } 655 // i.withinSpan=true 656 // Since we previously were within the span, we want to choose the 657 // MIN(pointKey,span.End). 658 switch { 659 case i.span == nil: 660 panic("i.withinSpan=true and i.span=nil") 661 case i.pointKey == nil: 662 // Since i.withinSpan=true, we step onto the end boundary of the 663 // keyspan. 664 i.pos = posKeyspanEnd 665 default: 666 // i.withinSpan && i.pointKey != nil && i.span != nil 667 if i.cmp(i.span.End, i.pointKey.UserKey) <= 0 { 668 i.pos = posKeyspanEnd 669 } else { 670 i.pos = posPointKey 671 } 672 } 673 case posKeyspanStart: 674 // Either a point key or the span's end key comes next. 675 if i.pointKey != nil && i.cmp(i.pointKey.UserKey, i.span.End) < 0 { 676 i.pos = posPointKey 677 } else { 678 i.pos = posKeyspanEnd 679 } 680 case posKeyspanEnd: 681 i.saveSpanForward(i.keyspanIter.Next()) 682 i.savedKeyspan() 683 i.computeSmallestPos() 684 default: 685 panic(fmt.Sprintf("unexpected pos=%d", i.pos)) 686 } 687 } 688 689 // prevPos advances the iterator one position in the reverse direction. 690 func (i *InterleavingIter) prevPos() { 691 if invariants.Enabled { 692 defer func() { 693 if i.err != nil && i.pos != posExhausted { 694 panic(errors.AssertionFailedf("iterator has accumulated error but i.pos = %d", i.pos)) 695 } 696 }() 697 } 698 // NB: If i.err != nil or any of the positioning methods performed in this 699 // function result in i.err != nil, we must set i.pos = posExhausted. We 700 // perform this check explicitly here, but if any of the branches below 701 // advance either iterator, they must also check i.err and set posExhausted 702 // if necessary. 703 if i.err != nil { 704 i.pos = posExhausted 705 return 706 } 707 708 switch i.pos { 709 case posExhausted: 710 i.savePoint(i.pointIter.Prev()) 711 i.saveSpanBackward(i.keyspanIter.Prev()) 712 i.savedKeyspan() 713 i.computeLargestPos() 714 case posPointKey: 715 i.savePoint(i.pointIter.Prev()) 716 if i.err != nil { 717 i.pos = posExhausted 718 return 719 } 720 // If we're not currently covered by the span, we want to chose the 721 // MAX(pointKey,span.End), which is exactly the calculation performed 722 // by computeLargestPos. 723 if !i.withinSpan { 724 i.computeLargestPos() 725 return 726 } 727 switch { 728 case i.span == nil: 729 panic("withinSpan=true, but i.span == nil") 730 case i.pointKey == nil: 731 i.pos = posKeyspanEnd 732 default: 733 // i.withinSpan && i.pointKey != nil && i.span != nil 734 if i.cmp(i.span.Start, i.pointKey.UserKey) > 0 { 735 i.pos = posKeyspanStart 736 } else { 737 i.pos = posPointKey 738 } 739 } 740 case posKeyspanStart: 741 i.saveSpanBackward(i.keyspanIter.Prev()) 742 i.savedKeyspan() 743 i.computeLargestPos() 744 case posKeyspanEnd: 745 // Either a point key or the span's start key is previous. 746 if i.pointKey != nil && i.cmp(i.pointKey.UserKey, i.span.Start) >= 0 { 747 i.pos = posPointKey 748 } else { 749 i.pos = posKeyspanStart 750 } 751 default: 752 panic(fmt.Sprintf("unexpected pos=%d", i.pos)) 753 } 754 } 755 756 func (i *InterleavingIter) yieldPosition( 757 lowerBound []byte, advance func(), 758 ) (*base.InternalKey, base.LazyValue) { 759 // This loop returns the first visible position in the current iteration 760 // direction. Some positions are not visible and skipped. For example, if 761 // masking is enabled and the iterator is positioned over a masked point 762 // key, this loop skips the position. If a span's start key should be 763 // interleaved next, but the span is empty, the loop continues to the next 764 // key. Currently, span end keys are also always skipped, and are used only 765 // for maintaining internal state. 766 for { 767 switch i.pos { 768 case posExhausted: 769 return i.yieldNil() 770 case posPointKey: 771 if i.pointKey == nil { 772 panic("i.pointKey is nil") 773 } 774 775 if i.mask != nil { 776 i.maybeUpdateMask() 777 if i.withinSpan && i.mask.SkipPoint(i.pointKey.UserKey) { 778 // The span covers the point key. If a SkipPoint hook is 779 // configured, ask it if we should skip this point key. 780 if i.prefix != nil { 781 // During prefix-iteration node, once a point is masked, 782 // all subsequent keys with the same prefix must also be 783 // masked according to the key ordering. We can stop and 784 // return nil. 785 // 786 // NB: The above is not just an optimization. During 787 // prefix-iteration mode, the internal iterator contract 788 // prohibits us from Next-ing beyond the first key 789 // beyond the iteration prefix. If we didn't already 790 // stop early, we would need to check if this masked 791 // point is already beyond the prefix. 792 return i.yieldNil() 793 } 794 // TODO(jackson): If we thread a base.Comparer through to 795 // InterleavingIter so that we have access to 796 // ImmediateSuccessor, we could use NextPrefix. We'd need to 797 // tweak the SpanMask interface slightly. 798 799 // Advance beyond the masked point key. 800 advance() 801 continue 802 } 803 } 804 return i.yieldPointKey() 805 case posKeyspanEnd: 806 // Don't interleave end keys; just advance. 807 advance() 808 continue 809 case posKeyspanStart: 810 // Don't interleave an empty span. 811 if i.span.Empty() { 812 advance() 813 continue 814 } 815 return i.yieldSyntheticSpanMarker(lowerBound) 816 default: 817 panic(fmt.Sprintf("unexpected interleavePos=%d", i.pos)) 818 } 819 } 820 } 821 822 // keyspanSeekGE seeks the keyspan iterator to the first span covering a key ≥ k. 823 func (i *InterleavingIter) keyspanSeekGE(k []byte, prefix []byte) { 824 i.saveSpanForward(i.keyspanIter.SeekGE(k)) 825 i.savedKeyspan() 826 } 827 828 // keyspanSeekLT seeks the keyspan iterator to the last span covering a key < k. 829 func (i *InterleavingIter) keyspanSeekLT(k []byte) { 830 i.saveSpanBackward(i.keyspanIter.SeekLT(k)) 831 // The current span's start key is not guaranteed to be less than key, 832 // because of the bounds enforcement. Consider the following example: 833 // 834 // Bounds are set to [d,e). The user performs a SeekLT(d). The 835 // FragmentIterator.SeekLT lands on a span [b,f). This span has a start key 836 // less than d, as expected. Above, saveSpanBackward truncates the span to 837 // match the iterator's current bounds, modifying the span to [d,e), which 838 // does not overlap the search space of [-∞, d). 839 // 840 // This problem is a consequence of the SeekLT's exclusive search key and 841 // the fact that we don't perform bounds truncation at every leaf iterator. 842 if i.span != nil && i.truncated && i.cmp(i.truncatedSpan.Start, k) >= 0 { 843 i.span = nil 844 } 845 i.savedKeyspan() 846 } 847 848 func (i *InterleavingIter) saveSpanForward(span *Span) { 849 i.span = span 850 i.truncated = false 851 i.truncatedSpan = Span{} 852 if i.span == nil { 853 i.err = firstError(i.err, i.keyspanIter.Error()) 854 return 855 } 856 if invariants.Enabled { 857 if err := i.keyspanIter.Error(); err != nil { 858 panic(errors.WithSecondaryError( 859 errors.AssertionFailedf("pebble: %T keyspan iterator returned non-nil span %s while iter has error", i.keyspanIter, i.span), 860 err)) 861 } 862 } 863 // Check the upper bound if we have one. 864 if i.upper != nil && i.cmp(i.span.Start, i.upper) >= 0 { 865 i.span = nil 866 return 867 } 868 869 // TODO(jackson): The key comparisons below truncate bounds whenever the 870 // keyspan iterator is repositioned. We could perform this lazily, and do it 871 // the first time the user actually asks for this span's bounds in 872 // SpanBounds. This would reduce work in the case where there's no span 873 // covering the point and the keyspan iterator is non-empty. 874 875 // NB: These truncations don't require setting `keyspanMarkerTruncated`: 876 // That flag only applies to truncated span marker keys. 877 if i.lower != nil && i.cmp(i.span.Start, i.lower) < 0 { 878 i.truncated = true 879 i.truncatedSpan = *i.span 880 i.truncatedSpan.Start = i.lower 881 } 882 if i.upper != nil && i.cmp(i.upper, i.span.End) < 0 { 883 if !i.truncated { 884 i.truncated = true 885 i.truncatedSpan = *i.span 886 } 887 i.truncatedSpan.End = i.upper 888 } 889 // If this is a part of a SeekPrefixGE call, we may also need to truncate to 890 // the prefix's bounds. 891 if i.prefix != nil { 892 if !i.truncated { 893 i.truncated = true 894 i.truncatedSpan = *i.span 895 } 896 if i.cmp(i.prefix, i.truncatedSpan.Start) > 0 { 897 i.truncatedSpan.Start = i.prefix 898 } 899 i.nextPrefixBuf = i.comparer.ImmediateSuccessor(i.nextPrefixBuf[:0], i.prefix) 900 if i.truncated && i.cmp(i.nextPrefixBuf, i.truncatedSpan.End) < 0 { 901 i.truncatedSpan.End = i.nextPrefixBuf 902 } 903 } 904 905 if i.truncated && i.comparer.Equal(i.truncatedSpan.Start, i.truncatedSpan.End) { 906 i.span = nil 907 } 908 } 909 910 func (i *InterleavingIter) saveSpanBackward(span *Span) { 911 i.span = span 912 i.truncated = false 913 i.truncatedSpan = Span{} 914 if i.span == nil { 915 i.err = firstError(i.err, i.keyspanIter.Error()) 916 return 917 } 918 if invariants.Enabled { 919 if err := i.keyspanIter.Error(); err != nil { 920 panic(errors.WithSecondaryError( 921 errors.AssertionFailedf("pebble: %T keyspan iterator returned non-nil span %s while iter has error", i.keyspanIter, i.span), 922 err)) 923 } 924 } 925 926 // Check the lower bound if we have one. 927 if i.lower != nil && i.cmp(i.span.End, i.lower) <= 0 { 928 i.span = nil 929 return 930 } 931 932 // TODO(jackson): The key comparisons below truncate bounds whenever the 933 // keyspan iterator is repositioned. We could perform this lazily, and do it 934 // the first time the user actually asks for this span's bounds in 935 // SpanBounds. This would reduce work in the case where there's no span 936 // covering the point and the keyspan iterator is non-empty. 937 938 // NB: These truncations don't require setting `keyspanMarkerTruncated`: 939 // That flag only applies to truncated span marker keys. 940 if i.lower != nil && i.cmp(i.span.Start, i.lower) < 0 { 941 i.truncated = true 942 i.truncatedSpan = *i.span 943 i.truncatedSpan.Start = i.lower 944 } 945 if i.upper != nil && i.cmp(i.upper, i.span.End) < 0 { 946 if !i.truncated { 947 i.truncated = true 948 i.truncatedSpan = *i.span 949 } 950 i.truncatedSpan.End = i.upper 951 } 952 if i.truncated && i.comparer.Equal(i.truncatedSpan.Start, i.truncatedSpan.End) { 953 i.span = nil 954 } 955 } 956 957 func (i *InterleavingIter) yieldNil() (*base.InternalKey, base.LazyValue) { 958 i.withinSpan = false 959 i.clearMask() 960 return i.verify(nil, base.LazyValue{}) 961 } 962 963 func (i *InterleavingIter) yieldPointKey() (*base.InternalKey, base.LazyValue) { 964 return i.verify(i.pointKey, i.pointVal) 965 } 966 967 func (i *InterleavingIter) yieldSyntheticSpanMarker( 968 lowerBound []byte, 969 ) (*base.InternalKey, base.LazyValue) { 970 i.spanMarker.UserKey = i.startKey() 971 i.spanMarker.Trailer = base.MakeTrailer(base.InternalKeySeqNumMax, i.span.Keys[0].Kind()) 972 973 // Truncate the key we return to our lower bound if we have one. Note that 974 // we use the lowerBound function parameter, not i.lower. The lowerBound 975 // argument is guaranteed to be ≥ i.lower. It may be equal to the SetBounds 976 // lower bound, or it could come from a SeekGE or SeekPrefixGE search key. 977 if lowerBound != nil && i.cmp(lowerBound, i.startKey()) > 0 { 978 // Truncating to the lower bound may violate the upper bound if 979 // lowerBound == i.upper. For example, a SeekGE(k) uses k as a lower 980 // bound for truncating a span. The span a-z will be truncated to [k, 981 // z). If i.upper == k, we'd mistakenly try to return a span [k, k), an 982 // invariant violation. 983 if i.comparer.Equal(lowerBound, i.upper) { 984 return i.yieldNil() 985 } 986 987 // If the lowerBound argument came from a SeekGE or SeekPrefixGE 988 // call, and it may be backed by a user-provided byte slice that is not 989 // guaranteed to be stable. 990 // 991 // If the lowerBound argument is the lower bound set by SetBounds, 992 // Pebble owns the slice's memory. However, consider two successive 993 // calls to SetBounds(). The second may overwrite the lower bound. 994 // Although the external contract requires a seek after a SetBounds, 995 // Pebble's tests don't always. For this reason and to simplify 996 // reasoning around lifetimes, always copy the bound into keyBuf when 997 // truncating. 998 i.keyBuf = append(i.keyBuf[:0], lowerBound...) 999 i.spanMarker.UserKey = i.keyBuf 1000 i.spanMarkerTruncated = true 1001 } 1002 i.maybeUpdateMask() 1003 return i.verify(&i.spanMarker, base.LazyValue{}) 1004 } 1005 1006 func (i *InterleavingIter) disablePrefixMode() { 1007 if i.prefix != nil { 1008 i.prefix = nil 1009 // Clear the existing span. It may not hold the true end bound of the 1010 // underlying span. 1011 i.span = nil 1012 } 1013 } 1014 1015 func (i *InterleavingIter) verify( 1016 k *base.InternalKey, v base.LazyValue, 1017 ) (*base.InternalKey, base.LazyValue) { 1018 // Wrap the entire function body in the invariants build tag, so that 1019 // production builds elide this entire function. 1020 if invariants.Enabled { 1021 switch { 1022 case i.dir == -1 && i.spanMarkerTruncated: 1023 panic("pebble: invariant violation: truncated span key in reverse iteration") 1024 case k != nil && i.lower != nil && i.cmp(k.UserKey, i.lower) < 0: 1025 panic("pebble: invariant violation: key < lower bound") 1026 case k != nil && i.upper != nil && i.cmp(k.UserKey, i.upper) >= 0: 1027 panic("pebble: invariant violation: key ≥ upper bound") 1028 case i.err != nil && k != nil: 1029 panic("pebble: invariant violation: accumulated error swallowed") 1030 case i.err == nil && i.pointIter.Error() != nil: 1031 panic("pebble: invariant violation: pointIter swallowed") 1032 case i.err == nil && i.keyspanIter.Error() != nil: 1033 panic("pebble: invariant violation: keyspanIter error swallowed") 1034 } 1035 } 1036 return k, v 1037 } 1038 1039 func (i *InterleavingIter) savedKeyspan() { 1040 i.spanMarkerTruncated = false 1041 i.maskSpanChangedCalled = false 1042 } 1043 1044 // updateMask updates the current mask, if a mask is configured and the mask 1045 // hasn't been updated with the current keyspan yet. 1046 func (i *InterleavingIter) maybeUpdateMask() { 1047 switch { 1048 case i.mask == nil, i.maskSpanChangedCalled: 1049 return 1050 case !i.withinSpan || i.span.Empty(): 1051 i.clearMask() 1052 case i.truncated: 1053 i.mask.SpanChanged(&i.truncatedSpan) 1054 i.maskSpanChangedCalled = true 1055 default: 1056 i.mask.SpanChanged(i.span) 1057 i.maskSpanChangedCalled = true 1058 } 1059 } 1060 1061 // clearMask clears the current mask, if a mask is configured and no mask should 1062 // be active. 1063 func (i *InterleavingIter) clearMask() { 1064 if i.mask != nil { 1065 i.maskSpanChangedCalled = false 1066 i.mask.SpanChanged(nil) 1067 } 1068 } 1069 1070 func (i *InterleavingIter) startKey() []byte { 1071 if i.truncated { 1072 return i.truncatedSpan.Start 1073 } 1074 return i.span.Start 1075 } 1076 1077 func (i *InterleavingIter) savePoint(key *base.InternalKey, value base.LazyValue) { 1078 i.pointKey, i.pointVal = key, value 1079 if key == nil { 1080 i.err = firstError(i.err, i.pointIter.Error()) 1081 } 1082 if invariants.Enabled { 1083 if err := i.pointIter.Error(); key != nil && err != nil { 1084 panic(errors.WithSecondaryError( 1085 errors.AssertionFailedf("pebble: %T point iterator returned non-nil key %q while iter has error", i.pointIter, key), 1086 err)) 1087 } 1088 } 1089 } 1090 1091 // Span returns the span covering the last key returned, if any. A span key is 1092 // considered to 'cover' a key if the key falls within the span's user key 1093 // bounds. The returned span is owned by the InterleavingIter. The caller is 1094 // responsible for copying if stability is required. 1095 // 1096 // Span will never return an invalid or empty span. 1097 func (i *InterleavingIter) Span() *Span { 1098 if !i.withinSpan || len(i.span.Keys) == 0 { 1099 return nil 1100 } else if i.truncated { 1101 return &i.truncatedSpan 1102 } 1103 return i.span 1104 } 1105 1106 // SetBounds implements (base.InternalIterator).SetBounds. 1107 func (i *InterleavingIter) SetBounds(lower, upper []byte) { 1108 i.lower, i.upper = lower, upper 1109 i.pointIter.SetBounds(lower, upper) 1110 i.Invalidate() 1111 } 1112 1113 // SetContext implements (base.InternalIterator).SetContext. 1114 func (i *InterleavingIter) SetContext(ctx context.Context) { 1115 i.pointIter.SetContext(ctx) 1116 } 1117 1118 // Invalidate invalidates the interleaving iterator's current position, clearing 1119 // its state. This prevents optimizations such as reusing the current span on 1120 // seek. 1121 func (i *InterleavingIter) Invalidate() { 1122 i.span = nil 1123 i.pointKey = nil 1124 i.pointVal = base.LazyValue{} 1125 } 1126 1127 // Error implements (base.InternalIterator).Error. 1128 func (i *InterleavingIter) Error() error { 1129 return i.err 1130 } 1131 1132 // Close implements (base.InternalIterator).Close. 1133 func (i *InterleavingIter) Close() error { 1134 perr := i.pointIter.Close() 1135 rerr := i.keyspanIter.Close() 1136 return firstError(perr, rerr) 1137 } 1138 1139 // String implements (base.InternalIterator).String. 1140 func (i *InterleavingIter) String() string { 1141 return fmt.Sprintf("keyspan-interleaving(%q)", i.pointIter.String()) 1142 } 1143 1144 func firstError(err0, err1 error) error { 1145 if err0 != nil { 1146 return err0 1147 } 1148 return err1 1149 }