define
a.SET.1:b
----

iter
first
next
----
a#1,SET:b
.

define
a.SET.2:c
a.SET.1:b
----

iter
first
next
----
a#2,SET:c
.

iter snapshots=0
first
next
----
a#2,SET:c
.

iter snapshots=1
first
next
----
a#2,SET:c
.

iter snapshots=2
first
next
next
----
a#2,SET:c
a#1,SET:b
.

define
a.DEL.2:
a.SET.1:b
----

iter
first
next
----
a#2,DEL:
.

iter elide-tombstones=true
first
----
.

iter elide-tombstones=true snapshots=2
first
next
next
----
a#2,DEL:
a#1,SET:b
.

iter elide-tombstones=true snapshots=1
first
next
----
a#2,DEL:
.

define
a.DEL.2:
a.SET.1:b
b.SET.3:c
----

iter
first
next
next
----
a#2,DEL:
b#3,SET:c
.

iter snapshots=1
first
next
next
----
a#2,DEL:
b#3,SET:c
.

iter snapshots=2
first
next
next
next
----
a#2,DEL:
a#1,SET:b
b#3,SET:c
.

define
a.SET.1:a
b.SET.2:b
c.SET.3:c
----

iter
first
next
next
next
----
a#1,SET:a
b#2,SET:b
c#3,SET:c
.

define
a.MERGE.3:d
a.MERGE.2:c
a.SET.1:b
b.MERGE.2:b
b.MERGE.1:a
----

iter
first
next
next
----
a#3,SET:bcd[base]
b#2,MERGE:ab
.

iter snapshots=3 print-snapshot-pinned print-force-obsolete
first
next
next
next
----
a#3,MERGE:d (not pinned) (not force obsolete)
a#2,SET:bc[base] (pinned) (not force obsolete)
b#2,MERGE:ab (not pinned) (not force obsolete)
.

define
a.SET.9:b
a.DEL.8:
a.SET.7:d
a.DEL.6:
a.SET.5:f
----

iter
first
next
----
a#9,SETWITHDEL:b
.

iter snapshots=6
first
next
next
----
a#9,SETWITHDEL:b
a#5,SET:f
.

iter snapshots=7
first
next
next
----
a#9,SETWITHDEL:b
a#6,DEL:
.

iter snapshots=8
first
next
next
----
a#9,SETWITHDEL:b
a#7,SETWITHDEL:d
.

iter snapshots=9
first
next
next
----
a#9,SET:b
a#8,DEL:
.

iter snapshots=10
first
next
----
a#9,SETWITHDEL:b
.

iter snapshots=(5,6,7,8,9)
first
next
next
next
next
next
----
a#9,SET:b
a#8,DEL:
a#7,SET:d
a#6,DEL:
a#5,SET:f
.

define
a.INVALID.2:b
a.SET.1:c
----

iter
first
----
err=invalid internal key kind: INVALID

define
a.SET.2:b
a.INVALID.1:c
----

iter
first
----
err=invalid internal key kind: INVALID

define
a.MERGE.2:b
a.INVALID.1:c
----

iter
first
----
err=invalid internal key kind: INVALID

define
a.INVALID.2:c
a.RANGEDEL.1:d
----

iter
first
next
----
a#inf,RANGEDEL:; Span() = a-d:{(#1,RANGEDEL)}
err=invalid internal key kind: INVALID

define
a.MERGE.2:b
a.MERGE.1:c
a.MERGE.0:d
----

iter snapshots=(1,2) print-snapshot-pinned print-force-obsolete
first
next
next
next
----
a#2,MERGE:b (not pinned) (not force obsolete)
a#1,MERGE:c (pinned) (not force obsolete)
a#0,MERGE:d (pinned) (not force obsolete)
.

define
a.SET.2:b
a.RANGEDEL.1:c
b.RANGEDEL.4:d
b.SET.2:e
c.SET.3:f
----

iter
first
next
next
next
next
----
a#inf,RANGEDEL:; Span() = a-b:{(#1,RANGEDEL)}
a#2,SET:b
b#inf,RANGEDEL:; Span() = b-c:{(#4,RANGEDEL)}
c#inf,RANGEDEL:; Span() = c-d:{(#4,RANGEDEL)}
.

iter snapshots=2
first
next
next
next
next
----
a#inf,RANGEDEL:; Span() = a-b:{(#1,RANGEDEL)}
a#2,SET:b
b#inf,RANGEDEL:; Span() = b-c:{(#4,RANGEDEL) (#1,RANGEDEL)}
c#inf,RANGEDEL:; Span() = c-d:{(#4,RANGEDEL)}
.

iter snapshots=3 print-snapshot-pinned print-force-obsolete
first
next
next
next
next
next
----
a#inf,RANGEDEL: (not pinned) (not force obsolete); Span() = a-b:{(#1,RANGEDEL)}
a#2,SET:b (not pinned) (not force obsolete)
b#inf,RANGEDEL: (not pinned) (not force obsolete); Span() = b-c:{(#4,RANGEDEL) (#1,RANGEDEL)}
b#2,SET:e (pinned) (force obsolete)
c#inf,RANGEDEL: (not pinned) (force obsolete); Span() = c-d:{(#4,RANGEDEL)}
.

iter snapshots=4 print-snapshot-pinned print-force-obsolete
first
next
next
next
next
next
next
----
a#inf,RANGEDEL: (not pinned) (not force obsolete); Span() = a-b:{(#1,RANGEDEL)}
a#2,SET:b (not pinned) (not force obsolete)
b#inf,RANGEDEL: (not pinned) (not force obsolete); Span() = b-c:{(#4,RANGEDEL) (#1,RANGEDEL)}
b#2,SET:e (pinned) (force obsolete)
c#inf,RANGEDEL: (not pinned) (force obsolete); Span() = c-d:{(#4,RANGEDEL)}
c#3,SET:f (pinned) (force obsolete)
.

define
a.RANGEDEL.3:e
b.SET.4:b
c.SET.3:c
d.SET.2:d
e.SET.1:e
----

iter
first
next
next
next
next
----
a#inf,RANGEDEL:; Span() = a-e:{(#3,RANGEDEL)}
b#4,SET:b
c#3,SET:c
e#1,SET:e
.

define
a.RANGEDEL.3:e
b.MERGE.4:b
c.MERGE.3:c
d.MERGE.2:d
e.MERGE.1:e
----

iter
first
next
next
next
next
----
a#inf,RANGEDEL:; Span() = a-e:{(#3,RANGEDEL)}
b#4,MERGE:b
c#3,MERGE:c
e#1,MERGE:e
.

define
a.RANGEDEL.3:c
b.MERGE.5:e
b.MERGE.4:d
b.MERGE.2:c
b.MERGE.1:b
d.MERGE.5:c
d.MERGE.4:b
d.RANGEDEL.3:f
d.MERGE.2:e
d.MERGE.1:d
----

iter
first
next
next
next
next
----
a#inf,RANGEDEL:; Span() = a-c:{(#3,RANGEDEL)}
b#5,MERGE:de
d#inf,RANGEDEL:; Span() = d-f:{(#3,RANGEDEL)}
d#5,MERGE:bc
.

define
a.RANGEDEL.3:d
b.RANGEDEL.2:e
c.RANGEDEL.1:f
----

iter
first
next
next
next
next
next
----
a#inf,RANGEDEL:; Span() = a-b:{(#3,RANGEDEL)}
b#inf,RANGEDEL:; Span() = b-c:{(#3,RANGEDEL)}
c#inf,RANGEDEL:; Span() = c-d:{(#3,RANGEDEL)}
d#inf,RANGEDEL:; Span() = d-e:{(#2,RANGEDEL)}
e#inf,RANGEDEL:; Span() = e-f:{(#1,RANGEDEL)}
.

iter snapshots=2
first
next
next
next
----
a#inf,RANGEDEL:; Span() = a-b:{(#3,RANGEDEL)}
b#inf,RANGEDEL:; Span() = b-c:{(#3,RANGEDEL)}
c#inf,RANGEDEL:; Span() = c-d:{(#3,RANGEDEL) (#1,RANGEDEL)}
d#inf,RANGEDEL:; Span() = d-e:{(#2,RANGEDEL) (#1,RANGEDEL)}

iter snapshots=3
first
next
next
next
next
next
----
a#inf,RANGEDEL:; Span() = a-b:{(#3,RANGEDEL)}
b#inf,RANGEDEL:; Span() = b-c:{(#3,RANGEDEL) (#2,RANGEDEL)}
c#inf,RANGEDEL:; Span() = c-d:{(#3,RANGEDEL) (#2,RANGEDEL)}
d#inf,RANGEDEL:; Span() = d-e:{(#2,RANGEDEL)}
e#inf,RANGEDEL:; Span() = e-f:{(#1,RANGEDEL)}
.

iter snapshots=(2,3)
first
next
next
next
next
next
----
a#inf,RANGEDEL:; Span() = a-b:{(#3,RANGEDEL)}
b#inf,RANGEDEL:; Span() = b-c:{(#3,RANGEDEL) (#2,RANGEDEL)}
c#inf,RANGEDEL:; Span() = c-d:{(#3,RANGEDEL) (#2,RANGEDEL) (#1,RANGEDEL)}
d#inf,RANGEDEL:; Span() = d-e:{(#2,RANGEDEL) (#1,RANGEDEL)}
e#inf,RANGEDEL:; Span() = e-f:{(#1,RANGEDEL)}
.

define
a.RANGEDEL.10:k
f.SET.9:f
f.SET.8:f
----

iter snapshots=(9,10) print-snapshot-pinned print-force-obsolete
first
next
next
----
a#inf,RANGEDEL: (not pinned) (not force obsolete); Span() = a-k:{(#10,RANGEDEL)}
f#9,SET:f (pinned) (force obsolete)
f#8,SET:f (pinned) (force obsolete)

define
f.RANGEDEL.10:k
f.SET.9:f
f.SET.8:f
----

iter snapshots=(9,10)
first
next
next
----
f#inf,RANGEDEL:; Span() = f-k:{(#10,RANGEDEL)}
f#9,SET:f
f#8,SET:f

define
a.SET.1:a
b.RANGEDEL.2:d
c.RANGEDEL.3:e
d.SET.4:d
----

iter
first
next
next
next
next
next
----
a#1,SET:a
b#inf,RANGEDEL:; Span() = b-c:{(#2,RANGEDEL)}
c#inf,RANGEDEL:; Span() = c-d:{(#3,RANGEDEL)}
d#inf,RANGEDEL:; Span() = d-e:{(#3,RANGEDEL)}
d#4,SET:d
.

iter snapshots=3
first
next
next
next
next
next
----
a#1,SET:a
b#inf,RANGEDEL:; Span() = b-c:{(#2,RANGEDEL)}
c#inf,RANGEDEL:; Span() = c-d:{(#3,RANGEDEL) (#2,RANGEDEL)}
d#inf,RANGEDEL:; Span() = d-e:{(#3,RANGEDEL)}
d#4,SET:d
.

define
a.SET.1:a
b.RANGEDEL.2:d
c.SET.4:d
----

iter
first
next
next
next
----
a#1,SET:a
b#inf,RANGEDEL:; Span() = b-d:{(#2,RANGEDEL)}
c#4,SET:d
.

define
a.RANGEDEL.2:d
a.SET.2:a
b.SET.2:b
c.SET.2:c
----

iter
first
next
next
next
next
----
a#inf,RANGEDEL:; Span() = a-d:{(#2,RANGEDEL)}
a#2,SET:a
b#2,SET:b
c#2,SET:c
.

define
a.SINGLEDEL.1:
----

iter
first
next
----
a#1,SINGLEDEL:
.

iter elide-tombstones=true
first
----
.
ineffectual-single-deletes: a

define
a.SINGLEDEL.2:
a.SINGLEDEL.1:
----

iter
first
next
----
a#2,SINGLEDEL:
.
ineffectual-single-deletes: a

define
a.SINGLEDEL.3:
a.SINGLEDEL.2:
a.SET.1:a
----

iter
first
----
.
ineffectual-single-deletes: a

define
a.SET.3:a
b.SINGLEDEL.2:
b.DEL.1:
----

iter
first
next
next
----
a#3,SET:a
b#2,DEL:
.
ineffectual-single-deletes: b

define
a.SINGLEDEL.2:
a.DEL.1:
----

iter
first
next
----
a#2,DEL:
.
ineffectual-single-deletes: a

iter elide-tombstones=true
first
----
.
ineffectual-single-deletes: a

define
a.SINGLEDEL.2:
a.MERGE.1:
----

iter
first
----
.

iter elide-tombstones=true
first
----
.

define
a.SINGLEDEL.2:
a.SET.1:b
----

iter
first
----
.

# SET that meets a SINGLEDEL is transformed into a SETWITHDEL.

define
a.SET.2:b
a.SINGLEDEL.1:
----

iter
first
next
----
a#2,SETWITHDEL:b
.

# We don't notice the ineffectual single delete since the SET causes all
# SingleDelete error checking to be skipped.
iter elide-tombstones=true
first
next
----
a#2,SETWITHDEL:b
.

define
a.MERGE.6:b
a.SINGLEDEL.5:
a.SET.4:a
----

iter
first
next
----
a#6,SETWITHDEL:b[base]
.

# Non-deterministic use of SINGLEDEL where there are two older SETs that have
# not been deleted or single deleted. It is permitted to shadow both, since
# MERGE turns into a SETWITHDELETE when it meets the SINGLEDEL.
define
a.MERGE.6:b
a.SINGLEDEL.5:
a.SET.4:a
a.SET.3:a
----

iter
first
next
----
a#6,SETWITHDEL:b[base]
.

define
a.SINGLEDEL.2:
a.SET.1:b
b.SET.3:c
----

iter
first
next
----
b#3,SET:c
.

define
a.SINGLEDEL.3:
a.SET.2:b
a.SET.1:a
----

iter
first
next
----
a#1,SET:a
.
invariant-violation-single-deletes: a

define
a.SINGLEDEL.3:
a.MERGE.2:b
a.MERGE.1:a
----

# SINGLEDEL consumes the first MERGE.
iter
first
next
----
a#1,MERGE:a
.
invariant-violation-single-deletes: a

define
a.SINGLEDEL.4:
a.SET.3:val
a.SINGLEDEL.2:
a.SET.1:val
----

iter
first
----
.

iter snapshots=2
first
next
next
----
a#2,SINGLEDEL:
a#1,SET:val
.

define
a.SINGLEDEL.4:
a.SET.3:val
a.DEL.2:
a.SET.1:val
----

iter
first
next
----
a#2,DEL:
.

iter snapshots=2
first
next
next
----
a#2,DEL:
a#1,SET:val
.

iter snapshots=3
first
next
----
a#2,DEL:
.

iter snapshots=(2,3)
first
next
next
----
a#2,DEL:
a#1,SET:val
.

define
a.SINGLEDEL.4:
a.SET.3:c
a.MERGE.2:b
a.SET.1:a
----

iter
first
next
----
a#2,SET:ab[base]
.
invariant-violation-single-deletes: a

iter snapshots=2
first
next
next
----
a#2,MERGE:b
a#1,SET:a
.
invariant-violation-single-deletes: a

iter snapshots=3
first
next
----
a#2,SET:ab[base]
.
invariant-violation-single-deletes: a

iter snapshots=(2,3,4)
first
next
next
next
next
----
a#4,SINGLEDEL:
a#3,SET:c
a#2,MERGE:b
a#1,SET:a
.

define
a.SINGLEDEL.3:
a.RANGEDEL.2:c
a.SET.1:val
----

iter
first
next
next
----
a#inf,RANGEDEL:; Span() = a-c:{(#2,RANGEDEL)}
a#3,SINGLEDEL:
.

define
a.RANGEDEL.3:d
a.DEL.2:
a.SET.1:a
d.DEL.2:
----

iter
first
next
next
----
a#inf,RANGEDEL:; Span() = a-d:{(#3,RANGEDEL)}
d#2,DEL:
.

iter snapshots=3
first
next
next
next
----
a#inf,RANGEDEL:; Span() = a-d:{(#3,RANGEDEL)}
a#2,DEL:
d#2,DEL:
.

iter snapshots=2
first
next
next
next
----
a#inf,RANGEDEL:; Span() = a-d:{(#3,RANGEDEL)}
a#1,SET:a
d#2,DEL:
.

iter snapshots=1
first
next
next
----
a#inf,RANGEDEL:; Span() = a-d:{(#3,RANGEDEL)}
d#2,DEL:
.

define
a.MERGE.2:a
b.RANGEDEL.1:c
----

iter
first
next
next
----
a#2,MERGE:a
b#inf,RANGEDEL:; Span() = b-c:{(#1,RANGEDEL)}
.

define
a.MERGE.2:v2
a.RANGEDEL.1:b
a.MERGE.1:v1
----

iter is-bottommost-layer=true
first
next
next
----
a#inf,RANGEDEL:; Span() = a-b:{(#1,RANGEDEL)}
a#0,SET:v1v2[base]
.

# Verify that we transform merge+del -> set.

define
a.MERGE.5:5
a.DEL.3:
a.MERGE.1:1
----

iter
first
next
----
a#5,SETWITHDEL:5[base]
.

iter is-bottommost-layer=true
first
next
----
a#0,SETWITHDEL:5[base]
.

iter elide-tombstones=true
first
next
----
a#5,SETWITHDEL:5[base]
.

iter snapshots=2
first
next
next
----
a#5,SETWITHDEL:5[base]
a#1,MERGE:1
.

iter snapshots=2 elide-tombstones=true
first
next
next
----
a#5,SETWITHDEL:5[base]
a#1,MERGE:1
.

# Verify that merge+rangedel -> merge.

define
a.RANGEDEL.3:c
b.MERGE.5:5
b.SET.2:2
b.MERGE.1:1
----

iter
first
next
next
----
a#inf,RANGEDEL:; Span() = a-c:{(#3,RANGEDEL)}
b#5,MERGE:5
.

iter is-bottommost-layer=true
first
next
next
----
a#inf,RANGEDEL:; Span() = a-c:{(#3,RANGEDEL)}
b#0,SET:5[base]
.

iter snapshots=2
first
next
next
next
----
a#inf,RANGEDEL:; Span() = a-c:{(#3,RANGEDEL)}
b#5,MERGE:5
b#1,MERGE:1
.

define
a.RANGEDEL.3:c
b.MERGE.5:5
b.MERGE.2:2
b.MERGE.1:1
----

iter
first
next
next
----
a#inf,RANGEDEL:; Span() = a-c:{(#3,RANGEDEL)}
b#5,MERGE:5
.

iter snapshots=2
first
next
next
next
----
a#inf,RANGEDEL:; Span() = a-c:{(#3,RANGEDEL)}
b#5,MERGE:5
b#1,MERGE:1
.

# SET that meets a DEL is transformed into a SETWITHDEL.

define
a.SET.2:b
a.DEL.1:
----

iter
first
next
----
a#2,SETWITHDEL:b
.

iter snapshots=2
first
next
next
----
a#2,SET:b
a#1,DEL:
.

define
a.SET.3:c
a.DEL.2:
a.SET.1:b
----

iter
first
next
----
a#3,SETWITHDEL:c
.

iter snapshots=2
first
next
next
----
a#3,SETWITHDEL:c
a#1,SET:b
.

define
a.SET.3:c
a.SET.2:b
a.DEL.1:
----

iter
first
next
----
a#3,SETWITHDEL:c
.

iter snapshots=3
first
next
next
----
a#3,SET:c
a#2,SETWITHDEL:b
.

iter snapshots=2
first
next
next
----
a#3,SET:c
a#1,DEL:
.

define
a.DEL.3:
a.SET.2:b
a.DEL.1:
----

iter
first
next
----
a#3,DEL:
.

iter snapshots=3
first
next
next
----
a#3,DEL:
a#2,SETWITHDEL:b
.

iter snapshots=2
first
next
next
----
a#3,DEL:
a#1,DEL:
.

# SETWITHDEL-eligible entries at or under a RANGEDEL at the same user key should
# be skipped.
define
a.SET.3:c
a.RANGEDEL.2:z
a.SET.2:b
a.DEL.1:
----

iter is-bottommost-layer=true
first
next
next
----
a#inf,RANGEDEL:; Span() = a-z:{(#2,RANGEDEL)}
a#0,SET:c
.

iter is-bottommost-layer=true snapshots=3
first
next
next
next
----
a#inf,RANGEDEL:; Span() = a-z:{(#2,RANGEDEL)}
a#3,SET:c
a#0,SET:b
.

iter is-bottommost-layer=true snapshots=2
first
next
next
next
----
a#inf,RANGEDEL:; Span() = a-z:{(#2,RANGEDEL)}
a#3,SET:c
a#1,DEL:
.

define
a.SET.4:c
a.RANGEDEL.3:z
a.SET.2:b
a.DEL.1:
----

iter
first
next
next
----
a#inf,RANGEDEL:; Span() = a-z:{(#3,RANGEDEL)}
a#4,SET:c
.

# Invalid keys are emitted under SETWITHDEL.

define
a.SET.2:b
a.INVALID.1:
----

iter
first
----
err=invalid internal key kind: INVALID

define
a.SET.3:c
a.INVALID.2:
a.SET.1:b
----

iter
first
----
err=invalid internal key kind: INVALID

# SINGLEDEL that meets a SETWITHDEL is transformed into a DEL.

define
a.SINGLEDEL.3:
a.SETWITHDEL.2:d
b.SET.1:c
----

iter
first
next
next
----
a#3,DEL:
b#1,SET:c
.

iter snapshots=2
first
next
next
----
a#3,DEL:
b#1,SET:c
.

iter snapshots=3
first
next
next
next
----
a#3,SINGLEDEL:
a#2,SETWITHDEL:d
b#1,SET:c
.

define
a.SETWITHDEL.3:3
a.SET.2:d
b.SET.1:c
----

iter print-missized-dels
first
next
next
----
a#3,SETWITHDEL:3
b#1,SET:c
.
missized-dels=0

iter snapshots=3
first
next
next
next
----
a#3,SETWITHDEL:3
a#2,SET:d
b#1,SET:c
.

# Test a DELSIZED whose encoded value matches the size of a deleted key. The
# DELSIZED's value should be removed, reflecting that the tombstone already
# dropped the key that it was expected to drop.

define
a.SET.9:foo
b.DELSIZED.8:varint(11)
b.SET.5:helloworld
c.SET.2:bar
----

iter print-missized-dels
first
next
next
----
a#9,SET:foo
b#8,DELSIZED:
c#2,SET:bar
missized-dels=0

# Test two DELSIZEDs meeting. The lower-sequenced number value should carry
# forward, at the higher sequence number. The first DELSIZED should be consider
# missized: It never found the key it was supposed to delete.

define
a.SET.9:foo
b.DELSIZED.9:varint(20)
b.DELSIZED.8:varint(10)
c.SET.2:bar
----

iter print-missized-dels
first
next
next
----
a#9,SET:foo
b#9,DELSIZED:varint(10)
c#2,SET:bar
missized-dels=1

# Test a DELSIZED whose encoded value is larger than the size of the deleted
# key. The DELSIZED should be replaced by an ordinary DEL with the same sequence
# number.

define
a.SET.2:foo
b.DELSIZED.8:varint(25)
b.SET.3:hello
c.SET.9:bar
----

iter print-missized-dels
first
next
next
----
a#2,SET:foo
b#8,DEL:
c#9,SET:bar
missized-dels=1

# Test two DELSIZED at the same user key, but with correctly sized deleted keys.

define
a.DELSIZED.9:varint(4)
a.SET.8:foo
a.DELSIZED.8:varint(6)
a.SET.5:hello
----

iter print-missized-dels
first
next
----
a#9,DELSIZED:
.
missized-dels=0

# Test the above scenario, except the second DELSIZED is missized. It should
# still count as missized.

define
a.DELSIZED.9:varint(4)
a.SET.8:foo
a.DELSIZED.8:varint(1)
a.SET.5:hello
----

iter print-missized-dels
first
next
----
a#9,DEL:
.
missized-dels=1

# Test the above scenario, except the second tombstone is a DEL. It should
# NOT count as missized.

define
a.DELSIZED.9:varint(4)
a.SET.8:foo
a.DEL.8:
a.SET.5:hello
----

iter print-missized-dels
first
next
----
a#9,DEL:
.
missized-dels=0

# Test various DELSIZEDs beneath live keys. SETS should be converted to
# SETWITHDELs when they meet a DELSIZED.

define
a.SET.7:foo
a.DELSIZED.5:varint(5)
b.SET.4:bar
b.DELSIZED.2:varint(4)
b.SET.1:bax
c.SET.9:coconut
c.DEL.8:del
c.DELSIZED.5:varint(2)
d.SET.8:dragonfruit
----

iter print-missized-dels
first
next
next
next
next
----
a#7,SETWITHDEL:foo
b#4,SETWITHDEL:bar
c#9,SETWITHDEL:coconut
d#8,SET:dragonfruit
.
missized-dels=0

# Test a DELSIZED meeting a MERGE. This counts as a missized DEL—The user can't
# know the value of the most recent MERGE since it's dependent on LSM state.

define
a.DELSIZED.9:varint(4)
a.MERGE.8:fo
a.MERGE.7:o
----

iter print-missized-dels
first
next
----
a#9,DEL:
.
missized-dels=1

# Test a DELSIZED that shadows a SINGLEDEL'd key.

define
a.DELSIZED.4:varint(4)
b.SINGLEDEL.3:
b.SET.1:val
----

iter
first
next
----
a#4,DELSIZED:varint(4)
.

# Repeat the above but with elision of tombstones.

iter elide-tombstones=t
first
----
.

# Test DELSIZED shadowing SINGLEDEL.

define
a.DELSIZED.4:varint(4)
a.SET.2:foo
b.SINGLEDEL.3:
b.SET.1:val
----

iter
first
next
----
a#4,DELSIZED:
.

# Repeat the above but with elision of tombstones.

iter elide-tombstones=t
first
----
.

# Test a very subtle sequence where a elision of tombstones is active, and a
# unskippable RANGEDEL sits between a DELSIZED and the key it was intended to
# delete. In previous versions of the code, the RANGEDEL was interleaved at its
# sequence number and "unskippable" breaking the skipping of keys within the
# snapshot stripe.

define
a.DELSIZED.5:varint(4)
a.RANGEDEL.4:d
a.SET.3:foo
----

iter elide-tombstones=t
first
next
----
.
.

# Try the same test as above, but with allowing sequence number zeroing as well.

iter elide-tombstones=t is-bottommost-layer=t
first
next
----
.
.

# Perform a variant of the above test but with a DEL key.

define
a.DEL.5:
a.RANGEDEL.4:d
a.SET.3:foo
----

iter elide-tombstones=t
first
next
----
.
.

# Perform a variant of the above test but with a SINGLEDEL key.

define
a.SINGLEDEL.5:
a.RANGEDEL.4:d
a.SET.3:foo
----

iter elide-tombstones=t
first
next
----
.
.
ineffectual-single-deletes: a

# Perform a few variants of the above but with a range del with a seqnum equal to
# keys. NB: When seqnums are equal, the order of keys with various kinds is:
#
# DeleteSized < RangeKey{Delete,Unset,Set} < SetWithDelete < RangeDelete < SingleDelete < Set < Delete
#
# NB: Range keys are interleaved always at the maximal sequence number, so the
# compaction iterator should always observe them first.

define
a-z:{(#5,RANGEKEYDEL)}
a.SINGLEDEL.6:
a.SETWITHDEL.5:foo
a.RANGEDEL.5:z
----

# In the following case, the SINGLEDEL meets a SETWITHDEL, promoting the
# SINGLEDEL into a DEL.

iter
first
next
next
next
----
a#inf,RANGEKEYDEL:; Span() = a-z:{(#5,RANGEKEYDEL)}
a#inf,RANGEDEL:; Span() = a-z:{(#5,RANGEDEL)}
a#6,DEL:
.

# In this case, SINGLEDEL is elided (despite its transformation into a DEL) due
# to elide-tombstones=t.

iter elide-tombstones=t
first
next
next
----
.
.
.

define
a.SINGLEDEL.6:
a.RANGEDEL.5:d
a.SET.5:foo
----

# NB: In this case, in previous versions of the code, the RANGEDEL acted as an
# unintentional snapshot stripe change. This was a code artifact that was fixed
# when we began interleaving range deletions at the maximal sequence number
# using an interleaving iterator (like range keys are).

iter
first
next
----
a#inf,RANGEDEL:; Span() = a-d:{(#5,RANGEDEL)}
.

iter elide-tombstones=t is-bottommost-layer=t
first
next
----
.
.

define
a.SINGLEDEL.6:
a.SET.5:foo
a.RANGEDEL.4:d
a.SET.4:bar
----

# In previous versions of the code, the SINGLEDEL invariant checking could not
# see past the RANGEDEL and see that the a.SET.4 violates the invariant. This
# was a code artifact that has been improved when we began interleaving range
# deletes at the maximal sequence number

iter
first
next
next
----
a#inf,RANGEDEL:; Span() = a-d:{(#4,RANGEDEL)}
a#4,SET:bar
.
invariant-violation-single-deletes: a

define
a.SINGLEDEL.6:
a.SETWITHDEL.5:foo
a.RANGEDEL.5:d
----

# When the SINGLEDEL and SETWITHDEL meet, the SINGLEDEL is promoted into a DEL.

iter
first
next
----
a#inf,RANGEDEL:; Span() = a-d:{(#5,RANGEDEL)}
a#6,DEL:

iter elide-tombstones=t
first
next
----
.
.

define
a.DELSIZED.6:varint(3)
a.RANGEDEL.5:d
a.SET.5:foo
----

iter
first
next
next
----
a#inf,RANGEDEL:; Span() = a-d:{(#5,RANGEDEL)}
a#6,DEL:
.

iter elide-tombstones=t
first
next
----
.
.

# Test a DELSIZED with a value that fails to decode.

define
a.DELSIZED.5:notavarint
a.SET.4:foo
----

iter
first
----
err=DELSIZED holds invalid value: 6e6f7461766172696e74

# Test a value-less DELSIZED.

define
a.DELSIZED.5:
a.SET.4:foo
a.SET.3:bar
----

iter print-missized-dels
first
next
----
a#5,DEL:
.
missized-dels=0

# Regression test for #3087.
#
# When a DELSIZED and a SINGLEDEL meet in a compaction, a DEL key should be
# emitted.

define
a.DELSIZED.5:
a.SINGLEDEL.3:
a.SET.2:foo
a.SET.1:bar
----

iter
first
next
----
a#5,DEL:
.

# When a MERGE and a DEL[SIZED] meet in a compaction, a SETWITHDEL key (NOT a
# SET) should be emitted. Otherwise, a sequence such as SINGLEDDEL, MERGE, DEL,
# SET could result in the SET re-appearing.

define
a.MERGE.5:foo
a.DEL.3:
----

iter
first
next
----
a#5,SETWITHDEL:foo[base]
.

define
a.SINGLEDEL.4:
a.MERGE.3:a3
a.SET.2:a2
b.SINGLEDEL.6:
b.SET.5:b5
b.SETWITHDEL.4:b4
----

iter
first
next
next
----
a#2,SET:a2
b#4,SETWITHDEL:b4
.
invariant-violation-single-deletes: a,b

# Add a test specifically for MissizedDeleteCallback
# This test creates a scenario where a DELSIZED tombstone's expected size
# doesn't match the actual size of the deleted entry.

define
a.DELSIZED.8:varint(25)
a.SET.5:hello
----

iter print-missized-dels print-missized-del-info
first
next
----
a#8,DEL:
.
missized-dels=1
missized-delete-info: a (elided=6, expected=25)

# Test a DELSIZED that never deletes a key (key doesn't exist)
define
a.DELSIZED.8:varint(10)
b.SET.5:hello
----

iter print-missized-dels print-missized-del-info
first
next
----
a#8,DELSIZED:varint(10)
b#5,SET:hello
missized-dels=0

# Test multiple missized DELSIZEDs in the same run
define
a.DELSIZED.9:varint(20)
a.SET.8:foo
b.DELSIZED.7:varint(15)
b.SET.5:bar
c.DELSIZED.6:varint(4)
c.SET.3:xyz
----

iter print-missized-dels print-missized-del-info
first
next
next
----
a#9,DEL:
b#7,DEL:
c#6,DELSIZED:
missized-dels=2
missized-delete-info: a (elided=4, expected=20); b (elided=4, expected=15)
