Skip to content

Commit

Permalink
db: cancel compactions that overlap with flushable ingest+excise
Browse files Browse the repository at this point in the history
This change addresses the case where an excise that was
ingested as a flushable needs to cancel any compactions that
have boundary overlap with the excise, but no inputs of that
compaction overlap with the excise.

Informs cockroachdb/cockroach#121263.
  • Loading branch information
itsbilal committed Apr 1, 2024
1 parent a306d7e commit 295c009
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 4 deletions.
18 changes: 15 additions & 3 deletions compaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -1722,12 +1722,24 @@ func (d *DB) flush1() (bytesFlushed uint64, err error) {
}
} else if len(ve.DeletedFiles) > 0 {
// c.kind == compactionKindIngestedFlushable && we have deleted files due
// to ingest-time splits.
// to ingest-time splits or excises.
//
// Iterate through all other compactions, and check if their inputs have
// been replaced due to an ingest-time split. In that case, cancel the
// compaction.
// been replaced due to an ingest-time split or excise. In that case,
// cancel the compaction.
ingestFlushable := c.flushing[0].flushable.(*ingestedFlushable)
for c2 := range d.mu.compact.inProgress {
// Check if this compaction overlaps with the excise span. Note that just
// checking if the inputs individually overlap with the excise span
// isn't sufficient; for instance, a compaction could have [a,b] and [e,f]
// as inputs and write it all out as [a,b,e,f] in one sstable. If we're
// doing a [c,d) excise at the same time as this compaction, we will have
// to error out the whole compaction as we can't guarantee it hasn't/won't
// write a file overlapping with the excise span.
if ingestFlushable.exciseSpan.OverlapsInternalKeyRange(d.cmp, c2.smallest, c2.largest) {
c2.cancel.Store(true)
continue
}
for i := range c2.inputs {
iter := c2.inputs[i].files.Iter()
for f := iter.First(); f != nil; f = iter.Next() {
Expand Down
9 changes: 8 additions & 1 deletion ingest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1417,7 +1417,6 @@ func TestConcurrentExcise(t *testing.T) {
require.NoError(t, mem2.MkdirAll("ext", 0755))
opts1 := &Options{
Comparer: testkeys.Comparer,
LBaseMaxBytes: 1,
FS: mem1,
L0CompactionThreshold: 100,
L0StopWritesThreshold: 100,
Expand All @@ -1437,6 +1436,7 @@ func TestConcurrentExcise(t *testing.T) {
// Disable automatic compactions because otherwise we'll race with
// delete-only compactions triggered by ingesting range tombstones.
opts1.DisableAutomaticCompactions = true
opts1.Experimental.MultiLevelCompactionHeuristic = NoMultiLevel{}

opts2 := &Options{}
*opts2 = *opts1
Expand Down Expand Up @@ -1512,6 +1512,9 @@ func TestConcurrentExcise(t *testing.T) {
return ""

case "ingest-and-excise":
d.mu.Lock()
prevFlushableIngests := d.mu.versions.metrics.Flush.AsIngestCount
d.mu.Unlock()
if err := runIngestAndExciseCmd(td, d, d.opts.FS); err != nil {
return err.Error()
}
Expand All @@ -1520,7 +1523,11 @@ func TestConcurrentExcise(t *testing.T) {
for d.mu.compact.flushing {
d.mu.compact.cond.Wait()
}
flushableIngests := d.mu.versions.metrics.Flush.AsIngestCount
d.mu.Unlock()
if prevFlushableIngests < flushableIngests {
return "flushable ingest"
}
return ""

case "replicate":
Expand Down
116 changes: 116 additions & 0 deletions testdata/concurrent_excise
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,119 @@ d: (something, .)
dd: (memory, .)
e: (bar, .)
.


reset
----

switch 1
----
ok

batch
set a bar
----

flush
----

compact a-z
----
ok

build ext6
set e foo
----

ingest ext6
----

lsm
----
L6:
000005:[a#10,SET-a#10,SET]
000006:[e#11,SET-e#11,SET]

batch
set a new
----

flush
----

batch
set d new
set e new
----

flush
----

lsm
----
L0.0:
000008:[a#12,SET-a#12,SET]
000010:[d#13,SET-e#14,SET]
L6:
000005:[a#10,SET-a#10,SET]
000006:[e#11,SET-e#11,SET]

build ext5
set bb something
set b something
del b-c
----

lsm
----
L0.0:
000008:[a#12,SET-a#12,SET]
000010:[d#13,SET-e#14,SET]
L6:
000005:[a#10,SET-a#10,SET]
000006:[e#11,SET-e#11,SET]

compact a-e block=c1
----
spun off in separate goroutine

batch
set bb new
----

lsm
----
L0.0:
000008:[a#12,SET-a#12,SET]
000010:[d#13,SET-e#14,SET]
L6:
000005:[a#10,SET-a#10,SET]
000006:[e#11,SET-e#11,SET]

ingest-and-excise ext5 excise=b-c contains-excise-tombstone
----
flushable ingest

lsm
----
L0.0:
000008:[a#12,SET-a#12,SET]
000010:[d#13,SET-e#14,SET]
L6:
000005:[a#10,SET-a#10,SET]
000012:[b#16,SET-bb#16,SET]
000006:[e#11,SET-e#11,SET]

unblock c1
----
ok

lsm
----
L0.0:
000008:[a#12,SET-a#12,SET]
000010:[d#13,SET-e#14,SET]
L6:
000005:[a#10,SET-a#10,SET]
000012:[b#16,SET-bb#16,SET]
000006:[e#11,SET-e#11,SET]

0 comments on commit 295c009

Please sign in to comment.