reset
----

batch commit
set a a
set b b
set c c
set d d
----
committed 4 keys

# Scan forward

combined-iter
seek-ge a
next
next
next
next
----
a: (a, .)
b: (b, .)
c: (c, .)
d: (d, .)
.

reopen
----

combined-iter
first
next
next
next
next
----
a: (a, .)
b: (b, .)
c: (c, .)
d: (d, .)
.

reopen enable-table-stats=false inject-errors=((ErrInjected (And Reads (PathMatch "*.sst") (OnIndex 4))))
----

combined-iter
first
first
next
next
next
next
----
err=pebble: backing file 000005 error: injected error
a: (a, .)
b: (b, .)
c: (c, .)
d: (d, .)
.

# Regression test for #2994.
#
# Previously, an error while loading an L0 sstable's range key block could
# result in an iterator that would always return the same error. Now, the IO is
# deferred to the first seek. If a seek encounters an IO error, re-seeking the
# iterator should re-attempt the failed IO operation, potentially succeeding if
# the IO error was transient.

define auto-compactions=off
L0
  a.SET.9:a
  rangekey:c-d:{(#0,RANGEKEYSET,@1,foo)}
  e@2.SET.2:e@2
----
L0.0:
  000004:[a#9,SET-e@2#2,SET]

layout filename=000004.sst
----
sstable
 ├── data  offset: 0  length: 38
 ├── index  offset: 43  length: 35
 ├── range-key  offset: 83  length: 29
 ├── properties  offset: 117  length: 573
 ├── meta-index  offset: 695  length: 57
 └── footer  offset: 757  length: 53

# Inject an error on the first `ReadAt` call on 000004.sst's range key block
# (which is at offset 83).

reopen auto-compactions=off enable-table-stats=false inject-errors=((ErrInjected (And (PathMatch "000004.sst") (OpFileReadAt 83) (OnIndex 0))))
----

combined-iter
first
first
----
err=injected error
a: (a, .)

# Test a scenario where an error occurs while the top-level Iterator is
# Prev()-ing backwards through many versions of the same user key. In the below
# test, reading the first block of the sstable (containing c.SET.13) fails. The
# iterator must surface the error. Previously a bug existed that would allow the
# iterator to mistakenly surface c.SET.12.

define auto-compactions=off block-size=1 snapshots=(10,11,12,13)
L1
  c.SET.13:c13
  c.SET.12:c12
  c.SET.11:c11
  c.SET.10:c10
  c.SET.9:c9
  c.SET.8:c8
  d.SET.9:d9
  e.SET.9:e9
----
L1:
  000004:[c#13,SET-e#9,SET]

layout filename=000004.sst
----
sstable
 ├── data  offset: 0  length: 23
 ├── data  offset: 28  length: 23
 ├── data  offset: 56  length: 23
 ├── data  offset: 84  length: 23
 ├── data  offset: 112  length: 22
 ├── data  offset: 139  length: 22
 ├── data  offset: 166  length: 22
 ├── index  offset: 193  length: 113
 ├── properties  offset: 311  length: 571
 ├── meta-index  offset: 887  length: 33
 └── footer  offset: 925  length: 53

reopen auto-compactions=off enable-table-stats=false inject-errors=((ErrInjected (And (PathMatch "000004.sst") (OpFileReadAt 0))))
----

combined-iter
last
prev
prev
----
e: (e9, .)
d: (d9, .)
err=injected error

reset
----

# Test the case of switching from reverse to forward iteration. During reverse
# iteration, the underlying iterator may be positioned at an internal key with a
# user key less than the current Key() [i.pos = iterPosPrev]. When switching
# back to the forward direction, the iterator must be stepped forward to a user
# key representing the current Key().
#
# Previously, if this step errored with the invariants tag enabled, a nil
# pointer panic was possible as an invariant assertion assumed that i.iterKey
# became non-nil (based on the knowledge that there must exist internal keys
# that represent the current Key()). This test exercises this case for both
# Next and NextPrefix.
#
# We set the cache-size to 1 so that no unused blocks are held in the cache, and
# we know the Next of the internal iterator will need to read from disk.

define auto-compactions=off cache-size=1 block-size=1
L1
  a.SET.1:a1
  b.SET.1:b1
  c.SET.1:c1
  d.SET.1:d1
  e.SET.1:e1
----
L1:
  000004:[a#1,SET-e#1,SET]

layout filename=000004.sst
----
sstable
 ├── data  offset: 0  length: 22
 ├── data  offset: 27  length: 22
 ├── data  offset: 54  length: 22
 ├── data  offset: 81  length: 22
 ├── data  offset: 108  length: 22
 ├── index  offset: 135  length: 84
 ├── properties  offset: 224  length: 495
 ├── meta-index  offset: 724  length: 33
 └── footer  offset: 762  length: 53

# NB: Block offset to key contained:
#  0 -> a, 27 -> b, 54 -> c, 81 -> d, 108 -> e
#
# After the last prev in the below cases, the top-level pebble.Iterator is
# positioned at c, but the underlying internal iterator is positioned at b.
# We set up error injection to error when loading the block corresponding to 'c'
# but only on the second tim the block is loaded.

reopen cache-size=1 auto-compactions=off enable-table-stats=false inject-errors=((ErrInjected (And (PathMatch "000004.sst") (OpFileReadAt 54) (OnIndex 1))))
----

combined-iter
last
prev
prev
next-prefix
----
e: (e1, .)
d: (d1, .)
c: (c1, .)
err=injected error

reopen cache-size=1 auto-compactions=off enable-table-stats=false inject-errors=((ErrInjected (And (PathMatch "000004.sst") (OpFileReadAt 54) (OnIndex 1))))
----

combined-iter
last
prev
prev
next
----
e: (e1, .)
d: (d1, .)
c: (c1, .)
err=injected error

# Test a simple MERGE scenario where an error occurs while the top-level
# Iterator is merging MERGE keys.

define auto-compactions=off block-size=1 snapshots=(1,2,3,4)
L1
    a.MERGE.1:a1
    a.MERGE.2:a2
    a.MERGE.3:a3
    a.MERGE.4:a4
----
L1:
  000004:[a#4,MERGE-a#1,MERGE]

layout filename=000004.sst
----
sstable
 ├── data  offset: 0  length: 22
 ├── data  offset: 27  length: 22
 ├── data  offset: 54  length: 22
 ├── data  offset: 81  length: 22
 ├── index  offset: 108  length: 71
 ├── properties  offset: 184  length: 570
 ├── meta-index  offset: 759  length: 33
 └── footer  offset: 797  length: 53


reopen auto-compactions=off enable-table-stats=false inject-errors=((ErrInjected (And (PathMatch "000004.sst") (OpFileReadAt 54))))
----

combined-iter
first
last
----
err=injected error
err=injected error
