github.com/zuoyebang/bitalostable@v1.0.1-0.20240229032404-e3b99a834294/sstable/data_test.go (about) 1 // Copyright 2019 The LevelDB-Go and Pebble Authors. All rights reserved. Use 2 // of this source code is governed by a BSD-style license that can be found in 3 // the LICENSE file. 4 5 package sstable 6 7 import ( 8 "bytes" 9 "fmt" 10 "io" 11 "strconv" 12 "strings" 13 14 "github.com/cockroachdb/errors" 15 "github.com/zuoyebang/bitalostable/bloom" 16 "github.com/zuoyebang/bitalostable/internal/base" 17 "github.com/zuoyebang/bitalostable/internal/cache" 18 "github.com/zuoyebang/bitalostable/internal/datadriven" 19 "github.com/zuoyebang/bitalostable/internal/keyspan" 20 "github.com/zuoyebang/bitalostable/vfs" 21 ) 22 23 func optsFromArgs(td *datadriven.TestData, writerOpts *WriterOptions) error { 24 for _, arg := range td.CmdArgs { 25 switch arg.Key { 26 case "leveldb": 27 if len(arg.Vals) != 0 { 28 return errors.Errorf("%s: arg %s expects 0 values", td.Cmd, arg.Key) 29 } 30 writerOpts.TableFormat = TableFormatLevelDB 31 case "block-size": 32 if len(arg.Vals) != 1 { 33 return errors.Errorf("%s: arg %s expects 1 value", td.Cmd, arg.Key) 34 } 35 var err error 36 writerOpts.BlockSize, err = strconv.Atoi(arg.Vals[0]) 37 if err != nil { 38 return err 39 } 40 case "index-block-size": 41 if len(arg.Vals) != 1 { 42 return errors.Errorf("%s: arg %s expects 1 value", td.Cmd, arg.Key) 43 } 44 var err error 45 writerOpts.IndexBlockSize, err = strconv.Atoi(arg.Vals[0]) 46 if err != nil { 47 return err 48 } 49 case "filter": 50 writerOpts.FilterPolicy = bloom.FilterPolicy(10) 51 case "comparer-split-4b-suffix": 52 writerOpts.Comparer = test4bSuffixComparer 53 } 54 } 55 return nil 56 } 57 58 func runBuildCmd( 59 td *datadriven.TestData, writerOpts *WriterOptions, cacheSize int, 60 ) (*WriterMetadata, *Reader, error) { 61 62 f0 := &memFile{} 63 if err := optsFromArgs(td, writerOpts); err != nil { 64 return nil, nil, err 65 } 66 67 w := NewWriter(f0, *writerOpts) 68 var rangeDels []keyspan.Span 69 rangeDelFrag := keyspan.Fragmenter{ 70 Cmp: DefaultComparer.Compare, 71 Format: DefaultComparer.FormatKey, 72 Emit: func(s keyspan.Span) { 73 rangeDels = append(rangeDels, s) 74 }, 75 } 76 var rangeKeys []keyspan.Span 77 rangeKeyFrag := keyspan.Fragmenter{ 78 Cmp: DefaultComparer.Compare, 79 Format: DefaultComparer.FormatKey, 80 Emit: func(s keyspan.Span) { 81 rangeKeys = append(rangeKeys, s) 82 }, 83 } 84 for _, data := range strings.Split(td.Input, "\n") { 85 if strings.HasPrefix(data, "rangekey:") { 86 var err error 87 func() { 88 defer func() { 89 if r := recover(); r != nil { 90 err = errors.Errorf("%v", r) 91 } 92 }() 93 rangeKeyFrag.Add(keyspan.ParseSpan(strings.TrimPrefix(data, "rangekey:"))) 94 }() 95 if err != nil { 96 return nil, nil, err 97 } 98 continue 99 } 100 101 j := strings.Index(data, ":") 102 key := base.ParseInternalKey(data[:j]) 103 value := []byte(data[j+1:]) 104 switch key.Kind() { 105 case InternalKeyKindRangeDelete: 106 var err error 107 func() { 108 defer func() { 109 if r := recover(); r != nil { 110 err = errors.Errorf("%v", r) 111 } 112 }() 113 rangeDelFrag.Add(keyspan.Span{ 114 Start: key.UserKey, 115 End: value, 116 Keys: []keyspan.Key{{Trailer: key.Trailer}}, 117 }) 118 }() 119 if err != nil { 120 return nil, nil, err 121 } 122 default: 123 if err := w.Add(key, value); err != nil { 124 return nil, nil, err 125 } 126 } 127 } 128 rangeDelFrag.Finish() 129 for _, v := range rangeDels { 130 for _, k := range v.Keys { 131 ik := base.InternalKey{UserKey: v.Start, Trailer: k.Trailer} 132 if err := w.Add(ik, v.End); err != nil { 133 return nil, nil, err 134 } 135 } 136 } 137 rangeKeyFrag.Finish() 138 for _, s := range rangeKeys { 139 if err := w.addRangeKeySpan(s); err != nil { 140 return nil, nil, err 141 } 142 } 143 if err := w.Close(); err != nil { 144 return nil, nil, err 145 } 146 meta, err := w.Metadata() 147 if err != nil { 148 return nil, nil, err 149 } 150 151 readerOpts := ReaderOptions{Comparer: writerOpts.Comparer} 152 if writerOpts.FilterPolicy != nil { 153 readerOpts.Filters = map[string]FilterPolicy{ 154 writerOpts.FilterPolicy.Name(): writerOpts.FilterPolicy, 155 } 156 } 157 if cacheSize > 0 { 158 readerOpts.Cache = cache.New(int64(cacheSize)) 159 defer readerOpts.Cache.Unref() 160 } 161 r, err := NewMemReader(f0.Data(), readerOpts) 162 if err != nil { 163 return nil, nil, err 164 } 165 return meta, r, nil 166 } 167 168 func runBuildRawCmd( 169 td *datadriven.TestData, opts *WriterOptions, 170 ) (*WriterMetadata, *Reader, error) { 171 mem := vfs.NewMem() 172 f0, err := mem.Create("test") 173 if err != nil { 174 return nil, nil, err 175 } 176 177 w := NewWriter(f0, *opts) 178 for i := range td.CmdArgs { 179 arg := &td.CmdArgs[i] 180 if arg.Key == "range-del-v1" { 181 w.rangeDelV1Format = true 182 break 183 } 184 } 185 186 for _, data := range strings.Split(td.Input, "\n") { 187 if strings.HasPrefix(data, "rangekey:") { 188 data = strings.TrimPrefix(data, "rangekey:") 189 if err := w.addRangeKeySpan(keyspan.ParseSpan(data)); err != nil { 190 return nil, nil, err 191 } 192 continue 193 } 194 195 j := strings.Index(data, ":") 196 key := base.ParseInternalKey(data[:j]) 197 value := []byte(data[j+1:]) 198 switch key.Kind() { 199 case base.InternalKeyKindRangeKeyDelete, 200 base.InternalKeyKindRangeKeyUnset, 201 base.InternalKeyKindRangeKeySet: 202 if err := w.AddRangeKey(key, value); err != nil { 203 return nil, nil, err 204 } 205 default: 206 if err := w.Add(key, value); err != nil { 207 return nil, nil, err 208 } 209 } 210 } 211 if err := w.Close(); err != nil { 212 return nil, nil, err 213 } 214 meta, err := w.Metadata() 215 if err != nil { 216 return nil, nil, err 217 } 218 219 f1, err := mem.Open("test") 220 if err != nil { 221 return nil, nil, err 222 } 223 r, err := NewReader(f1, ReaderOptions{}) 224 if err != nil { 225 return nil, nil, err 226 } 227 return meta, r, nil 228 } 229 230 func scanGlobalSeqNum(td *datadriven.TestData) (uint64, error) { 231 for _, arg := range td.CmdArgs { 232 switch arg.Key { 233 case "globalSeqNum": 234 if len(arg.Vals) != 1 { 235 return 0, errors.Errorf("%s: arg %s expects 1 value", td.Cmd, arg.Key) 236 } 237 v, err := strconv.Atoi(arg.Vals[0]) 238 if err != nil { 239 return 0, err 240 } 241 return uint64(v), nil 242 } 243 } 244 return 0, nil 245 } 246 247 type runIterCmdOption func(*runIterCmdOptions) 248 249 type runIterCmdOptions struct { 250 everyOp func(io.Writer) 251 everyOpAfter func(io.Writer) 252 stats *base.InternalIteratorStats 253 } 254 255 func runIterCmdEveryOp(everyOp func(io.Writer)) runIterCmdOption { 256 return func(opts *runIterCmdOptions) { opts.everyOp = everyOp } 257 } 258 259 func runIterCmdEveryOpAfter(everyOp func(io.Writer)) runIterCmdOption { 260 return func(opts *runIterCmdOptions) { opts.everyOpAfter = everyOp } 261 } 262 263 func runIterCmdStats(stats *base.InternalIteratorStats) runIterCmdOption { 264 return func(opts *runIterCmdOptions) { opts.stats = stats } 265 } 266 267 func runIterCmd(td *datadriven.TestData, origIter Iterator, opt ...runIterCmdOption) string { 268 var opts runIterCmdOptions 269 for _, o := range opt { 270 o(&opts) 271 } 272 273 iter := newIterAdapter(origIter) 274 defer iter.Close() 275 276 var b bytes.Buffer 277 var prefix []byte 278 for _, line := range strings.Split(td.Input, "\n") { 279 parts := strings.Fields(line) 280 if len(parts) == 0 { 281 continue 282 } 283 switch parts[0] { 284 case "seek-ge": 285 if len(parts) < 2 || len(parts) > 3 { 286 return "seek-ge <key> [<try-seek-using-next]\n" 287 } 288 prefix = nil 289 var flags base.SeekGEFlags 290 if len(parts) == 3 { 291 if trySeekUsingNext, err := strconv.ParseBool(parts[2]); err != nil { 292 return err.Error() 293 } else if trySeekUsingNext { 294 flags = flags.EnableTrySeekUsingNext() 295 } 296 } 297 iter.SeekGE([]byte(strings.TrimSpace(parts[1])), flags) 298 case "seek-prefix-ge": 299 if len(parts) != 2 && len(parts) != 3 { 300 return "seek-prefix-ge <key> [<try-seek-using-next>]\n" 301 } 302 prefix = []byte(strings.TrimSpace(parts[1])) 303 var flags base.SeekGEFlags 304 if len(parts) == 3 { 305 if trySeekUsingNext, err := strconv.ParseBool(parts[2]); err != nil { 306 return err.Error() 307 } else if trySeekUsingNext { 308 flags = flags.EnableTrySeekUsingNext() 309 } 310 } 311 iter.SeekPrefixGE(prefix, prefix /* key */, flags) 312 case "seek-lt": 313 if len(parts) != 2 { 314 return "seek-lt <key>\n" 315 } 316 prefix = nil 317 iter.SeekLT([]byte(strings.TrimSpace(parts[1])), base.SeekLTFlagsNone) 318 case "first": 319 prefix = nil 320 iter.First() 321 case "last": 322 prefix = nil 323 iter.Last() 324 case "next": 325 iter.Next() 326 case "next-ignore-result": 327 iter.NextIgnoreResult() 328 case "prev": 329 iter.Prev() 330 case "set-bounds": 331 if len(parts) <= 1 || len(parts) > 3 { 332 return "set-bounds lower=<lower> upper=<upper>\n" 333 } 334 var lower []byte 335 var upper []byte 336 for _, part := range parts[1:] { 337 arg := strings.Split(strings.TrimSpace(part), "=") 338 switch arg[0] { 339 case "lower": 340 lower = []byte(arg[1]) 341 if len(lower) == 0 { 342 lower = nil 343 } 344 case "upper": 345 upper = []byte(arg[1]) 346 if len(upper) == 0 { 347 upper = nil 348 } 349 default: 350 return fmt.Sprintf("set-bounds: unknown arg: %s", arg) 351 } 352 } 353 iter.SetBounds(lower, upper) 354 case "stats": 355 fmt.Fprintf(&b, "%+v\n", *opts.stats) 356 continue 357 case "reset-stats": 358 *opts.stats = base.InternalIteratorStats{} 359 continue 360 } 361 if opts.everyOp != nil { 362 opts.everyOp(&b) 363 } 364 if iter.Valid() && checkValidPrefix(prefix, iter.Key().UserKey) { 365 fmt.Fprintf(&b, "<%s:%d>", iter.Key().UserKey, iter.Key().SeqNum()) 366 } else if err := iter.Error(); err != nil { 367 fmt.Fprintf(&b, "<err=%v>", err) 368 } else { 369 fmt.Fprintf(&b, ".") 370 } 371 if opts.everyOpAfter != nil { 372 opts.everyOpAfter(&b) 373 } 374 b.WriteString("\n") 375 } 376 return b.String() 377 } 378 379 func runRewriteCmd( 380 td *datadriven.TestData, r *Reader, writerOpts WriterOptions, 381 ) (*WriterMetadata, *Reader, error) { 382 var from, to []byte 383 for _, arg := range td.CmdArgs { 384 switch arg.Key { 385 case "from": 386 from = []byte(arg.Vals[0]) 387 case "to": 388 to = []byte(arg.Vals[0]) 389 } 390 } 391 if from == nil || to == nil { 392 return nil, r, errors.New("missing from/to") 393 } 394 395 opts := writerOpts 396 if err := optsFromArgs(td, &opts); err != nil { 397 return nil, r, err 398 } 399 400 f := &memFile{} 401 meta, err := rewriteKeySuffixesInBlocks(r, f, opts, from, to, 2) 402 if err != nil { 403 return nil, r, errors.Wrap(err, "rewrite failed") 404 } 405 readerOpts := ReaderOptions{Comparer: opts.Comparer} 406 if opts.FilterPolicy != nil { 407 readerOpts.Filters = map[string]FilterPolicy{ 408 opts.FilterPolicy.Name(): opts.FilterPolicy, 409 } 410 } 411 r.Close() 412 413 r, err = NewMemReader(f.Data(), readerOpts) 414 if err != nil { 415 return nil, nil, err 416 } 417 return meta, r, nil 418 }