Skip to content

Commit 445410d

Browse files
craig[bot]iskettaneh
andcommitted
Merge #143334
143334: kvserver: add kv excise command r=iskettaneh a=iskettaneh kvserver: add kv excise command This commit adds a KV command called Excise, which ends up calling Pebble's excise command. The command deletes all the data overlapping with the provided key span. This command will be used by the OnlineRestore job to clean up the state where an external SSTable is pointing to a deleted file. These are the remaining items: 1. Perform split operations after the file is removed. 2. Add more detailed Rangefeed/Changefeed tests. 3. Add a test to excise part of the deleted span only (after cockroachdb/pebble#4417 is fixed) 4. Understand if merges require to read the SSTable if the range contains estimates. 5. Add a small test to verify that SSTables aren't read during writeBatch commit. 6. Defensive patches: Handle FileNotFound error from code locations that didn't fail in tests, but that could in theory fail under some circumstances. References: #143135 Release note: None Co-authored-by: Ibrahim Kettaneh <[email protected]>
2 parents dc53d9e + 91dffdc commit 445410d

File tree

16 files changed

+968
-5
lines changed

16 files changed

+968
-5
lines changed

docs/generated/metrics/metrics.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,7 @@
641641
<tr><td>STORAGE</td><td>rpc.method.delete.recv</td><td>Number of Delete requests processed</td><td>RPCs</td><td>COUNTER</td><td>COUNT</td><td>AVG</td><td>NON_NEGATIVE_DERIVATIVE</td></tr>
642642
<tr><td>STORAGE</td><td>rpc.method.deleterange.recv</td><td>Number of DeleteRange requests processed</td><td>RPCs</td><td>COUNTER</td><td>COUNT</td><td>AVG</td><td>NON_NEGATIVE_DERIVATIVE</td></tr>
643643
<tr><td>STORAGE</td><td>rpc.method.endtxn.recv</td><td>Number of EndTxn requests processed</td><td>RPCs</td><td>COUNTER</td><td>COUNT</td><td>AVG</td><td>NON_NEGATIVE_DERIVATIVE</td></tr>
644+
<tr><td>STORAGE</td><td>rpc.method.excise.recv</td><td>Number of Excise requests processed</td><td>RPCs</td><td>COUNTER</td><td>COUNT</td><td>AVG</td><td>NON_NEGATIVE_DERIVATIVE</td></tr>
644645
<tr><td>STORAGE</td><td>rpc.method.export.recv</td><td>Number of Export requests processed</td><td>RPCs</td><td>COUNTER</td><td>COUNT</td><td>AVG</td><td>NON_NEGATIVE_DERIVATIVE</td></tr>
645646
<tr><td>STORAGE</td><td>rpc.method.gc.recv</td><td>Number of GC requests processed</td><td>RPCs</td><td>COUNTER</td><td>COUNT</td><td>AVG</td><td>NON_NEGATIVE_DERIVATIVE</td></tr>
646647
<tr><td>STORAGE</td><td>rpc.method.get.recv</td><td>Number of Get requests processed</td><td>RPCs</td><td>COUNTER</td><td>COUNT</td><td>AVG</td><td>NON_NEGATIVE_DERIVATIVE</td></tr>
@@ -1105,6 +1106,7 @@
11051106
<tr><td>APPLICATION</td><td>distsender.rpc.err.unsupportedrequesterrtype</td><td>Number of UnsupportedRequestErrType errors received replica-bound RPCs<br/><br/>This counts how often error of the specified type was received back from replicas<br/>as part of executing possibly range-spanning requests. Failures to reach the target<br/>replica will be accounted for as &#39;roachpb.CommunicationErrType&#39; and unclassified<br/>errors as &#39;roachpb.InternalErrType&#39;.<br/></td><td>Errors</td><td>COUNTER</td><td>COUNT</td><td>AVG</td><td>NON_NEGATIVE_DERIVATIVE</td></tr>
11061107
<tr><td>APPLICATION</td><td>distsender.rpc.err.writeintenterrtype</td><td>Number of WriteIntentErrType errors received replica-bound RPCs<br/><br/>This counts how often error of the specified type was received back from replicas<br/>as part of executing possibly range-spanning requests. Failures to reach the target<br/>replica will be accounted for as &#39;roachpb.CommunicationErrType&#39; and unclassified<br/>errors as &#39;roachpb.InternalErrType&#39;.<br/></td><td>Errors</td><td>COUNTER</td><td>COUNT</td><td>AVG</td><td>NON_NEGATIVE_DERIVATIVE</td></tr>
11071108
<tr><td>APPLICATION</td><td>distsender.rpc.err.writetooolderrtype</td><td>Number of WriteTooOldErrType errors received replica-bound RPCs<br/><br/>This counts how often error of the specified type was received back from replicas<br/>as part of executing possibly range-spanning requests. Failures to reach the target<br/>replica will be accounted for as &#39;roachpb.CommunicationErrType&#39; and unclassified<br/>errors as &#39;roachpb.InternalErrType&#39;.<br/></td><td>Errors</td><td>COUNTER</td><td>COUNT</td><td>AVG</td><td>NON_NEGATIVE_DERIVATIVE</td></tr>
1109+
<tr><td>APPLICATION</td><td>distsender.rpc.excise.sent</td><td>Number of Excise requests processed.<br/><br/>This counts the requests in batches handed to DistSender, not the RPCs<br/>sent to individual Ranges as a result.</td><td>RPCs</td><td>COUNTER</td><td>COUNT</td><td>AVG</td><td>NON_NEGATIVE_DERIVATIVE</td></tr>
11081110
<tr><td>APPLICATION</td><td>distsender.rpc.export.sent</td><td>Number of Export requests processed.<br/><br/>This counts the requests in batches handed to DistSender, not the RPCs<br/>sent to individual Ranges as a result.</td><td>RPCs</td><td>COUNTER</td><td>COUNT</td><td>AVG</td><td>NON_NEGATIVE_DERIVATIVE</td></tr>
11091111
<tr><td>APPLICATION</td><td>distsender.rpc.gc.sent</td><td>Number of GC requests processed.<br/><br/>This counts the requests in batches handed to DistSender, not the RPCs<br/>sent to individual Ranges as a result.</td><td>RPCs</td><td>COUNTER</td><td>COUNT</td><td>AVG</td><td>NON_NEGATIVE_DERIVATIVE</td></tr>
11101112
<tr><td>APPLICATION</td><td>distsender.rpc.get.sent</td><td>Number of Get requests processed.<br/><br/>This counts the requests in batches handed to DistSender, not the RPCs<br/>sent to individual Ranges as a result.</td><td>RPCs</td><td>COUNTER</td><td>COUNT</td><td>AVG</td><td>NON_NEGATIVE_DERIVATIVE</td></tr>

pkg/kv/batch.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ func (b *Batch) fillResults(ctx context.Context) {
301301
case *kvpb.QueryResolvedTimestampRequest:
302302
case *kvpb.BarrierRequest:
303303
case *kvpb.LinkExternalSSTableRequest:
304+
case *kvpb.ExciseRequest:
304305
default:
305306
if result.Err == nil {
306307
result.Err = errors.Errorf("unsupported reply: %T for %T",

pkg/kv/kvpb/api.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,19 @@ func (r *IsSpanEmptyResponse) combine(_ context.Context, c combinable, _ *BatchR
720720

721721
var _ combinable = &IsSpanEmptyResponse{}
722722

723+
// combine implements the combinable interface.
724+
func (r *ExciseResponse) combine(_ context.Context, c combinable, _ *BatchRequest) error {
725+
otherDR := c.(*ExciseResponse)
726+
if r != nil {
727+
if err := r.ResponseHeader.combine(otherDR.Header()); err != nil {
728+
return err
729+
}
730+
}
731+
return nil
732+
}
733+
734+
var _ combinable = &ExciseResponse{}
735+
723736
// Header implements the Request interface.
724737
func (rh RequestHeader) Header() RequestHeader {
725738
return rh
@@ -970,6 +983,9 @@ func (*AddSSTableRequest) Method() Method { return AddSSTable }
970983
// Method implements the Request interface.
971984
func (*LinkExternalSSTableRequest) Method() Method { return LinkExternalSSTable }
972985

986+
// Method implements the Request interface.
987+
func (*ExciseRequest) Method() Method { return Excise }
988+
973989
// Method implements the Request interface.
974990
func (*MigrateRequest) Method() Method { return Migrate }
975991

@@ -1236,6 +1252,12 @@ func (r *LinkExternalSSTableRequest) ShallowCopy() Request {
12361252
return &shallowCopy
12371253
}
12381254

1255+
// ShallowCopy implements the Request interface.
1256+
func (r *ExciseRequest) ShallowCopy() Request {
1257+
shallowCopy := *r
1258+
return &shallowCopy
1259+
}
1260+
12391261
// ShallowCopy implements the Request interface.
12401262
func (r *MigrateRequest) ShallowCopy() Request {
12411263
shallowCopy := *r
@@ -1528,6 +1550,12 @@ func (r *LinkExternalSSTableResponse) ShallowCopy() Response {
15281550
return &shallowCopy
15291551
}
15301552

1553+
// ShallowCopy implements the Response interface.
1554+
func (r *ExciseResponse) ShallowCopy() Response {
1555+
shallowCopy := *r
1556+
return &shallowCopy
1557+
}
1558+
15311559
// ShallowCopy implements the Response interface.
15321560
func (r *MigrateResponse) ShallowCopy() Response {
15331561
shallowCopy := *r
@@ -2100,6 +2128,11 @@ func (r *LinkExternalSSTableRequest) flags() flag {
21002128
}
21012129
return flags
21022130
}
2131+
2132+
func (r *ExciseRequest) flags() flag {
2133+
return isWrite | isRange | isAlone | bypassesReplicaCircuitBreaker
2134+
}
2135+
21032136
func (*MigrateRequest) flags() flag { return isWrite | isRange | isAlone }
21042137

21052138
// RefreshRequest and RefreshRangeRequest both determine which timestamp cache

pkg/kv/kvpb/api.proto

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,25 @@ message ScanResponse {
698698
ColBatches col_batches = 5 [(gogoproto.nullable) = false];
699699
}
700700

701+
// ExciseRequest is the argument to the Excise() method, which ends up calling
702+
// the storage Excise() method. It is used to atomically remove all data in the
703+
// specified key span.
704+
// It's used as a recovery tool in the event of data loss. It's a non-MVCC
705+
// command that will destroy MVCC history, and can result in transactional
706+
// anomalies like lost portions of transactions, uncommiting committed
707+
// transactions, and possible other anomalies. It allows for inconsistent
708+
// follower reads.
709+
// It can not be applied to non-user spans.
710+
message ExciseRequest {
711+
reserved 2, 3;
712+
RequestHeader header = 1 [(gogoproto.nullable) = false, (gogoproto.embed) = true];
713+
}
714+
715+
// ExciseResponse is the return value from the Excise() method.
716+
message ExciseResponse {
717+
ResponseHeader header = 1 [(gogoproto.nullable) = false, (gogoproto.embed) = true];
718+
}
719+
701720
// A ReverseScanRequest is the argument to the ReverseScan() method. It specifies the
702721
// start and end keys for a descending scan of [start,end) and the maximum
703722
// number of results (unbounded if zero).
@@ -2536,6 +2555,7 @@ message RequestUnion {
25362555
ProbeRequest probe = 54;
25372556
IsSpanEmptyRequest is_span_empty = 56;
25382557
LinkExternalSSTableRequest link_external_sstable = 57;
2558+
ExciseRequest excise = 58;
25392559
}
25402560
reserved 8, 15, 23, 25, 27, 31, 34, 52;
25412561
}
@@ -2592,6 +2612,7 @@ message ResponseUnion {
25922612
ProbeResponse probe = 54;
25932613
IsSpanEmptyResponse is_span_empty = 56;
25942614
LinkExternalSSTableResponse link_external_sstable = 57;
2615+
ExciseResponse excise = 58;
25952616
}
25962617
reserved 8, 15, 23, 25, 27, 28, 31, 34, 52;
25972618
}

pkg/kv/kvpb/batch_generated.go

Lines changed: 26 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/kv/kvpb/method.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,9 @@ const (
171171
// IsSpanEmpty is a non-transaction read request used to determine whether
172172
// a span contains any keys whatsoever (garbage or otherwise).
173173
IsSpanEmpty
174+
// Excise is a non-MVCC command that destroys all data in a user MVCC key
175+
// span. See ExciseRequest for details.
176+
Excise
174177
// MaxMethod is the maximum method.
175178
MaxMethod Method = iota - 1
176179
// NumMethods represents the total number of API methods.

pkg/kv/kvpb/method_string.go

Lines changed: 8 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/kv/kvserver/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,7 @@ go_test(
306306
"closed_timestamp_test.go",
307307
"consistency_queue_test.go",
308308
"debug_print_test.go",
309+
"deleted_external_sstable_test.go",
309310
"errors_test.go",
310311
"flow_control_integration_test.go",
311312
"flow_control_raft_transport_test.go",

pkg/kv/kvserver/app_batch.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,5 +198,15 @@ func (b *appBatch) runPostAddTriggers(
198198
cmd.Index(),
199199
*res.LinkExternalSSTable)
200200
}
201+
202+
if res.Excise != nil {
203+
if err := env.eng.Excise(ctx, res.Excise.Span); err != nil {
204+
return errors.Wrapf(err, "error while excising span: %v", res.Excise.Span)
205+
}
206+
if err := env.eng.Excise(ctx, res.Excise.LockTableSpan); err != nil {
207+
return errors.Wrapf(err, "error while excising span: %v", res.Excise.LockTableSpan)
208+
}
209+
}
210+
201211
return nil
202212
}

pkg/kv/kvserver/batcheval/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ go_library(
1111
"cmd_delete.go",
1212
"cmd_delete_range.go",
1313
"cmd_end_transaction.go",
14+
"cmd_excise.go",
1415
"cmd_export.go",
1516
"cmd_gc.go",
1617
"cmd_get.go",

0 commit comments

Comments
 (0)