Repository: cockroachdb/pebble
Pull request #3857 (2024-08-15 18:29:26)

colblk: fix offset reset to 0 when encoding/decoding empty block
This changes a few instances where a block is empty and we are returning 0 instead of `offset` as the next offset.

cockroach-teamcity: 

<!-- Reviewable:start -->
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/cockroachdb/pebble/3857)
<!-- Reviewable:end -->

RaduBerinde: TFTR!

Patch:
diff --git a/sstable/colblk/prefix_bytes.go b/sstable/colblk/prefix_bytes.go
index cae878b3..9a704a48 100644
--- a/sstable/colblk/prefix_bytes.go
+++ b/sstable/colblk/prefix_bytes.go
@@ -1029,7 +1029,7 @@ func (b *PrefixBytesBuilder) Finish(
 // from the returned offset.
 func (b *PrefixBytesBuilder) Size(rows int, offset uint32) uint32 {
 	if rows == 0 {
-		return 0
+		return offset
 	} else if rows != b.nKeys && rows != b.nKeys-1 {
 		panic(errors.AssertionFailedf("PrefixBytes has accumulated %d keys, asked to Size %d", b.nKeys, rows))
 	}
diff --git a/sstable/colblk/raw_bytes.go b/sstable/colblk/raw_bytes.go
index a8500e7c..6d1f3508 100644
--- a/sstable/colblk/raw_bytes.go
+++ b/sstable/colblk/raw_bytes.go
@@ -59,7 +59,7 @@ var _ Array[[]byte] = RawBytes{}
 // number of byte slices within the array.
 func DecodeRawBytes(b []byte, offset uint32, count int) (rawBytes RawBytes, endOffset uint32) {
 	if count == 0 {
-		return RawBytes{}, 0
+		return RawBytes{}, offset
 	}
 	offsets, dataOff := DecodeUnsafeOffsets(b, offset, count+1 /* +1 offset */)
 	return RawBytes{
@@ -179,7 +179,7 @@ func (b *RawBytesBuilder) LastSlice() []byte {
 // should use [Size] to size buf appropriately before calling Finish.
 func (b *RawBytesBuilder) Finish(col, rows int, offset uint32, buf []byte) uint32 {
 	if rows == 0 {
-		return 0
+		return offset
 	}
 	dataLen := b.offsets.Get(rows)
 	offset = b.offsets.Finish(0, rows+1, offset, buf)
@@ -194,7 +194,7 @@ func (b *RawBytesBuilder) Finish(col, rows int, offset uint32, buf []byte) uint3
 // passed into Size from the returned offset.
 func (b *RawBytesBuilder) Size(rows int, offset uint32) uint32 {
 	if rows == 0 {
-		return 0
+		return offset
 	}
 	// Get the size needed to encode the rows+1 offsets.
 	offset = b.offsets.Size(rows+1, offset)
diff --git a/sstable/colblk/uints.go b/sstable/colblk/uints.go
index c68911e7..5efb6cb6 100644
--- a/sstable/colblk/uints.go
+++ b/sstable/colblk/uints.go
@@ -248,7 +248,7 @@ func (b *UintBuilder) Set(row int, v uint64) {
 // [rows] rows were serialized, serializing the column into offset [offset].
 func (b *UintBuilder) Size(rows int, offset uint32) uint32 {
 	if rows == 0 {
-		return 0
+		return offset
 	}
 	e, _ := b.determineEncoding(rows)
 	return uintColumnSize(uint32(rows), offset, e)


Test patch:
diff --git a/sstable/colblk/testdata/data_block/bundle_search b/sstable/colblk/testdata/data_block/bundle_search
index ecf16a8c..c23b7b6a 100644
--- a/sstable/colblk/testdata/data_block/bundle_search
+++ b/sstable/colblk/testdata/data_block/bundle_search
@@ -10,7 +10,7 @@
 
 init bundle-size=4
 ----
-size=1:
+size=49:
 0: prefixes:       prefixbytes(4): 0 keys
 1: suffixes:       bytes: 0 rows set; 0 bytes in data
 2: trailers:       uint: 0 rows
diff --git a/sstable/colblk/testdata/data_block/external_value b/sstable/colblk/testdata/data_block/external_value
index 6fe407e0..301f56c6 100644
--- a/sstable/colblk/testdata/data_block/external_value
+++ b/sstable/colblk/testdata/data_block/external_value
@@ -1,6 +1,6 @@
 init
 ----
-size=1:
+size=49:
 0: prefixes:       prefixbytes(16): 0 keys
 1: suffixes:       bytes: 0 rows set; 0 bytes in data
 2: trailers:       uint: 0 rows
diff --git a/sstable/colblk/testdata/data_block/next_prefix b/sstable/colblk/testdata/data_block/next_prefix
index 1b2c4246..f56cd1f2 100644
--- a/sstable/colblk/testdata/data_block/next_prefix
+++ b/sstable/colblk/testdata/data_block/next_prefix
@@ -1,6 +1,6 @@
 init
 ----
-size=1:
+size=49:
 0: prefixes:       prefixbytes(16): 0 keys
 1: suffixes:       bytes: 0 rows set; 0 bytes in data
 2: trailers:       uint: 0 rows
diff --git a/sstable/colblk/testdata/data_block/simple b/sstable/colblk/testdata/data_block/simple
index 25bd2e8d..b1f304a2 100644
--- a/sstable/colblk/testdata/data_block/simple
+++ b/sstable/colblk/testdata/data_block/simple
@@ -1,6 +1,6 @@
 init
 ----
-size=1:
+size=49:
 0: prefixes:       prefixbytes(16): 0 keys
 1: suffixes:       bytes: 0 rows set; 0 bytes in data
 2: trailers:       uint: 0 rows
@@ -299,7 +299,7 @@ d@11:
 
 init
 ----
-size=1:
+size=49:
 0: prefixes:       prefixbytes(16): 0 keys
 1: suffixes:       bytes: 0 rows set; 0 bytes in data
 2: trailers:       uint: 0 rows
diff --git a/sstable/colblk/testdata/keyspan_block b/sstable/colblk/testdata/keyspan_block
index 47d44c3b..5311c7e5 100644
--- a/sstable/colblk/testdata/keyspan_block
+++ b/sstable/colblk/testdata/keyspan_block
@@ -1,6 +1,6 @@
 init
 ----
-size=1:
+size=37:
 0: user keys:      bytes: 0 rows set; 0 bytes in data
 1: start indices:  uint: 0 rows
 2: trailers:       uint: 0 rows
@@ -212,7 +212,7 @@ d-e:{(#0,RANGEDEL)}
 
 init
 ----
-size=1:
+size=37:
 0: user keys:      bytes: 0 rows set; 0 bytes in data
 1: start indices:  uint: 0 rows
 2: trailers:       uint: 0 rows
@@ -301,7 +301,7 @@ b-d:{(#4,RANGEKEYSET,@3,coconut)}
 
 reset
 ----
-size=1:
+size=37:
 0: user keys:      bytes: 0 rows set; 0 bytes in data
 1: start indices:  uint: 0 rows
 2: trailers:       uint: 0 rows