github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/revert.go (about) 1 // Copyright 2019 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package sql 12 13 import ( 14 "context" 15 16 "github.com/cockroachdb/cockroach/pkg/kv" 17 "github.com/cockroachdb/cockroach/pkg/roachpb" 18 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 19 "github.com/cockroachdb/cockroach/pkg/util/hlc" 20 "github.com/cockroachdb/cockroach/pkg/util/log" 21 "github.com/cockroachdb/errors" 22 ) 23 24 // RevertTableDefaultBatchSize is the default batch size for reverting tables. 25 // This only needs to be small enough to keep raft/rocks happy -- there is no 26 // reply size to worry about. 27 // TODO(dt): tune this via experimentation. 28 const RevertTableDefaultBatchSize = 500000 29 30 // RevertTables reverts the passed table to the target time. 31 func RevertTables( 32 ctx context.Context, 33 db *kv.DB, 34 execCfg *ExecutorConfig, 35 tables []*sqlbase.TableDescriptor, 36 targetTime hlc.Timestamp, 37 batchSize int64, 38 ) error { 39 reverting := make(map[sqlbase.ID]bool, len(tables)) 40 for i := range tables { 41 reverting[tables[i].ID] = true 42 } 43 44 spans := make([]roachpb.Span, 0, len(tables)) 45 46 // Check that all the tables are revertable -- i.e. offline and that their 47 // full interleave hierarchy is being reverted. 48 for i := range tables { 49 if tables[i].State != sqlbase.TableDescriptor_OFFLINE { 50 return errors.New("only offline tables can be reverted") 51 } 52 53 if !tables[i].IsPhysicalTable() { 54 return errors.Errorf("cannot revert virtual table %s", tables[i].Name) 55 } 56 for _, idx := range tables[i].AllNonDropIndexes() { 57 for _, parent := range idx.Interleave.Ancestors { 58 if !reverting[parent.TableID] { 59 return errors.New("cannot revert table without reverting all interleaved tables and indexes") 60 } 61 } 62 for _, child := range idx.InterleavedBy { 63 if !reverting[child.Table] { 64 return errors.New("cannot revert table without reverting all interleaved tables and indexes") 65 } 66 } 67 } 68 spans = append(spans, tables[i].TableSpan(execCfg.Codec)) 69 } 70 71 for i := range tables { 72 // This is a) rare and b) probably relevant if we are looking at logs so it 73 // probably makes sense to log it without a verbosity filter. 74 log.Infof(ctx, "reverting table %s (%d) to time %v", tables[i].Name, tables[i].ID, targetTime) 75 } 76 77 // TODO(dt): pre-split requests up using a rangedesc cache and run batches in 78 // parallel (since we're passing a key limit, distsender won't do its usual 79 // splitting/parallel sending to separate ranges). 80 for len(spans) != 0 { 81 var b kv.Batch 82 for _, span := range spans { 83 b.AddRawRequest(&roachpb.RevertRangeRequest{ 84 RequestHeader: roachpb.RequestHeader{ 85 Key: span.Key, 86 EndKey: span.EndKey, 87 }, 88 TargetTime: targetTime, 89 }) 90 } 91 b.Header.MaxSpanRequestKeys = batchSize 92 93 if err := db.Run(ctx, &b); err != nil { 94 return err 95 } 96 97 spans = spans[:0] 98 for _, raw := range b.RawResponse().Responses { 99 r := raw.GetRevertRange() 100 if r.ResumeSpan != nil { 101 if !r.ResumeSpan.Valid() { 102 return errors.Errorf("invalid resume span: %s", r.ResumeSpan) 103 } 104 spans = append(spans, *r.ResumeSpan) 105 } 106 } 107 } 108 109 return nil 110 }