mirror of
https://source.quilibrium.com/quilibrium/ceremonyclient.git
synced 2024-11-10 10:15:18 +00:00
760 lines
12 KiB
Plaintext
760 lines
12 KiB
Plaintext
|
# Set a key within the indexed batch.
|
||
|
new-batch
|
||
|
set foo foo
|
||
|
----
|
||
|
|
||
|
# Construct an iterator over the indexed batch.
|
||
|
|
||
|
new-batch-iter i0
|
||
|
----
|
||
|
|
||
|
# The key we set should be visible.
|
||
|
|
||
|
iter iter=i0
|
||
|
first
|
||
|
next
|
||
|
----
|
||
|
foo: (foo, .)
|
||
|
.
|
||
|
|
||
|
# Same behavior with a batch-only iterator.
|
||
|
new-batch-only-iter i-bo0
|
||
|
----
|
||
|
|
||
|
iter iter=i-bo0
|
||
|
first
|
||
|
next
|
||
|
----
|
||
|
foo: (foo, .)
|
||
|
.
|
||
|
|
||
|
# Set a new key, while the above iterator is still open.
|
||
|
|
||
|
mutate
|
||
|
set bar bar
|
||
|
----
|
||
|
|
||
|
# The new key should be invisible.
|
||
|
|
||
|
iter iter=i0
|
||
|
prev
|
||
|
next
|
||
|
----
|
||
|
foo: (foo, .)
|
||
|
.
|
||
|
|
||
|
# Same behavior with a batch-only iterator.
|
||
|
iter iter=i-bo0
|
||
|
prev
|
||
|
next
|
||
|
----
|
||
|
foo: (foo, .)
|
||
|
.
|
||
|
|
||
|
# A set-options operation should refresh the Iterator's view of the batch. The
|
||
|
# bar key should now be visibile.
|
||
|
|
||
|
iter iter=i0
|
||
|
set-options
|
||
|
first
|
||
|
next
|
||
|
next
|
||
|
----
|
||
|
.
|
||
|
bar: (bar, .)
|
||
|
foo: (foo, .)
|
||
|
.
|
||
|
|
||
|
# Same behavior with a batch-only iterator.
|
||
|
iter iter=i-bo0
|
||
|
set-options
|
||
|
first
|
||
|
next
|
||
|
next
|
||
|
----
|
||
|
.
|
||
|
bar: (bar, .)
|
||
|
foo: (foo, .)
|
||
|
.
|
||
|
|
||
|
# Delete foo with a range deletion.
|
||
|
|
||
|
mutate
|
||
|
del-range f g
|
||
|
----
|
||
|
|
||
|
# Both keys should still be visible.
|
||
|
|
||
|
iter iter=i0
|
||
|
prev
|
||
|
prev
|
||
|
----
|
||
|
foo: (foo, .)
|
||
|
bar: (bar, .)
|
||
|
|
||
|
# Same behavior with a batch-only iterator.
|
||
|
iter iter=i-bo0
|
||
|
prev
|
||
|
prev
|
||
|
----
|
||
|
foo: (foo, .)
|
||
|
bar: (bar, .)
|
||
|
|
||
|
# After refreshing the iterator's view of the batch, foo should be deleted.
|
||
|
|
||
|
iter iter=i0
|
||
|
set-options
|
||
|
seek-ge foo
|
||
|
seek-lt foo
|
||
|
----
|
||
|
.
|
||
|
.
|
||
|
bar: (bar, .)
|
||
|
|
||
|
# Same behavior with a batch-only iterator.
|
||
|
iter iter=i-bo0
|
||
|
set-options
|
||
|
seek-ge foo
|
||
|
seek-lt foo
|
||
|
----
|
||
|
.
|
||
|
.
|
||
|
bar: (bar, .)
|
||
|
|
||
|
# Write a range key set and a point key.
|
||
|
|
||
|
mutate
|
||
|
range-key-set a c @1 boop
|
||
|
set b b
|
||
|
----
|
||
|
|
||
|
# The mutations should not be visible.
|
||
|
|
||
|
iter iter=i0
|
||
|
prev
|
||
|
next
|
||
|
----
|
||
|
.
|
||
|
bar: (bar, .)
|
||
|
|
||
|
# Same behavior with a batch-only iterator.
|
||
|
iter iter=i-bo0
|
||
|
prev
|
||
|
next
|
||
|
----
|
||
|
.
|
||
|
bar: (bar, .)
|
||
|
|
||
|
# But refreshing the batch through a call to SetOptions should surface them.
|
||
|
|
||
|
iter iter=i0
|
||
|
set-options
|
||
|
first
|
||
|
next
|
||
|
next
|
||
|
----
|
||
|
.
|
||
|
a: (., [a-c) @1=boop UPDATED)
|
||
|
b: (b, [a-c) @1=boop)
|
||
|
bar: (bar, [a-c) @1=boop)
|
||
|
|
||
|
# Same behavior with a batch-only iterator.
|
||
|
iter iter=i-bo0
|
||
|
set-options
|
||
|
first
|
||
|
next
|
||
|
next
|
||
|
----
|
||
|
.
|
||
|
a: (., [a-c) @1=boop UPDATED)
|
||
|
b: (b, [a-c) @1=boop)
|
||
|
bar: (bar, [a-c) @1=boop)
|
||
|
|
||
|
# Remove part of the range key to fragment it.
|
||
|
|
||
|
mutate
|
||
|
range-key-del ace arc
|
||
|
----
|
||
|
|
||
|
iter iter=i0
|
||
|
next
|
||
|
prev
|
||
|
prev
|
||
|
prev
|
||
|
prev
|
||
|
----
|
||
|
.
|
||
|
bar: (bar, [a-c) @1=boop UPDATED)
|
||
|
b: (b, [a-c) @1=boop)
|
||
|
a: (., [a-c) @1=boop)
|
||
|
.
|
||
|
|
||
|
# Same behavior with a batch-only iterator.
|
||
|
iter iter=i-bo0
|
||
|
next
|
||
|
prev
|
||
|
prev
|
||
|
prev
|
||
|
prev
|
||
|
----
|
||
|
.
|
||
|
bar: (bar, [a-c) @1=boop UPDATED)
|
||
|
b: (b, [a-c) @1=boop)
|
||
|
a: (., [a-c) @1=boop)
|
||
|
.
|
||
|
|
||
|
iter iter=i0
|
||
|
set-options
|
||
|
first
|
||
|
next
|
||
|
next
|
||
|
next
|
||
|
----
|
||
|
.
|
||
|
a: (., [a-ace) @1=boop UPDATED)
|
||
|
arc: (., [arc-c) @1=boop UPDATED)
|
||
|
b: (b, [arc-c) @1=boop)
|
||
|
bar: (bar, [arc-c) @1=boop)
|
||
|
|
||
|
# Same behavior with a batch-only iterator.
|
||
|
iter iter=i-bo0
|
||
|
set-options
|
||
|
first
|
||
|
next
|
||
|
next
|
||
|
next
|
||
|
----
|
||
|
.
|
||
|
a: (., [a-ace) @1=boop UPDATED)
|
||
|
arc: (., [arc-c) @1=boop UPDATED)
|
||
|
b: (b, [arc-c) @1=boop)
|
||
|
bar: (bar, [arc-c) @1=boop)
|
||
|
|
||
|
# Create a new indexed batch and a new iterator over it.
|
||
|
|
||
|
new-batch
|
||
|
set foo foo
|
||
|
----
|
||
|
|
||
|
new-batch-iter i1
|
||
|
----
|
||
|
|
||
|
iter iter=i1
|
||
|
first
|
||
|
next
|
||
|
----
|
||
|
foo: (foo, .)
|
||
|
.
|
||
|
|
||
|
# Test interactions with cloned iterators.
|
||
|
# First, apply mutations to the batch. They should remain invisible.
|
||
|
|
||
|
mutate
|
||
|
set bar bar
|
||
|
range-key-set a z @1 boop
|
||
|
del-range f g
|
||
|
----
|
||
|
|
||
|
iter iter=i1
|
||
|
first
|
||
|
next
|
||
|
----
|
||
|
foo: (foo, .)
|
||
|
.
|
||
|
|
||
|
# Clone i1 to create i2.
|
||
|
|
||
|
clone from=i1 to=i2 refresh-batch=false
|
||
|
----
|
||
|
|
||
|
# i1 unchanged.
|
||
|
|
||
|
iter iter=i1
|
||
|
first
|
||
|
next
|
||
|
----
|
||
|
foo: (foo, .)
|
||
|
.
|
||
|
|
||
|
# i2 sees exactly the same stale state as i1 until SetOptions is called to
|
||
|
# explicitly refresh the view of the underlying batch.
|
||
|
|
||
|
iter iter=i2
|
||
|
first
|
||
|
next
|
||
|
set-options
|
||
|
first
|
||
|
next
|
||
|
next
|
||
|
----
|
||
|
foo: (foo, .)
|
||
|
.
|
||
|
.
|
||
|
a: (., [a-z) @1=boop UPDATED)
|
||
|
bar: (bar, [a-z) @1=boop)
|
||
|
.
|
||
|
|
||
|
# Clone i1 to create i3, this time passing RefreshBatchView: true. This clone
|
||
|
# should view the updated view of the underlying batch.
|
||
|
clone from=i1 to=i3 refresh-batch=true
|
||
|
----
|
||
|
|
||
|
iter iter=i3
|
||
|
first
|
||
|
next
|
||
|
----
|
||
|
a: (., [a-z) @1=boop UPDATED)
|
||
|
bar: (bar, [a-z) @1=boop)
|
||
|
|
||
|
# i1 should still have the old, stale view of the batch.
|
||
|
|
||
|
iter iter=i1
|
||
|
first
|
||
|
next
|
||
|
----
|
||
|
foo: (foo, .)
|
||
|
.
|
||
|
|
||
|
# Mutate the underlying batch again.
|
||
|
|
||
|
mutate
|
||
|
set foo foo
|
||
|
range-key-set a z @2 bax
|
||
|
del-range b c
|
||
|
----
|
||
|
|
||
|
# The new mutations should be invisible until SetOptions is called.
|
||
|
|
||
|
iter iter=i1
|
||
|
first
|
||
|
next
|
||
|
set-options
|
||
|
first
|
||
|
next
|
||
|
next
|
||
|
----
|
||
|
foo: (foo, .)
|
||
|
.
|
||
|
.
|
||
|
a: (., [a-z) @2=bax, @1=boop UPDATED)
|
||
|
foo: (foo, [a-z) @2=bax, @1=boop)
|
||
|
.
|
||
|
|
||
|
iter iter=i2
|
||
|
first
|
||
|
next
|
||
|
next
|
||
|
set-options
|
||
|
first
|
||
|
next
|
||
|
next
|
||
|
----
|
||
|
a: (., [a-z) @1=boop UPDATED)
|
||
|
bar: (bar, [a-z) @1=boop)
|
||
|
.
|
||
|
.
|
||
|
a: (., [a-z) @2=bax, @1=boop UPDATED)
|
||
|
foo: (foo, [a-z) @2=bax, @1=boop)
|
||
|
.
|
||
|
|
||
|
# Commit a separate batch to the underlying engine.
|
||
|
batch
|
||
|
range-key-set a z @5 poi
|
||
|
set apple apple
|
||
|
----
|
||
|
|
||
|
# The writes to the underlying engine should be invisible.
|
||
|
|
||
|
iter iter=i1
|
||
|
first
|
||
|
next
|
||
|
next
|
||
|
----
|
||
|
a: (., [a-z) @2=bax, @1=boop UPDATED)
|
||
|
foo: (foo, [a-z) @2=bax, @1=boop)
|
||
|
.
|
||
|
|
||
|
# Clone i1 to create i4.
|
||
|
|
||
|
clone from=i1 to=i4 refresh-batch=false
|
||
|
----
|
||
|
|
||
|
iter iter=i4
|
||
|
first
|
||
|
next
|
||
|
next
|
||
|
----
|
||
|
a: (., [a-z) @2=bax, @1=boop UPDATED)
|
||
|
foo: (foo, [a-z) @2=bax, @1=boop)
|
||
|
.
|
||
|
|
||
|
# Refresh i4's view of its batch. It should still not see the newly committed
|
||
|
# writes.
|
||
|
|
||
|
iter iter=i4
|
||
|
set-options
|
||
|
first
|
||
|
next
|
||
|
next
|
||
|
----
|
||
|
.
|
||
|
a: (., [a-z) @2=bax, @1=boop UPDATED)
|
||
|
foo: (foo, [a-z) @2=bax, @1=boop)
|
||
|
.
|
||
|
|
||
|
# Create a new iterator i5 over the indexed batch [not a Clone]. It should see
|
||
|
# all committed writes and uncommitted writes.
|
||
|
|
||
|
new-batch-iter i5
|
||
|
----
|
||
|
|
||
|
iter iter=i5
|
||
|
first
|
||
|
next
|
||
|
next
|
||
|
next
|
||
|
----
|
||
|
a: (., [a-z) @5=poi, @2=bax, @1=boop UPDATED)
|
||
|
apple: (apple, [a-z) @5=poi, @2=bax, @1=boop)
|
||
|
foo: (foo, [a-z) @5=poi, @2=bax, @1=boop)
|
||
|
.
|
||
|
|
||
|
# The batch-only iter only sees the contents of the batch.
|
||
|
new-batch-only-iter i-bo1
|
||
|
----
|
||
|
|
||
|
iter iter=i-bo1
|
||
|
first
|
||
|
next
|
||
|
next
|
||
|
----
|
||
|
a: (., [a-z) @2=bax, @1=boop UPDATED)
|
||
|
foo: (foo, [a-z) @2=bax, @1=boop)
|
||
|
.
|
||
|
|
||
|
# Mutate all the open iterators' underlying batch.
|
||
|
|
||
|
mutate
|
||
|
range-key-set a z @6 yaya
|
||
|
set c c
|
||
|
----
|
||
|
|
||
|
# The iterators should still not see the committed writes, even after refreshing
|
||
|
# to observe more recent batch writes.
|
||
|
|
||
|
iter iter=i1
|
||
|
first
|
||
|
next
|
||
|
next
|
||
|
----
|
||
|
a: (., [a-z) @2=bax, @1=boop UPDATED)
|
||
|
foo: (foo, [a-z) @2=bax, @1=boop)
|
||
|
.
|
||
|
|
||
|
iter iter=i4
|
||
|
first
|
||
|
next
|
||
|
next
|
||
|
set-options
|
||
|
first
|
||
|
next
|
||
|
next
|
||
|
----
|
||
|
a: (., [a-z) @2=bax, @1=boop UPDATED)
|
||
|
foo: (foo, [a-z) @2=bax, @1=boop)
|
||
|
.
|
||
|
.
|
||
|
a: (., [a-z) @6=yaya, @2=bax, @1=boop UPDATED)
|
||
|
c: (c, [a-z) @6=yaya, @2=bax, @1=boop)
|
||
|
foo: (foo, [a-z) @6=yaya, @2=bax, @1=boop)
|
||
|
|
||
|
|
||
|
# The batch-only iter sees the more recent batch writes after refreshing.
|
||
|
iter iter=i-bo1
|
||
|
first
|
||
|
next
|
||
|
next
|
||
|
set-options
|
||
|
first
|
||
|
next
|
||
|
next
|
||
|
next
|
||
|
----
|
||
|
a: (., [a-z) @2=bax, @1=boop UPDATED)
|
||
|
foo: (foo, [a-z) @2=bax, @1=boop)
|
||
|
.
|
||
|
.
|
||
|
a: (., [a-z) @6=yaya, @2=bax, @1=boop UPDATED)
|
||
|
c: (c, [a-z) @6=yaya, @2=bax, @1=boop)
|
||
|
foo: (foo, [a-z) @6=yaya, @2=bax, @1=boop)
|
||
|
.
|
||
|
|
||
|
# Test a scenario where constructing an Iterator should NOT use the cached
|
||
|
# fragmented tombstones / range keys, because the new Iterator is a Clone which
|
||
|
# must read at an earlier batch sequence number.
|
||
|
|
||
|
# Reset and start a new batch.
|
||
|
|
||
|
reset
|
||
|
----
|
||
|
|
||
|
new-batch
|
||
|
set foo foo
|
||
|
----
|
||
|
|
||
|
new-batch-iter i1
|
||
|
----
|
||
|
|
||
|
iter iter=i1
|
||
|
first
|
||
|
next
|
||
|
----
|
||
|
foo: (foo, .)
|
||
|
.
|
||
|
|
||
|
# Apply a range deletion and a range key.
|
||
|
|
||
|
mutate
|
||
|
del-range a z
|
||
|
range-key-set a z @1 foo
|
||
|
----
|
||
|
|
||
|
# Create a new iterator which will see both the range deletion and the range
|
||
|
# key, and cache both on the batch so that future iterators constructed over the
|
||
|
# batch do not need to.
|
||
|
|
||
|
new-batch-iter i2
|
||
|
----
|
||
|
|
||
|
iter iter=i2
|
||
|
first
|
||
|
next
|
||
|
----
|
||
|
a: (., [a-z) @1=foo UPDATED)
|
||
|
.
|
||
|
|
||
|
# Clone the original iterator from before the delete range and the range key
|
||
|
# were created. It should not use the cached fragments of range deletions or
|
||
|
# range keys, and should not see the effects of either.
|
||
|
|
||
|
clone from=i1 to=i3 refresh-batch=false
|
||
|
----
|
||
|
|
||
|
iter iter=i3
|
||
|
first
|
||
|
next
|
||
|
----
|
||
|
foo: (foo, .)
|
||
|
.
|
||
|
|
||
|
reset
|
||
|
----
|
||
|
|
||
|
new-batch
|
||
|
range-key-set a c @1 poi
|
||
|
range-key-set b d @2 yaya
|
||
|
----
|
||
|
|
||
|
new-batch-iter i1
|
||
|
----
|
||
|
|
||
|
# The batch contains 2 range keys, but the skiplist of fragmented range keys
|
||
|
# contains 3 elements (a-b, b-c, c-d).
|
||
|
|
||
|
iter iter=i1
|
||
|
first
|
||
|
next
|
||
|
next
|
||
|
----
|
||
|
a: (., [a-b) @1=poi UPDATED)
|
||
|
b: (., [b-c) @2=yaya, @1=poi UPDATED)
|
||
|
c: (., [c-d) @2=yaya UPDATED)
|
||
|
|
||
|
# Add a new range key to the batch. The batch contains 3 internal range keys,
|
||
|
# and the skiplist of fragmented range keys contains 3 elements.
|
||
|
|
||
|
mutate
|
||
|
range-key-set e f @3 foo
|
||
|
----
|
||
|
|
||
|
# Refreshing the iterator's view of the batch through SetOptions should surface
|
||
|
# the new range key. An earlier bug incorrectly compared the number of
|
||
|
# fragmented range keys to the number of internal batch range keys in order to
|
||
|
# determine when to refresh the iterator.
|
||
|
|
||
|
iter iter=i1
|
||
|
first
|
||
|
next
|
||
|
next
|
||
|
set-options
|
||
|
first
|
||
|
next
|
||
|
next
|
||
|
next
|
||
|
seek-ge bat
|
||
|
----
|
||
|
a: (., [a-b) @1=poi UPDATED)
|
||
|
b: (., [b-c) @2=yaya, @1=poi UPDATED)
|
||
|
c: (., [c-d) @2=yaya UPDATED)
|
||
|
.
|
||
|
a: (., [a-b) @1=poi UPDATED)
|
||
|
b: (., [b-c) @2=yaya, @1=poi UPDATED)
|
||
|
c: (., [c-d) @2=yaya UPDATED)
|
||
|
e: (., [e-f) @3=foo UPDATED)
|
||
|
bat: (., [b-c) @2=yaya, @1=poi UPDATED)
|
||
|
|
||
|
# Mutate the range key under the interleaving iterator's current position in the
|
||
|
# indexed batch.
|
||
|
#
|
||
|
# The last `seek-ge` operation landed on the range key [b-c). The top-level
|
||
|
# *pebble.Iterator needs to step the iterator again to see if there's a
|
||
|
# coincident point key at (`bat`), which would've advanced the interleaving
|
||
|
# iterator to the range key with bounds [c,d), so the underlying interleaving
|
||
|
# iterator is positioned ahead at:
|
||
|
#
|
||
|
# c: (., [c-d) @2=yaya)
|
||
|
#
|
||
|
# If we call set-options to refresh the iterator's view of the indexed batch,
|
||
|
# the range-key-unset [c,d)@2 becomes visible, and the range key that the
|
||
|
# underlying interleaving iterator is positioned over should not be visible.
|
||
|
#
|
||
|
# A bug previously allowed this range key to be visible when seeking into this
|
||
|
# span's bounds (see the optimization in InterleavingIter.SeekGE). Now, the call
|
||
|
# to SetOptions clears the interleaving iterator's positional state to avoid the
|
||
|
# SeekGE optimization.
|
||
|
|
||
|
mutate
|
||
|
range-key-unset b d @2
|
||
|
----
|
||
|
|
||
|
iter iter=i1
|
||
|
set-options
|
||
|
seek-ge cat
|
||
|
----
|
||
|
.
|
||
|
e: (., [e-f) @3=foo UPDATED)
|
||
|
|
||
|
reset
|
||
|
----
|
||
|
|
||
|
batch
|
||
|
range-key-set a e @1 foo
|
||
|
----
|
||
|
|
||
|
flush
|
||
|
----
|
||
|
|
||
|
new-batch
|
||
|
----
|
||
|
|
||
|
new-batch-iter batchiter
|
||
|
----
|
||
|
|
||
|
new-db-iter dbiter
|
||
|
----
|
||
|
|
||
|
# Test RangeKeyChanged() semantics.
|
||
|
# Seeking to the same prefix returns RangeKeyChanged()=false.
|
||
|
# Seeking to a new prefix returns RangeKeyChanged()=true.
|
||
|
# Seeking to the same prefix with a SetOptions call in between returns
|
||
|
# RangeKeyChanged()=true.
|
||
|
|
||
|
iter iter=dbiter
|
||
|
seek-prefix-ge b@3
|
||
|
seek-prefix-ge b@4
|
||
|
seek-prefix-ge c@3
|
||
|
seek-prefix-ge d@3
|
||
|
set-options
|
||
|
seek-prefix-ge d@1
|
||
|
----
|
||
|
b@3: (., [b-"b\x00") @1=foo UPDATED)
|
||
|
b@4: (., [b-"b\x00") @1=foo)
|
||
|
c@3: (., [c-"c\x00") @1=foo UPDATED)
|
||
|
d@3: (., [d-"d\x00") @1=foo UPDATED)
|
||
|
.
|
||
|
d@1: (., [d-"d\x00") @1=foo UPDATED)
|
||
|
|
||
|
# Test the same semantics on a batch iterator.
|
||
|
|
||
|
iter iter=batchiter
|
||
|
seek-prefix-ge b@3
|
||
|
seek-prefix-ge b@4
|
||
|
seek-prefix-ge c@3
|
||
|
seek-prefix-ge d@3
|
||
|
set-options
|
||
|
seek-prefix-ge d@1
|
||
|
----
|
||
|
b@3: (., [b-"b\x00") @1=foo UPDATED)
|
||
|
b@4: (., [b-"b\x00") @1=foo)
|
||
|
c@3: (., [c-"c\x00") @1=foo UPDATED)
|
||
|
d@3: (., [d-"d\x00") @1=foo UPDATED)
|
||
|
.
|
||
|
d@1: (., [d-"d\x00") @1=foo UPDATED)
|
||
|
|
||
|
# Test mutating the indexed batch's range keys, overlapping the existing seek
|
||
|
# position. It should not see the new mutations, but after a call to SetOptions
|
||
|
# it should AND it should return RangeKeyChanged()=true.
|
||
|
|
||
|
mutate
|
||
|
range-key-set d e @2 foo
|
||
|
----
|
||
|
|
||
|
iter iter=batchiter
|
||
|
seek-prefix-ge d@2
|
||
|
set-options
|
||
|
seek-prefix-ge d@2
|
||
|
----
|
||
|
d@2: (., [d-"d\x00") @1=foo)
|
||
|
.
|
||
|
d@2: (., [d-"d\x00") @2=foo, @1=foo UPDATED)
|
||
|
|
||
|
# Test cloning an iterator with a range-key mask block property filter
|
||
|
# configured. If the cloned and the clonee iterators have different suffixes
|
||
|
# configured, their suffixes should be respected. Previously, the
|
||
|
# RangeKeyMasking.Filter option was a footgun, because it was a single mutable
|
||
|
# instance. Cloning the iterator without supplying new iterator options would
|
||
|
# result in two iterators using the same filter.
|
||
|
|
||
|
reset
|
||
|
----
|
||
|
|
||
|
batch
|
||
|
range-key-set a e @5 foo
|
||
|
set b@4 b@4
|
||
|
----
|
||
|
|
||
|
new-db-iter iter-a
|
||
|
----
|
||
|
|
||
|
iter iter=iter-a
|
||
|
set-options mask-suffix=@3 mask-filter=true
|
||
|
seek-ge a
|
||
|
next
|
||
|
next
|
||
|
----
|
||
|
.
|
||
|
a: (., [a-e) @5=foo UPDATED)
|
||
|
b@4: (b@4, [a-e) @5=foo)
|
||
|
.
|
||
|
|
||
|
clone from=iter-a to=iter-b refresh-batch=false
|
||
|
----
|
||
|
|
||
|
iter iter=iter-b
|
||
|
set-options mask-suffix=@6
|
||
|
seek-ge a
|
||
|
next
|
||
|
----
|
||
|
.
|
||
|
a: (., [a-e) @5=foo UPDATED)
|
||
|
.
|
||
|
|
||
|
iter iter=iter-a
|
||
|
seek-ge a
|
||
|
next
|
||
|
next
|
||
|
----
|
||
|
a: (., [a-e) @5=foo UPDATED)
|
||
|
b@4: (b@4, [a-e) @5=foo)
|
||
|
.
|