github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/ccl/utilccl/sampledataccl/bankdata.go (about) 1 // Copyright 2017 The Cockroach Authors. 2 // 3 // Licensed as a CockroachDB Enterprise file under the Cockroach Community 4 // License (the "License"); you may not use this file except in compliance with 5 // the License. You may obtain a copy of the License at 6 // 7 // https://github.com/cockroachdb/cockroach/blob/master/licenses/CCL.txt 8 9 package sampledataccl 10 11 import ( 12 "bytes" 13 "context" 14 "fmt" 15 "io" 16 "io/ioutil" 17 "path/filepath" 18 "strings" 19 "testing" 20 21 "github.com/cockroachdb/cockroach/pkg/base" 22 "github.com/cockroachdb/cockroach/pkg/ccl/backupccl" 23 "github.com/cockroachdb/cockroach/pkg/ccl/importccl" 24 "github.com/cockroachdb/cockroach/pkg/ccl/storageccl" 25 "github.com/cockroachdb/cockroach/pkg/keys" 26 "github.com/cockroachdb/cockroach/pkg/roachpb" 27 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 28 "github.com/cockroachdb/cockroach/pkg/storage" 29 "github.com/cockroachdb/cockroach/pkg/testutils" 30 "github.com/cockroachdb/cockroach/pkg/testutils/serverutils" 31 "github.com/cockroachdb/cockroach/pkg/util/hlc" 32 "github.com/cockroachdb/cockroach/pkg/workload" 33 "github.com/cockroachdb/cockroach/pkg/workload/workloadsql" 34 "github.com/cockroachdb/errors" 35 ) 36 37 // ToBackup creates an enterprise backup in `dir`. 38 func ToBackup(t testing.TB, data workload.Table, dir string) (*Backup, error) { 39 return toBackup(t, data, dir, 0) 40 } 41 42 func toBackup(t testing.TB, data workload.Table, dir string, chunkBytes int64) (*Backup, error) { 43 tempDir, dirCleanupFn := testutils.TempDir(t) 44 defer dirCleanupFn() 45 46 // TODO(dan): Get rid of the `t testing.TB` parameter and this `TestServer`. 47 ctx := context.Background() 48 s, db, _ := serverutils.StartServer(t, base.TestServerArgs{}) 49 defer s.Stopper().Stop(ctx) 50 if _, err := db.Exec(`CREATE DATABASE data`); err != nil { 51 return nil, err 52 } 53 54 var stmts bytes.Buffer 55 fmt.Fprintf(&stmts, "CREATE TABLE %s %s;\n", data.Name, data.Schema) 56 for rowIdx := 0; rowIdx < data.InitialRows.NumBatches; rowIdx++ { 57 for _, row := range data.InitialRows.BatchRows(rowIdx) { 58 rowBatch := strings.Join(workloadsql.StringTuple(row), `,`) 59 fmt.Fprintf(&stmts, "INSERT INTO %s VALUES (%s);\n", data.Name, rowBatch) 60 } 61 } 62 63 // TODO(dan): The csv load will be less overhead, use it when we have it. 64 ts := hlc.Timestamp{WallTime: hlc.UnixNano()} 65 desc, err := importccl.Load(ctx, db, &stmts, `data`, `nodelocal://0/`, ts, chunkBytes, tempDir, dir) 66 if err != nil { 67 return nil, err 68 } 69 return &Backup{BaseDir: dir, Desc: desc}, nil 70 } 71 72 // Backup is a representation of an enterprise BACKUP. 73 type Backup struct { 74 // BaseDir can be used for a RESTORE. All paths in the descriptor are 75 // relative to this. 76 BaseDir string 77 Desc backupccl.BackupManifest 78 79 fileIdx int 80 iterIdx int 81 } 82 83 // ResetKeyValueIteration resets the NextKeyValues iteration to the first kv. 84 func (b *Backup) ResetKeyValueIteration() { 85 b.fileIdx = 0 86 b.iterIdx = 0 87 } 88 89 // NextKeyValues iterates and returns every *user table data* key-value in the 90 // backup. At least `count` kvs will be returned, but rows are not broken up, so 91 // slightly more than `count` may come back. If fewer than `count` are 92 // available, err will be `io.EOF` and kvs may be partially filled with the 93 // remainer. 94 func (b *Backup) NextKeyValues( 95 count int, newTableID sqlbase.ID, 96 ) ([]storage.MVCCKeyValue, roachpb.Span, error) { 97 var userTables []*sqlbase.TableDescriptor 98 for _, d := range b.Desc.Descriptors { 99 if t := d.Table(hlc.Timestamp{}); t != nil && t.ParentID != keys.SystemDatabaseID { 100 userTables = append(userTables, t) 101 } 102 } 103 if len(userTables) != 1 { 104 return nil, roachpb.Span{}, errors.Errorf( 105 "only backups of one table are currently supported, got %d", len(userTables)) 106 } 107 tableDesc := userTables[0] 108 109 newDesc := *tableDesc 110 newDesc.ID = newTableID 111 kr, err := storageccl.MakeKeyRewriter(sqlbase.TablesByID{tableDesc.ID: &newDesc}) 112 if err != nil { 113 return nil, roachpb.Span{}, err 114 } 115 116 var kvs []storage.MVCCKeyValue 117 span := roachpb.Span{Key: keys.MaxKey} 118 for ; b.fileIdx < len(b.Desc.Files); b.fileIdx++ { 119 file := b.Desc.Files[b.fileIdx] 120 121 sst := storage.MakeRocksDBSstFileReader() 122 defer sst.Close() 123 fileContents, err := ioutil.ReadFile(filepath.Join(b.BaseDir, file.Path)) 124 if err != nil { 125 return nil, roachpb.Span{}, err 126 } 127 if err := sst.IngestExternalFile(fileContents); err != nil { 128 return nil, roachpb.Span{}, err 129 } 130 131 it := sst.NewIterator(storage.IterOptions{UpperBound: roachpb.KeyMax}) 132 defer it.Close() 133 it.SeekGE(storage.MVCCKey{Key: file.Span.Key}) 134 135 iterIdx := 0 136 for ; ; it.Next() { 137 if len(kvs) >= count { 138 break 139 } 140 if iterIdx < b.iterIdx { 141 iterIdx++ 142 continue 143 } 144 145 ok, err := it.Valid() 146 if err != nil { 147 return nil, roachpb.Span{}, err 148 } 149 if !ok || it.UnsafeKey().Key.Compare(file.Span.EndKey) >= 0 { 150 break 151 } 152 153 if iterIdx < b.iterIdx { 154 break 155 } 156 b.iterIdx = iterIdx 157 158 key := it.Key() 159 key.Key, ok, err = kr.RewriteKey(key.Key, false /* isFromSpan */) 160 if err != nil { 161 return nil, roachpb.Span{}, err 162 } 163 if !ok { 164 return nil, roachpb.Span{}, errors.Errorf("rewriter did not match key: %s", key.Key) 165 } 166 v := roachpb.Value{RawBytes: it.Value()} 167 v.ClearChecksum() 168 v.InitChecksum(key.Key) 169 kvs = append(kvs, storage.MVCCKeyValue{Key: key, Value: v.RawBytes}) 170 171 if key.Key.Compare(span.Key) < 0 { 172 span.Key = append(span.Key[:0], key.Key...) 173 } 174 if key.Key.Compare(span.EndKey) > 0 { 175 span.EndKey = append(span.EndKey[:0], key.Key...) 176 } 177 iterIdx++ 178 } 179 b.iterIdx = iterIdx 180 181 if len(kvs) >= count { 182 break 183 } 184 if ok, _ := it.Valid(); !ok { 185 b.iterIdx = 0 186 } 187 } 188 189 span.EndKey = span.EndKey.Next() 190 if len(kvs) < count { 191 return kvs, span, io.EOF 192 } 193 return kvs, span, nil 194 }