diff --git a/internal/crdbtest/crdb.go b/internal/crdbtest/crdb.go index 4c0511550a..8dd99020ed 100644 --- a/internal/crdbtest/crdb.go +++ b/internal/crdbtest/crdb.go @@ -423,7 +423,7 @@ const ( // hasEmptySuffixes is set if there is at least one key with no suffix in the block. hasEmptySuffixes // hasNonMVCCSuffixes is set if there is at least one key with a non-empty, - // non-MVCC sufffix. + // non-MVCC suffix. hasNonMVCCSuffixes ) @@ -435,7 +435,7 @@ func (s suffixTypes) String() string { if s&hasEmptySuffixes != 0 { suffixes = append(suffixes, "empty") } - if s&hasEmptySuffixes != 0 { + if s&hasNonMVCCSuffixes != 0 { suffixes = append(suffixes, "non-mvcc") } if len(suffixes) == 0 { @@ -527,7 +527,7 @@ func (kw *cockroachKeyWriter) WriteKey( switch versionLen { case 0: // No-op. - kw.suffixTypes |= hasNonMVCCSuffixes + kw.suffixTypes |= hasEmptySuffixes case 9: kw.suffixTypes |= hasMVCCSuffixes wallTime = binary.BigEndian.Uint64(key[keyPrefixLen : keyPrefixLen+8]) @@ -539,7 +539,7 @@ func (kw *cockroachKeyWriter) WriteKey( // longer consulted and can be ignored during decoding. default: // Not a MVCC timestamp. - kw.suffixTypes |= hasEmptySuffixes + kw.suffixTypes |= hasNonMVCCSuffixes untypedVersion = key[keyPrefixLen:] } kw.wallTimes.Set(row, wallTime) @@ -731,7 +731,7 @@ func (ks *cockroachKeySeeker) seekGEOnSuffix(index int, seekSuffix []byte) (row for l < u { h := int(uint(l+u) >> 1) // avoid overflow when computing h // l ≤ h < u - if bytes.Compare(ks.untypedVersions.At(h), seekSuffix) >= 0 { + if bytes.Compare(ks.untypedVersions.At(h), seekSuffix) <= 0 { u = h // preserves f(u) == true } else { l = h + 1 // preserves f(l-1) == false @@ -774,6 +774,9 @@ func (ks *cockroachKeySeeker) seekGEOnSuffix(index int, seekSuffix []byte) (row func (ks *cockroachKeySeeker) MaterializeUserKey( ki *colblk.PrefixBytesIter, prevRow, row int, ) []byte { + if invariants.Enabled && (row < 0 || row >= ks.roachKeys.Rows()) { + panic(errors.AssertionFailedf("invalid row number %d", row)) + } if prevRow+1 == row && prevRow >= 0 { ks.roachKeys.SetNext(ki) } else { diff --git a/internal/crdbtest/crdb_test.go b/internal/crdbtest/crdb_test.go index 61bd8cea28..a6f35b1487 100644 --- a/internal/crdbtest/crdb_test.go +++ b/internal/crdbtest/crdb_test.go @@ -320,3 +320,103 @@ func (g *cockroachKeyGen) randTimestamp() (wallTime uint64, logicalTime uint32) } return wallTime, logicalTime } + +// formatUserKey formats a user key in the format: +// +// [ @ ] +func formatUserKey(key []byte) string { + n := Split(key) + if key[n-1] != 0 { + panic("expected sentinel byte") + } + prefix := key[:n-1] + if n == len(key) { + return string(prefix) + } + suffix := key[n : len(key)-1] + if key[len(key)-1] != byte(len(suffix)+1) { + panic("invalid suffix length byte") + } + return fmt.Sprintf("%s @ %X", prefix, suffix) +} + +// formatKey formats an internal key in the format: +// +// [ @ ] #, +func formatKey(key base.InternalKey) string { + return fmt.Sprintf("%s #%d,%s", formatUserKey(key.UserKey), key.SeqNum(), key.Kind()) +} + +// formatKV formats an internal key in the format: +// +// [ @ ] #, = value +// +// For example: +// +// foo @ 0001020304050607 #1,SET +func formatKV(kv base.InternalKV) string { + val, _, err := kv.V.Value(nil) + if err != nil { + panic(err) + } + if len(val) == 0 { + return formatKey(kv.K) + } + return fmt.Sprintf("%s = %s", formatKey(kv.K), val) +} + +// parseKey parses a cockroach user key in the following format: +// +// [@ ] +// +// For example: +// +// foo @ 0001020304050607 +func parseUserKey(userKeyStr string) []byte { + roachKey, versionStr := splitStringAt(userKeyStr, " @ ") + // Append sentinel byte. + userKey := append([]byte(roachKey), 0) + if versionStr != "" { + var version []byte + if _, err := fmt.Sscanf(versionStr, "%X", &version); err != nil { + panic(fmt.Sprintf("invalid user key string %q: cannot parse version %X", userKeyStr, version)) + } + userKey = append(userKey, version...) + userKey = append(userKey, byte(len(version)+1)) + } + return userKey +} + +// parseKey parses a cockroach key in the following format: +// +// [@ ] #, +// +// For example: +// +// foo @ 0001020304050607 #1,SET +func parseKey(keyStr string) base.InternalKey { + userKeyStr, trailerStr := splitStringAt(keyStr, " #") + return base.InternalKey{ + UserKey: parseUserKey(userKeyStr), + Trailer: base.ParseInternalKey(fmt.Sprintf("foo#%s", trailerStr)).Trailer, + } +} + +// parseKey parses a cockroach KV in the following format: +// +// [@ ] #, = value +// +// For example: +// +// foo @ 0001020304050607 #1,SET = bar +func parseKV(input string) (key base.InternalKey, value []byte) { + keyStr, valStr := splitStringAt(input, " = ") + return parseKey(keyStr), []byte(valStr) +} + +func splitStringAt(str string, sep string) (before, after string) { + if s := strings.SplitN(str, sep, 2); len(s) == 2 { + return s[0], s[1] + } + return str, "" +} diff --git a/internal/crdbtest/key_schema_test.go b/internal/crdbtest/key_schema_test.go new file mode 100644 index 0000000000..a3b05e120c --- /dev/null +++ b/internal/crdbtest/key_schema_test.go @@ -0,0 +1,105 @@ +package crdbtest + +import ( + "bytes" + "fmt" + "strings" + "testing" + + "github.com/cockroachdb/crlib/crstrings" + "github.com/cockroachdb/datadriven" + "github.com/cockroachdb/pebble/internal/base" + "github.com/cockroachdb/pebble/internal/binfmt" + "github.com/cockroachdb/pebble/internal/treeprinter" + "github.com/cockroachdb/pebble/sstable/block" + "github.com/cockroachdb/pebble/sstable/colblk" + "github.com/stretchr/testify/require" +) + +// TestKeySchema tests the cockroachKeyWriter and cockroachKeySeeker. +func TestKeySchema(t *testing.T) { + for _, file := range []string{"suffix_types", "block_encoding", "seek"} { + t.Run(file, func(t *testing.T) { + runDataDrivenTest(t, fmt.Sprintf("testdata/%s", file)) + }) + } +} + +func runDataDrivenTest(t *testing.T, path string) { + var blockData []byte + var e colblk.DataBlockEncoder + e.Init(&KeySchema) + var iter colblk.DataBlockIter + iter.InitOnce(&KeySchema, Comparer.Compare, Comparer.Split, nil) + + datadriven.RunTest(t, path, func(t *testing.T, td *datadriven.TestData) string { + switch td.Cmd { + case "init": + e.Reset() + for _, l := range crstrings.Lines(td.Input) { + key, value := parseKV(l) + kcmp := e.KeyWriter.ComparePrev(key.UserKey) + e.Add(key, value, 0, kcmp, false /* isObsolete */) + } + numRows := e.Rows() + size := e.Size() + blockData, _ = e.Finish(numRows, size) + require.Equal(t, size, len(blockData)) + return fmt.Sprintf("%d rows, total size %dB", numRows, size) + + case "describe": + var d colblk.DataBlockDecoder + d.Init(&KeySchema, blockData) + f := binfmt.New(blockData) + tp := treeprinter.New() + d.Describe(f, tp) + return tp.String() + + case "suffix-types": + var d colblk.DataBlockDecoder + d.Init(&KeySchema, blockData) + var ks cockroachKeySeeker + ks.init(&d) + return fmt.Sprintf("suffix-types: %s", ks.suffixTypes) + + case "keys": + var d colblk.DataBlockDecoder + d.Init(&KeySchema, blockData) + require.NoError(t, iter.Init(&d, block.IterTransforms{})) + defer iter.Close() + var buf bytes.Buffer + var prevKey base.InternalKey + for kv := iter.First(); kv != nil; kv = iter.Next() { + fmt.Fprintf(&buf, "%s", formatKV(*kv)) + if prevKey.UserKey != nil && base.InternalCompare(Comparer.Compare, prevKey, kv.K) != -1 { + buf.WriteString(" !!! OUT OF ORDER KEY !!!") + } + buf.WriteString("\n") + prevKey = kv.K.Clone() + } + return buf.String() + + case "seek": + var d colblk.DataBlockDecoder + d.Init(&KeySchema, blockData) + require.NoError(t, iter.Init(&d, block.IterTransforms{})) + defer iter.Close() + var buf strings.Builder + for _, l := range crstrings.Lines(td.Input) { + key := parseUserKey(l) + fmt.Fprintf(&buf, "%s: ", formatUserKey(key)) + kv := iter.SeekGE(key, base.SeekGEFlagsNone) + require.NoError(t, iter.Error()) + if kv == nil { + buf.WriteString(".\n") + } else { + fmt.Fprintf(&buf, "%s\n", formatKV(*kv)) + } + } + return buf.String() + + default: + return fmt.Sprintf("unknown command: %s", td.Cmd) + } + }) +} diff --git a/internal/crdbtest/testdata/block_encoding b/internal/crdbtest/testdata/block_encoding new file mode 100644 index 0000000000..95323170e3 --- /dev/null +++ b/internal/crdbtest/testdata/block_encoding @@ -0,0 +1,208 @@ +# Note that these versions are the same MVCC timestamp: +# 0102030405060708 +# 0102030405060708000000000 (zero logical) +# 01020304050607080000000001 (zero logical, synthetic bit) +init +foo #3,SET = nosuffix3 +foo #2,SET = nosuffix2 +foo #1,SET = nosuffix1 +foo @ 0102030405060708091011121314151617 #1,SET = lockkey +foo @ 010203040506070801020304 #2,SET = mvcclogical2 +foo @ 01020304050607080102030401 #1,SET = mvcclogical1 +foo @ 010203040506070800000000 #4,SET = mvcc4 +foo @ 0102030405060708 #3,SET = mvcc3 +foo @ 01020304050607080000000001 #2,SET = mvcc2 +foo @ 0102030405060708 #1,SET = mvcc1 +fop #1,SET = foo +x #1,SET = x +---- +12 rows, total size 411B + +keys +---- +foo #3,SET = nosuffix3 +foo #2,SET = nosuffix2 +foo #1,SET = nosuffix1 +foo @ 0102030405060708091011121314151617 #1,SET = lockkey +foo @ 010203040506070801020304 #2,SET = mvcclogical2 +foo @ 010203040506070801020304 #1,SET = mvcclogical1 +foo @ 0102030405060708 #4,SET = mvcc4 +foo @ 0102030405060708 #3,SET = mvcc3 +foo @ 0102030405060708 #2,SET = mvcc2 +foo @ 0102030405060708 #1,SET = mvcc1 +fop #1,SET = foo +x #1,SET = x + +describe +---- +data block header + ├── columnar block header + │ ├── 000-001: x 07 # key schema header + │ ├── 001-005: x 16000000 # maximum key length: 22 + │ ├── 005-006: x 01 # version 1 + │ ├── 006-008: x 0900 # 9 columns + │ ├── 008-012: x 0c000000 # 12 rows + │ ├── 012-013: b 00000100 # col 0: prefixbytes + │ ├── 013-017: x 39000000 # col 0: page start 57 + │ ├── 017-018: b 00000010 # col 1: uint + │ ├── 018-022: x 50000000 # col 1: page start 80 + │ ├── 022-023: b 00000010 # col 2: uint + │ ├── 023-027: x b8000000 # col 2: page start 184 + │ ├── 027-028: b 00000011 # col 3: bytes + │ ├── 028-032: x ec000000 # col 3: page start 236 + │ ├── 032-033: b 00000010 # col 4: uint + │ ├── 033-037: x 0c010000 # col 4: page start 268 + │ ├── 037-038: b 00000001 # col 5: bool + │ ├── 038-042: x 26010000 # col 5: page start 294 + │ ├── 042-043: b 00000011 # col 6: bytes + │ ├── 043-047: x 38010000 # col 6: page start 312 + │ ├── 047-048: b 00000001 # col 7: bool + │ ├── 048-052: x 98010000 # col 7: page start 408 + │ ├── 052-053: b 00000001 # col 8: bool + │ └── 053-057: x 99010000 # col 8: page start 409 + ├── data for column 0 (prefixbytes) + │ ├── 057-058: x 04 # bundle size: 16 + │ ├── offsets table + │ │ ├── 058-059: x 01 # encoding: 1b + │ │ ├── 059-060: x 00 # data[0] = 0 [73 overall] + │ │ ├── 060-061: x 00 # data[1] = 0 [73 overall] + │ │ ├── 061-062: x 03 # data[2] = 3 [76 overall] + │ │ ├── 062-063: x 03 # data[3] = 3 [76 overall] + │ │ ├── 063-064: x 03 # data[4] = 3 [76 overall] + │ │ ├── 064-065: x 03 # data[5] = 3 [76 overall] + │ │ ├── 065-066: x 03 # data[6] = 3 [76 overall] + │ │ ├── 066-067: x 03 # data[7] = 3 [76 overall] + │ │ ├── 067-068: x 03 # data[8] = 3 [76 overall] + │ │ ├── 068-069: x 03 # data[9] = 3 [76 overall] + │ │ ├── 069-070: x 03 # data[10] = 3 [76 overall] + │ │ ├── 070-071: x 03 # data[11] = 3 [76 overall] + │ │ ├── 071-072: x 06 # data[12] = 6 [79 overall] + │ │ └── 072-073: x 07 # data[13] = 7 [80 overall] + │ └── data + │ ├── 073-073: x # data[00]: (block prefix) + │ ├── 073-073: x # data[01]: (bundle prefix) + │ ├── 073-076: x 666f6f # data[02]: foo + │ ├── 076-076: x # data[03]: ... + │ ├── 076-076: x # data[04]: ... + │ ├── 076-076: x # data[05]: ... + │ ├── 076-076: x # data[06]: ... + │ ├── 076-076: x # data[07]: ... + │ ├── 076-076: x # data[08]: ... + │ ├── 076-076: x # data[09]: ... + │ ├── 076-076: x # data[10]: ... + │ ├── 076-076: x # data[11]: ... + │ ├── 076-079: x 666f70 # data[12]: fop + │ └── 079-080: x 78 # data[13]: x + ├── data for column 1 (uint) + │ ├── 080-081: x 08 # encoding: 8b + │ ├── 081-088: x 00000000000000 # padding (aligning to 64-bit boundary) + │ ├── 088-096: x 0000000000000000 # data[0] = 0 + │ ├── 096-104: x 0000000000000000 # data[1] = 0 + │ ├── 104-112: x 0000000000000000 # data[2] = 0 + │ ├── 112-120: x 0000000000000000 # data[3] = 0 + │ ├── 120-128: x 0807060504030201 # data[4] = 72623859790382856 + │ ├── 128-136: x 0807060504030201 # data[5] = 72623859790382856 + │ ├── 136-144: x 0807060504030201 # data[6] = 72623859790382856 + │ ├── 144-152: x 0807060504030201 # data[7] = 72623859790382856 + │ ├── 152-160: x 0807060504030201 # data[8] = 72623859790382856 + │ ├── 160-168: x 0807060504030201 # data[9] = 72623859790382856 + │ ├── 168-176: x 0000000000000000 # data[10] = 0 + │ └── 176-184: x 0000000000000000 # data[11] = 0 + ├── data for column 2 (uint) + │ ├── 184-185: x 04 # encoding: 4b + │ ├── 185-188: x 000000 # padding (aligning to 32-bit boundary) + │ ├── 188-192: x 00000000 # data[0] = 0 + │ ├── 192-196: x 00000000 # data[1] = 0 + │ ├── 196-200: x 00000000 # data[2] = 0 + │ ├── 200-204: x 00000000 # data[3] = 0 + │ ├── 204-208: x 04030201 # data[4] = 16909060 + │ ├── 208-212: x 04030201 # data[5] = 16909060 + │ ├── 212-216: x 00000000 # data[6] = 0 + │ ├── 216-220: x 00000000 # data[7] = 0 + │ ├── 220-224: x 00000000 # data[8] = 0 + │ ├── 224-228: x 00000000 # data[9] = 0 + │ ├── 228-232: x 00000000 # data[10] = 0 + │ └── 232-236: x 00000000 # data[11] = 0 + ├── data for column 3 (bytes) + │ ├── offsets table + │ │ ├── 236-237: x 01 # encoding: 1b + │ │ ├── 237-238: x 00 # data[0] = 0 [250 overall] + │ │ ├── 238-239: x 00 # data[1] = 0 [250 overall] + │ │ ├── 239-240: x 00 # data[2] = 0 [250 overall] + │ │ ├── 240-241: x 00 # data[3] = 0 [250 overall] + │ │ ├── 241-242: x 12 # data[4] = 18 [268 overall] + │ │ ├── 242-243: x 12 # data[5] = 18 [268 overall] + │ │ ├── 243-244: x 12 # data[6] = 18 [268 overall] + │ │ ├── 244-245: x 12 # data[7] = 18 [268 overall] + │ │ ├── 245-246: x 12 # data[8] = 18 [268 overall] + │ │ ├── 246-247: x 12 # data[9] = 18 [268 overall] + │ │ ├── 247-248: x 12 # data[10] = 18 [268 overall] + │ │ ├── 248-249: x 12 # data[11] = 18 [268 overall] + │ │ └── 249-250: x 12 # data[12] = 18 [268 overall] + │ └── data + │ ├── 250-250: x # data[0]: + │ ├── 250-250: x # data[1]: + │ ├── 250-250: x # data[2]: + │ ├── 250-268: x 010203040506070809101112131415161712 # data[3]: "\x01\x02\x03\x04\x05\x06\a\b\t\x10\x11\x12\x13\x14\x15\x16\x17\x12" + │ ├── 268-268: x # data[4]: + │ ├── 268-268: x # data[5]: + │ ├── 268-268: x # data[6]: + │ ├── 268-268: x # data[7]: + │ ├── 268-268: x # data[8]: + │ ├── 268-268: x # data[9]: + │ ├── 268-268: x # data[10]: + │ └── 268-268: x # data[11]: + ├── data for column 4 (uint) + │ ├── 268-269: x 02 # encoding: 2b + │ ├── 269-270: x 00 # padding (aligning to 16-bit boundary) + │ ├── 270-272: x 0103 # data[0] = 769 + │ ├── 272-274: x 0102 # data[1] = 513 + │ ├── 274-276: x 0101 # data[2] = 257 + │ ├── 276-278: x 0101 # data[3] = 257 + │ ├── 278-280: x 0102 # data[4] = 513 + │ ├── 280-282: x 0101 # data[5] = 257 + │ ├── 282-284: x 0104 # data[6] = 1025 + │ ├── 284-286: x 0103 # data[7] = 769 + │ ├── 286-288: x 0102 # data[8] = 513 + │ ├── 288-290: x 0101 # data[9] = 257 + │ ├── 290-292: x 0101 # data[10] = 257 + │ └── 292-294: x 0101 # data[11] = 257 + ├── data for column 5 (bool) + │ ├── 294-295: x 00 # default bitmap encoding + │ ├── 295-296: x 00 # padding to align to 64-bit boundary + │ ├── 296-304: b 0000000100001100000000000000000000000000000000000000000000000000 # bitmap word 0 + │ └── 304-312: b 0000000100000000000000000000000000000000000000000000000000000000 # bitmap summary word 0-63 + ├── data for column 6 (bytes) + │ ├── offsets table + │ │ ├── 312-313: x 01 # encoding: 1b + │ │ ├── 313-314: x 00 # data[0] = 0 [326 overall] + │ │ ├── 314-315: x 09 # data[1] = 9 [335 overall] + │ │ ├── 315-316: x 12 # data[2] = 18 [344 overall] + │ │ ├── 316-317: x 1b # data[3] = 27 [353 overall] + │ │ ├── 317-318: x 22 # data[4] = 34 [360 overall] + │ │ ├── 318-319: x 2e # data[5] = 46 [372 overall] + │ │ ├── 319-320: x 3a # data[6] = 58 [384 overall] + │ │ ├── 320-321: x 3f # data[7] = 63 [389 overall] + │ │ ├── 321-322: x 44 # data[8] = 68 [394 overall] + │ │ ├── 322-323: x 49 # data[9] = 73 [399 overall] + │ │ ├── 323-324: x 4e # data[10] = 78 [404 overall] + │ │ ├── 324-325: x 51 # data[11] = 81 [407 overall] + │ │ └── 325-326: x 52 # data[12] = 82 [408 overall] + │ └── data + │ ├── 326-335: x 6e6f73756666697833 # data[0]: nosuffix3 + │ ├── 335-344: x 6e6f73756666697832 # data[1]: nosuffix2 + │ ├── 344-353: x 6e6f73756666697831 # data[2]: nosuffix1 + │ ├── 353-360: x 6c6f636b6b6579 # data[3]: lockkey + │ ├── 360-372: x 6d7663636c6f676963616c32 # data[4]: mvcclogical2 + │ ├── 372-384: x 6d7663636c6f676963616c31 # data[5]: mvcclogical1 + │ ├── 384-389: x 6d76636334 # data[6]: mvcc4 + │ ├── 389-394: x 6d76636333 # data[7]: mvcc3 + │ ├── 394-399: x 6d76636332 # data[8]: mvcc2 + │ ├── 399-404: x 6d76636331 # data[9]: mvcc1 + │ ├── 404-407: x 666f6f # data[10]: foo + │ └── 407-408: x 78 # data[11]: x + ├── data for column 7 (bool) + │ └── 408-409: x 01 # zero bitmap encoding + ├── data for column 8 (bool) + │ └── 409-410: x 01 # zero bitmap encoding + └── 410-411: x 00 # block padding byte diff --git a/internal/crdbtest/testdata/seek b/internal/crdbtest/testdata/seek new file mode 100644 index 0000000000..eb0f0e8b13 --- /dev/null +++ b/internal/crdbtest/testdata/seek @@ -0,0 +1,133 @@ +# Test seeking with MVCC versions. +init +fo @ 0102030405060708 #1,SET = row0 +foo @ 0102030405060708 #1,SET = row1 +foo @ 010203040506070701020304 #2,SET = row2 +foo @ 010203040506070701020304 #1,SET = row3 +foo @ 0102030405060707 #1,SET = row4 +foop @ 0102030405060708 #1,SET = row5 +fop @ 0102030405060708 #1,SET = row6 +---- +7 rows, total size 200B + +seek +fo +fo @ 05 +fo @ 05 +fo @ 0102030405060709 #1,SET = v0 +fo @ 0102030405060708 #1,SET = v0 +fo @ 0102030405060707 #1,SET = v0 +---- +fo: fo @ 0102030405060708 #1,SET = row0 +fo @ 05: fo @ 0102030405060708 #1,SET = row0 +fo @ 05: fo @ 0102030405060708 #1,SET = row0 +fo @ 0102030405060709: fo @ 0102030405060708 #1,SET = row0 +fo @ 0102030405060708: fo @ 0102030405060708 #1,SET = row0 +fo @ 0102030405060707: foo @ 0102030405060708 #1,SET = row1 + +seek +foo +foo @ 0102030405060708 +foo @ 010203040506070701020305 +foo @ 010203040506070701020304 +foo @ 010203040506070701020303 +foo @ 0102030405060707 +---- +foo: foo @ 0102030405060708 #1,SET = row1 +foo @ 0102030405060708: foo @ 0102030405060708 #1,SET = row1 +foo @ 010203040506070701020305: foo @ 010203040506070701020304 #2,SET = row2 +foo @ 010203040506070701020304: foo @ 010203040506070701020304 #2,SET = row2 +foo @ 010203040506070701020303: foo @ 0102030405060707 #1,SET = row4 +foo @ 0102030405060707: foo @ 0102030405060707 #1,SET = row4 + +seek +foop +foop @ 0102030405060708 +foop @ 0102030405060707 +fop +foq +---- +foop: foop @ 0102030405060708 #1,SET = row5 +foop @ 0102030405060708: foop @ 0102030405060708 #1,SET = row5 +foop @ 0102030405060707: fop @ 0102030405060708 #1,SET = row6 +fop: fop @ 0102030405060708 #1,SET = row6 +foq: . + +# Test seeking with no versions. +init +fo #2,SET = row0 +fo #1,SET = row1 +foo #1,DEL +fop #1,DEL +foq #1,SET = row4 +fz #1,SET = row5 +---- +6 rows, total size 139B + +seek +a +fo +foo +foo1 +fop +fop1 +foq +fu +g +---- +a: fo #2,SET = row0 +fo: fo #2,SET = row0 +foo: foo #1,DEL +foo1: fop #1,DEL +fop: fop #1,DEL +fop1: foq #1,SET = row4 +foq: foq #1,SET = row4 +fu: fz #1,SET = row5 +g: . + +# Test seeking among lock keys. +init +fo @ 0000000000000000000000000000000002 #1,SET = row0 +foo @ 0000000000000000000000000000000010 #1,SET = row1 +foo @ 0000000000000000000000000000000008 #1,SET = row2 +foo @ 0000000000000000000000000000000002 #1,SET = row3 +foo @ 0000000000000000000000000000000001 #1,SET = row4 +z @ 0000000000000000000000000000000001 #1,SET = row5 +---- +6 rows, total size 259B + +seek +a +fo +fo @ 0000000000000000000000000000000003 +fo @ 0000000000000000000000000000000002 +fo @ 0000000000000000000000000000000001 +---- +a: fo @ 0000000000000000000000000000000002 #1,SET = row0 +fo: fo @ 0000000000000000000000000000000002 #1,SET = row0 +fo @ 0000000000000000000000000000000003: fo @ 0000000000000000000000000000000002 #1,SET = row0 +fo @ 0000000000000000000000000000000002: fo @ 0000000000000000000000000000000002 #1,SET = row0 +fo @ 0000000000000000000000000000000001: foo @ 0000000000000000000000000000000010 #1,SET = row1 + +seek +foo +foo @ 0000000000000000000000000000000015 +foo @ 0000000000000000000000000000000010 +foo @ 0000000000000000000000000000000009 +foo @ 0000000000000000000000000000000008 +foo @ 0000000000000000000000000000000007 +foo @ 0000000000000000000000000000000002 +foo @ 0000000000000000000000000000000001 +foo @ 0000000000000000000000000000000000 +---- +foo: foo @ 0000000000000000000000000000000010 #1,SET = row1 +foo @ 0000000000000000000000000000000015: foo @ 0000000000000000000000000000000010 #1,SET = row1 +foo @ 0000000000000000000000000000000010: foo @ 0000000000000000000000000000000010 #1,SET = row1 +foo @ 0000000000000000000000000000000009: foo @ 0000000000000000000000000000000008 #1,SET = row2 +foo @ 0000000000000000000000000000000008: foo @ 0000000000000000000000000000000008 #1,SET = row2 +foo @ 0000000000000000000000000000000007: foo @ 0000000000000000000000000000000002 #1,SET = row3 +foo @ 0000000000000000000000000000000002: foo @ 0000000000000000000000000000000002 #1,SET = row3 +foo @ 0000000000000000000000000000000001: foo @ 0000000000000000000000000000000001 #1,SET = row4 +foo @ 0000000000000000000000000000000000: z @ 0000000000000000000000000000000001 #1,SET = row5 + +# TODO(radu): tests with mixed types of versions. diff --git a/internal/crdbtest/testdata/suffix_types b/internal/crdbtest/testdata/suffix_types new file mode 100644 index 0000000000..004ea03fc8 --- /dev/null +++ b/internal/crdbtest/testdata/suffix_types @@ -0,0 +1,71 @@ +# This file contains tests that verifies the suffixTypes indicator encoded in +# the key schema prefix. + +init +foo #1,SET = bar +---- +1 rows, total size 105B + +suffix-types +---- +suffix-types: empty + +init +foo @ 0102030405060708 #1,SET = bar +foo @ 010203040506070801020304 #1,SET = bar +---- +2 rows, total size 125B + +suffix-types +---- +suffix-types: mvcc + +init +foo @ 0102030405060708091011121314151617 #1,SET = bar +---- +1 rows, total size 121B + +suffix-types +---- +suffix-types: non-mvcc + +init +foo #1,SET = bar +foo @ 0102030405060708 #1,SET = bar +---- +2 rows, total size 133B + +suffix-types +---- +suffix-types: mvcc,empty + +init +foo @ 0102030405060708 #1,SET = bar +foo @ 0102030405060708091011121314151617 #1,SET = bar +---- +2 rows, total size 149B + +suffix-types +---- +suffix-types: mvcc,non-mvcc + +init +foo #1,SET = bar +foo @ 0102030405060708091011121314151617 #1,SET = bar +---- +2 rows, total size 133B + +suffix-types +---- +suffix-types: empty,non-mvcc + +init +foo #1,SET = bar +foo @ 0102030405060708 #1,SET = bar +foo @ 0102030405060708091011121314151617 #1,SET = bar +---- +3 rows, total size 169B + +suffix-types +---- +suffix-types: mvcc,empty,non-mvcc diff --git a/sstable/colblk/data_block.go b/sstable/colblk/data_block.go index c6a245ddf1..aafe7f8b28 100644 --- a/sstable/colblk/data_block.go +++ b/sstable/colblk/data_block.go @@ -905,6 +905,9 @@ func (d *DataBlockDecoder) Describe(f *binfmt.Formatter, tp treeprinter.Node) { f.SetAnchorOffset() n := tp.Child("data block header") + if keySchemaHeaderSize := int(d.d.customHeaderSize - 4); keySchemaHeaderSize > 0 { + f.HexBytesln(keySchemaHeaderSize, "key schema header") + } f.HexBytesln(4, "maximum key length: %d", d.maximumKeyLength) d.d.headerToBinFormatter(f, n) for i := 0; i < int(d.d.header.Columns); i++ {