# Tests MVCC gets across range tombstones.
#
# Sets up the following dataset, where x is tombstone, o-o is range tombstone, [] is intent.
#
#  T
#  6                 [e6]                                     o6
#  5                      f5
#  4          o-----------------------o   o-------o  [j-l)@4 has localTs=3
#  3  x          d3       f3
#  2  o---------------o           h2                      o--------o
#  1  a1  x   c1          f1
#     a   b   c   d   e   f   g   h   i   j   k   l   m   n   o    p
#
run ok
put k=a ts=1 v=a1
del k=b ts=1
put k=c ts=1 v=c1
put k=f ts=1 v=f1
del_range_ts k=a end=e ts=2
del k=a ts=3
put k=d ts=3 v=d3
put k=f ts=3 v=f3
put k=h ts=2 v=h2
del_range_ts k=n end=p ts=2
del_range_ts k=c end=i ts=4
put k=f ts=5 v=f5
del_range_ts k=j end=l ts=4 localTs=3
with t=A
  txn_begin k=e ts=6
  put k=e v=e6
put k=o ts=6 v=o6
----
del: "b": found key false
del: "a": found key false
put: lock acquisition = {e id=00000001 key="e" iso=Serializable pri=0.00000000 epo=0 ts=6.000000000,0 min=0,0 seq=0 Replicated Intent []}
>> at end:
txn: "A" meta={id=00000001 key="e" iso=Serializable pri=0.00000000 epo=0 ts=6.000000000,0 min=0,0 seq=0} lock=true stat=PENDING rts=6.000000000,0 wto=false gul=0,0
rangekey: {a-c}/[2.000000000,0=/<empty>]
rangekey: {c-e}/[4.000000000,0=/<empty> 2.000000000,0=/<empty>]
rangekey: {e-i}/[4.000000000,0=/<empty>]
rangekey: {j-l}/[4.000000000,0={localTs=3.000000000,0}/<empty>]
rangekey: {n-p}/[2.000000000,0=/<empty>]
data: "a"/3.000000000,0 -> /<empty>
data: "a"/1.000000000,0 -> /BYTES/a1
data: "b"/1.000000000,0 -> /<empty>
data: "c"/1.000000000,0 -> /BYTES/c1
data: "d"/3.000000000,0 -> /BYTES/d3
meta: "e"/0,0 -> txn={id=00000001 key="e" iso=Serializable pri=0.00000000 epo=0 ts=6.000000000,0 min=0,0 seq=0} ts=6.000000000,0 del=false klen=12 vlen=7 mergeTs=<nil> txnDidNotUpdateMeta=true
data: "e"/6.000000000,0 -> /BYTES/e6
data: "f"/5.000000000,0 -> /BYTES/f5
data: "f"/3.000000000,0 -> /BYTES/f3
data: "f"/1.000000000,0 -> /BYTES/f1
data: "h"/2.000000000,0 -> /BYTES/h2
data: "o"/6.000000000,0 -> /BYTES/o6

# Run gets for all keys and all timestamps.
run ok
get k=a ts=1
get k=a ts=2
get k=a ts=3
get k=a ts=1 tombstones
get k=a ts=2 tombstones
get k=a ts=3 tombstones
----
get: "a" -> /BYTES/a1 @1.000000000,0
get: "a" -> <no data>
get: "a" -> <no data>
get: "a" -> /BYTES/a1 @1.000000000,0
get: "a" -> /<empty> @2.000000000,0
get: "a" -> /<empty> @3.000000000,0

run ok
get k=b ts=1
get k=b ts=2
get k=b ts=3
get k=b ts=1 tombstones
get k=b ts=2 tombstones
get k=b ts=3 tombstones
----
get: "b" -> <no data>
get: "b" -> <no data>
get: "b" -> <no data>
get: "b" -> /<empty> @1.000000000,0
get: "b" -> /<empty> @2.000000000,0
get: "b" -> /<empty> @2.000000000,0

run ok
get k=c ts=1
get k=c ts=2
get k=c ts=3
get k=c ts=4
get k=c ts=5
get k=c ts=1 tombstones
get k=c ts=2 tombstones
get k=c ts=3 tombstones
get k=c ts=4 tombstones
get k=c ts=5 tombstones
----
get: "c" -> /BYTES/c1 @1.000000000,0
get: "c" -> <no data>
get: "c" -> <no data>
get: "c" -> <no data>
get: "c" -> <no data>
get: "c" -> /BYTES/c1 @1.000000000,0
get: "c" -> /<empty> @2.000000000,0
get: "c" -> /<empty> @2.000000000,0
get: "c" -> /<empty> @4.000000000,0
get: "c" -> /<empty> @4.000000000,0

run ok
get k=d ts=1
get k=d ts=2
get k=d ts=3
get k=d ts=4
get k=d ts=5
get k=d ts=1 tombstones
get k=d ts=2 tombstones
get k=d ts=3 tombstones
get k=d ts=4 tombstones
get k=d ts=5 tombstones
----
get: "d" -> <no data>
get: "d" -> <no data>
get: "d" -> /BYTES/d3 @3.000000000,0
get: "d" -> <no data>
get: "d" -> <no data>
get: "d" -> <no data>
get: "d" -> /<empty> @2.000000000,0
get: "d" -> /BYTES/d3 @3.000000000,0
get: "d" -> /<empty> @4.000000000,0
get: "d" -> /<empty> @4.000000000,0

run ok
get k=e ts=3 inconsistent
get k=e ts=4 inconsistent
get k=e ts=5 inconsistent
get k=e ts=6 inconsistent
get k=e ts=3 tombstones inconsistent
get k=e ts=4 tombstones inconsistent
get k=e ts=5 tombstones inconsistent
get k=e ts=6 tombstones inconsistent
----
get: "e" -> <no data>
get: "e" -> <no data>
get: "e" -> <no data>
get: "e" -> intent {id=00000001 key="e" iso=Serializable pri=0.00000000 epo=0 ts=6.000000000,0 min=0,0 seq=0}
get: "e" -> <no data>
get: "e" -> <no data>
get: "e" -> /<empty> @4.000000000,0
get: "e" -> /<empty> @4.000000000,0
get: "e" -> intent {id=00000001 key="e" iso=Serializable pri=0.00000000 epo=0 ts=6.000000000,0 min=0,0 seq=0}
get: "e" -> /<empty> @4.000000000,0

run ok
get k=f ts=1
get k=f ts=2
get k=f ts=3
get k=f ts=4
get k=f ts=5
get k=f ts=6
get k=f ts=1 tombstones
get k=f ts=2 tombstones
get k=f ts=3 tombstones
get k=f ts=4 tombstones
get k=f ts=5 tombstones
get k=f ts=6 tombstones
----
get: "f" -> /BYTES/f1 @1.000000000,0
get: "f" -> /BYTES/f1 @1.000000000,0
get: "f" -> /BYTES/f3 @3.000000000,0
get: "f" -> <no data>
get: "f" -> /BYTES/f5 @5.000000000,0
get: "f" -> /BYTES/f5 @5.000000000,0
get: "f" -> /BYTES/f1 @1.000000000,0
get: "f" -> /BYTES/f1 @1.000000000,0
get: "f" -> /BYTES/f3 @3.000000000,0
get: "f" -> /<empty> @4.000000000,0
get: "f" -> /BYTES/f5 @5.000000000,0
get: "f" -> /BYTES/f5 @5.000000000,0

run ok
get k=g ts=3
get k=g ts=4
get k=g ts=5
get k=g ts=3 tombstones
get k=g ts=4 tombstones
get k=g ts=5 tombstones
----
get: "g" -> <no data>
get: "g" -> <no data>
get: "g" -> <no data>
get: "g" -> <no data>
get: "g" -> /<empty> @4.000000000,0
get: "g" -> /<empty> @4.000000000,0

run ok
get k=h ts=1
get k=h ts=2
get k=h ts=3
get k=h ts=4
get k=h ts=5
get k=h ts=1 tombstones
get k=h ts=2 tombstones
get k=h ts=3 tombstones
get k=h ts=4 tombstones
get k=h ts=5 tombstones
----
get: "h" -> <no data>
get: "h" -> /BYTES/h2 @2.000000000,0
get: "h" -> /BYTES/h2 @2.000000000,0
get: "h" -> <no data>
get: "h" -> <no data>
get: "h" -> <no data>
get: "h" -> /BYTES/h2 @2.000000000,0
get: "h" -> /BYTES/h2 @2.000000000,0
get: "h" -> /<empty> @4.000000000,0
get: "h" -> /<empty> @4.000000000,0

run ok
get k=j ts=3
get k=j ts=4
get k=j ts=5
get k=j ts=3 tombstones
get k=j ts=4 tombstones
get k=j ts=5 tombstones
----
get: "j" -> <no data>
get: "j" -> <no data>
get: "j" -> <no data>
get: "j" -> <no data>
get: "j" -> /<empty> @4.000000000,0
get: "j" -> /<empty> @4.000000000,0

run ok
get k=k ts=3
get k=k ts=4
get k=k ts=5
get k=k ts=3 tombstones
get k=k ts=4 tombstones
get k=k ts=5 tombstones
----
get: "k" -> <no data>
get: "k" -> <no data>
get: "k" -> <no data>
get: "k" -> <no data>
get: "k" -> /<empty> @4.000000000,0
get: "k" -> /<empty> @4.000000000,0

run ok
get k=l ts=1
get k=l ts=2
get k=l ts=3
get k=l ts=4
get k=l ts=5
get k=l ts=6
get k=l ts=1 tombstones
get k=l ts=2 tombstones
get k=l ts=3 tombstones
get k=l ts=4 tombstones
get k=l ts=5 tombstones
get k=l ts=6 tombstones
----
get: "l" -> <no data>
get: "l" -> <no data>
get: "l" -> <no data>
get: "l" -> <no data>
get: "l" -> <no data>
get: "l" -> <no data>
get: "l" -> <no data>
get: "l" -> <no data>
get: "l" -> <no data>
get: "l" -> <no data>
get: "l" -> <no data>
get: "l" -> <no data>

run ok
get k=n ts=1
get k=n ts=2
get k=n ts=3
get k=n ts=4
get k=n ts=5
get k=n ts=6
get k=n ts=1 tombstones
get k=n ts=2 tombstones
get k=n ts=3 tombstones
get k=n ts=4 tombstones
get k=n ts=5 tombstones
get k=n ts=6 tombstones
----
get: "n" -> <no data>
get: "n" -> <no data>
get: "n" -> <no data>
get: "n" -> <no data>
get: "n" -> <no data>
get: "n" -> <no data>
get: "n" -> <no data>
get: "n" -> /<empty> @2.000000000,0
get: "n" -> /<empty> @2.000000000,0
get: "n" -> /<empty> @2.000000000,0
get: "n" -> /<empty> @2.000000000,0
get: "n" -> /<empty> @2.000000000,0

run ok
get k=o ts=1
get k=o ts=2
get k=o ts=3
get k=o ts=4
get k=o ts=5
get k=o ts=6
get k=o ts=1 tombstones
get k=o ts=2 tombstones
get k=o ts=3 tombstones
get k=o ts=4 tombstones
get k=o ts=5 tombstones
get k=o ts=6 tombstones
----
get: "o" -> <no data>
get: "o" -> <no data>
get: "o" -> <no data>
get: "o" -> <no data>
get: "o" -> <no data>
get: "o" -> /BYTES/o6 @6.000000000,0
get: "o" -> <no data>
get: "o" -> /<empty> @2.000000000,0
get: "o" -> /<empty> @2.000000000,0
get: "o" -> /<empty> @2.000000000,0
get: "o" -> /<empty> @2.000000000,0
get: "o" -> /BYTES/o6 @6.000000000,0

# failOnMoreRecent: c
run error
get k=c ts=1 failOnMoreRecent
----
get: "c" -> <no data>
error: (*kvpb.WriteTooOldError:) WriteTooOldError: write for key "c" at timestamp 1.000000000,0 too old; must write at or above 4.000000000,1

run error
get k=c ts=2 failOnMoreRecent
----
get: "c" -> <no data>
error: (*kvpb.WriteTooOldError:) WriteTooOldError: write for key "c" at timestamp 2.000000000,0 too old; must write at or above 4.000000000,1

run error
get k=c ts=3 failOnMoreRecent
----
get: "c" -> <no data>
error: (*kvpb.WriteTooOldError:) WriteTooOldError: write for key "c" at timestamp 3.000000000,0 too old; must write at or above 4.000000000,1

run error
get k=c ts=4 failOnMoreRecent
----
get: "c" -> <no data>
error: (*kvpb.WriteTooOldError:) WriteTooOldError: write for key "c" at timestamp 4.000000000,0 too old; must write at or above 4.000000000,1

run ok
get k=c ts=5 failOnMoreRecent
----
get: "c" -> <no data>

# failOnMoreRecent: e
run error
get k=e ts=3 failOnMoreRecent
----
get: "e" -> <no data>
error: (*kvpb.LockConflictError:) conflicting locks on "e"

run error
get k=e ts=4 failOnMoreRecent
----
get: "e" -> <no data>
error: (*kvpb.LockConflictError:) conflicting locks on "e"

run error
get k=e ts=5 failOnMoreRecent
----
get: "e" -> <no data>
error: (*kvpb.LockConflictError:) conflicting locks on "e"

# failOnMoreRecent: g
run error
get k=g ts=3 failOnMoreRecent
----
get: "g" -> <no data>
error: (*kvpb.WriteTooOldError:) WriteTooOldError: write for key "g" at timestamp 3.000000000,0 too old; must write at or above 4.000000000,1

run error
get k=g ts=4 failOnMoreRecent
----
get: "g" -> <no data>
error: (*kvpb.WriteTooOldError:) WriteTooOldError: write for key "g" at timestamp 4.000000000,0 too old; must write at or above 4.000000000,1

run ok
get k=g ts=5 failOnMoreRecent
----
get: "g" -> <no data>


# globalUncertaintyLimit: b
run ok
get k=b ts=1 globalUncertaintyLimit=1
----
get: "b" -> <no data>

run error
get k=b ts=1 globalUncertaintyLimit=2
----
get: "b" -> <no data>
error: (*kvpb.ReadWithinUncertaintyIntervalError:) ReadWithinUncertaintyIntervalError: read at time 1.000000000,0 encountered previous write with future timestamp 2.000000000,0 within uncertainty interval `t <= (local=0,0, global=0,0)`; observed timestamps: []

# globalUncertaintyLimit: d
run ok
get k=d ts=1 globalUncertaintyLimit=1
----
get: "d" -> <no data>

run error
get k=d ts=1 globalUncertaintyLimit=2
----
get: "d" -> <no data>
error: (*kvpb.ReadWithinUncertaintyIntervalError:) ReadWithinUncertaintyIntervalError: read at time 1.000000000,0 encountered previous write with future timestamp 2.000000000,0 within uncertainty interval `t <= (local=0,0, global=0,0)`; observed timestamps: []

# globalUncertaintyLimit: g
run ok
get k=g ts=1 globalUncertaintyLimit=1
----
get: "g" -> <no data>

run ok
get k=g ts=1 globalUncertaintyLimit=3
----
get: "g" -> <no data>

run error
get k=g ts=1 globalUncertaintyLimit=4
----
get: "g" -> <no data>
error: (*kvpb.ReadWithinUncertaintyIntervalError:) ReadWithinUncertaintyIntervalError: read at time 1.000000000,0 encountered previous write with future timestamp 4.000000000,0 within uncertainty interval `t <= (local=0,0, global=0,0)`; observed timestamps: []

run ok
get k=g ts=4 globalUncertaintyLimit=5
----
get: "g" -> <no data>

# globalUncertaintyLimit: h
run ok
get k=h ts=2 globalUncertaintyLimit=2
----
get: "h" -> /BYTES/h2 @2.000000000,0

run ok
get k=h ts=2 globalUncertaintyLimit=3
----
get: "h" -> /BYTES/h2 @2.000000000,0

run error
get k=h ts=2 globalUncertaintyLimit=4
----
get: "h" -> <no data>
error: (*kvpb.ReadWithinUncertaintyIntervalError:) ReadWithinUncertaintyIntervalError: read at time 2.000000000,0 encountered previous write with future timestamp 4.000000000,0 within uncertainty interval `t <= (local=0,0, global=0,0)`; observed timestamps: []

# Test local timestamp uncertainty for [j-l)@4 with localTs=3. Normally,
# globalUncertaintyLimit=4 would error. However, localUncertaintyLimit<4
# disables this via observed timestamps, but not if
# localTs<=localUncertaintyLimit.
run error
get k=k ts=1 globalUncertaintyLimit=4
----
get: "k" -> <no data>
error: (*kvpb.ReadWithinUncertaintyIntervalError:) ReadWithinUncertaintyIntervalError: read at time 1.000000000,0 encountered previous write with future timestamp 4.000000000,0 (local=3.000000000,0) within uncertainty interval `t <= (local=0,0, global=0,0)`; observed timestamps: []

run ok
get k=k ts=1 globalUncertaintyLimit=4 localUncertaintyLimit=1
----
get: "k" -> <no data>

run ok
get k=k ts=1 globalUncertaintyLimit=4 localUncertaintyLimit=2
----
get: "k" -> <no data>

run error
get k=k ts=1 globalUncertaintyLimit=4 localUncertaintyLimit=3
----
get: "k" -> <no data>
error: (*kvpb.ReadWithinUncertaintyIntervalError:) ReadWithinUncertaintyIntervalError: read at time 1.000000000,0 encountered previous write with future timestamp 4.000000000,0 (local=3.000000000,0) within uncertainty interval `t <= (local=3.000000000,0, global=0,0)`; observed timestamps: []

# Test a particular case where:
# - a tombstone must be synthesized due to a range tombstone
# - the uncertainty limit is such that we must check for uncertainty
# - the only point at the key is not visible at the read timstamp, but is also
#   not outside the uncertainty limit
#
# In these circumstances, the scanner will seekVersion to find the first visible
# key (there is none), invalidating the underlying Pebble iterator. Although the
# underlying Pebble iterator has been invalidated, the scanner should still
# succeed in synthesizing a tombstone at the range key timestamp retrieved
# before the iterator was invalidated.
run ok
get k=o ts=5 tombstones globalUncertaintyLimit=6 localUncertaintyLimit=5
----
get: "o" -> /<empty> @2.000000000,0
