Skip to content

Commit f4e0157

Browse files
authored
change BSUP version to use major-minor pattern (#7532)
1 parent abd8dd3 commit f4e0157

3 files changed

Lines changed: 93 additions & 36 deletions

File tree

‎bsup/header.go‎

Lines changed: 24 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ import (
6060
// which simply produces a larger and still-valid Container.
6161

6262
const (
63-
Version = 28
6463
MaxMetaSize = 100 * 1024 * 1024
6564
MaxFrameSize = 2 * 1024 * 1024 * 1024
6665
MaxSuperFrameSize = 256 * MaxFrameSize
@@ -80,7 +79,7 @@ type Header interface {
8079
// Structure of ColumnFrame
8180
//
8281
// S U P C (4 byte string)
83-
// Version (2 bytes)
82+
// Version (2 bytes) - 6-bit major and 10-bit minor (see Version)
8483
// Frame size (8 bytes) - entire frame including header to end of data section
8584
// Root ID (4 bytes)
8685
// Fused type size (8 bytes) - 0 if not present
@@ -91,20 +90,20 @@ type Header interface {
9190
// Fused type value (encoded as raw type value bytes)
9291
// Data section (encoded as raw bytes with size = FrameSize - MetadataSize)
9392
type ColumnHeader struct {
94-
Version uint16 // off 4
95-
FrameSize uint64 // 6
96-
Root uint32 // 14
97-
MetadataSize uint64 // 18
98-
TypedefsSize uint64 // 26
99-
FusedTypeSize uint64 // 34
93+
Version Version // off 4
94+
FrameSize uint64 // 6
95+
Root uint32 // 14
96+
MetadataSize uint64 // 18
97+
TypedefsSize uint64 // 26
98+
FusedTypeSize uint64 // 34
10099
}
101100

102101
const ColumnHeaderSize = 42
103102

104103
func newColumnHeader(root ID, metadataSize, typedefsSize, fusedTypeSize, dataSectionSize uint64) ColumnHeader {
105104
frameSize := ColumnHeaderSize + metadataSize + typedefsSize + fusedTypeSize + dataSectionSize
106105
return ColumnHeader{
107-
Version: Version,
106+
Version: CurrentVersion,
108107
FrameSize: frameSize,
109108
Root: uint32(root),
110109
MetadataSize: metadataSize,
@@ -120,7 +119,7 @@ func (c *ColumnHeader) Size() uint64 {
120119
func (c ColumnHeader) Serialize() []byte {
121120
var bytes [ColumnHeaderSize]byte
122121
copy(bytes[0:4], []byte(ColumnMagic))
123-
binary.LittleEndian.PutUint16(bytes[4:], c.Version)
122+
c.Version.Serialize(bytes[4:])
124123
binary.LittleEndian.PutUint64(bytes[6:], c.FrameSize)
125124
binary.LittleEndian.PutUint32(bytes[14:], c.Root)
126125
binary.LittleEndian.PutUint64(bytes[18:], c.MetadataSize)
@@ -130,7 +129,7 @@ func (c ColumnHeader) Serialize() []byte {
130129
}
131130

132131
func (c *ColumnHeader) Deserialize(bytes [ColumnHeaderSize]byte) {
133-
c.Version = binary.LittleEndian.Uint16(bytes[4:])
132+
c.Version.Deserialize(bytes[4:])
134133
c.FrameSize = binary.LittleEndian.Uint64(bytes[6:])
135134
c.Root = binary.LittleEndian.Uint32(bytes[14:])
136135
c.MetadataSize = binary.LittleEndian.Uint64(bytes[18:])
@@ -174,15 +173,15 @@ func (c ColumnHeader) check() error {
174173
// Structure of RowFrame
175174
//
176175
// S U P R (4 byte string)
177-
// Version (2 bytes)
176+
// Version (2 bytes) - 6-bit major and 10-bit minor (see Version)
178177
// Frame size (8 bytes) - entire frame including header to end of data section
179178
// Fused type size (8 bytes) - 0 if not present
180179
// Typedefs section size (8 bytes)
181180
// Fused type value (variable bytes)
182181
// Typedefs section (variable bytes)
183182
// Values section size = FrameSize - (FusedTypeSize+TypedefsSize)
184183
type RowHeader struct {
185-
Version uint16
184+
Version Version
186185
FrameSize uint64
187186
FusedTypeSize uint64
188187
TypedefsSize uint64
@@ -194,7 +193,7 @@ const RowHeaderSize = 30
194193
func newRowHeader(oob bool, typedefsSize, fusedTypeSize, dataSectionSize uint64) RowHeader {
195194
frameSize := RowHeaderSize + +typedefsSize + fusedTypeSize + dataSectionSize
196195
return RowHeader{
197-
Version: Version,
196+
Version: CurrentVersion,
198197
FrameSize: frameSize,
199198
TypedefsSize: typedefsSize,
200199
FusedTypeSize: fusedTypeSize,
@@ -212,15 +211,15 @@ func (r RowHeader) Serialize(ctrl bool) []byte {
212211
} else {
213212
copy(bytes[0:4], []byte(RowMagic))
214213
}
215-
binary.LittleEndian.PutUint16(bytes[4:], r.Version)
214+
r.Version.Serialize(bytes[4:])
216215
binary.LittleEndian.PutUint64(bytes[6:], r.FrameSize)
217216
binary.LittleEndian.PutUint64(bytes[14:], r.FusedTypeSize)
218217
binary.LittleEndian.PutUint64(bytes[22:], r.TypedefsSize)
219218
return bytes[:]
220219
}
221220

222221
func (r *RowHeader) Deserialize(bytes [RowHeaderSize]byte) {
223-
r.Version = binary.LittleEndian.Uint16(bytes[4:])
222+
r.Version.Deserialize(bytes[4:])
224223
r.FrameSize = binary.LittleEndian.Uint64(bytes[6:])
225224
r.FusedTypeSize = binary.LittleEndian.Uint64(bytes[14:])
226225
r.TypedefsSize = binary.LittleEndian.Uint64(bytes[22:])
@@ -254,18 +253,18 @@ func (r RowHeader) check() error {
254253
// Structure of SuperFrame footer
255254
//
256255
// S U P S (4 byte string)
257-
// Version (2 bytes)
256+
// Version (2 bytes) - 6-bit major and 10-bit minor (see Version)
258257
// Footer size (8 bytes) - total size of footer including SuperFooterPad
259258
// Total size of previous SuperFrame (8 bytes) - excludes this SuperFrame footer
260259
// Fused type value (variable bytes)
261260
// Stats Section (variable bytes)
262261
// Footer size (8 bytes) - same as above for backward traversal
263262
type SuperFooter struct {
264-
Version uint16 // off 4
265-
FooterSize uint64 // off 6
266-
FusedTypeSize uint64 // off 14
267-
StatsSize uint64 // off 22
268-
SuperFrameSize uint64 // off 30
263+
Version Version // off 4
264+
FooterSize uint64 // off 6
265+
FusedTypeSize uint64 // off 14
266+
StatsSize uint64 // off 22
267+
SuperFrameSize uint64 // off 30
269268
}
270269

271270
const (
@@ -275,7 +274,7 @@ const (
275274

276275
func newSuperFooter(superFrameSize, fusedTypeSize, statsSize uint64) SuperFooter {
277276
return SuperFooter{
278-
Version: Version,
277+
Version: CurrentVersion,
279278
FooterSize: SuperFooterSize + SuperFooterPad + fusedTypeSize + statsSize,
280279
FusedTypeSize: fusedTypeSize,
281280
StatsSize: statsSize,
@@ -300,7 +299,7 @@ func (s SuperFooter) StatsSection() (int64, int64) {
300299
func (s SuperFooter) Serialize() []byte {
301300
var bytes [SuperFooterSize]byte
302301
copy(bytes[0:4], []byte(SuperMagic))
303-
binary.LittleEndian.PutUint16(bytes[4:], s.Version)
302+
s.Version.Serialize(bytes[4:])
304303
binary.LittleEndian.PutUint64(bytes[6:], s.FooterSize)
305304
binary.LittleEndian.PutUint64(bytes[14:], s.FusedTypeSize)
306305
binary.LittleEndian.PutUint64(bytes[22:], s.StatsSize)
@@ -309,7 +308,7 @@ func (s SuperFooter) Serialize() []byte {
309308
}
310309

311310
func (s *SuperFooter) Deserialize(bytes [SuperFooterSize]byte) {
312-
s.Version = binary.LittleEndian.Uint16(bytes[4:])
311+
s.Version.Deserialize(bytes[4:])
313312
s.FooterSize = binary.LittleEndian.Uint64(bytes[6:])
314313
s.FusedTypeSize = binary.LittleEndian.Uint64(bytes[14:])
315314
s.StatsSize = binary.LittleEndian.Uint64(bytes[22:])
@@ -455,13 +454,6 @@ func checkEOF(err error) error {
455454
return err
456455
}
457456

458-
func checkVersion(version uint16) error {
459-
if version != Version {
460-
return fmt.Errorf("version mismatch: expected %d, found %d", Version, version)
461-
}
462-
return nil
463-
}
464-
465457
func checkSize(msg string, size, max int) error {
466458
// We check for underflow of size since they are stored as unsigned.
467459
if size > max || size < 0 {

‎bsup/version.go‎

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package bsup
2+
3+
import (
4+
"encoding/binary"
5+
"fmt"
6+
)
7+
8+
// Versioning is done with major/minor versions. Any implementation can read
9+
// files with the same major version, forward and backward, but an older minor
10+
// version might not be able to take advantage of or understand new types
11+
// supported by a later minor version under the same major version. No
12+
// compatibility (except possibly backward compatibility depending on the
13+
// implementation) is available between different major versions. Major
14+
// version 0 is for development and there is no compatibility between minor
15+
// versions under major version 0. No releases should be made with a zero
16+
// major version.
17+
//
18+
// A version is encoded in two bytes as a little-endian uint16 with the major
19+
// version in the upper 6 bits and the minor version in the lower 10 bits, so
20+
// a development version encoded before major and minor versions were
21+
// introduced (when the version was a plain uint16) decodes as major version 0.
22+
//
23+
// Last dev minor version: 28
24+
var CurrentVersion = Version{0, 28}
25+
26+
const (
27+
VersionSize = 2
28+
29+
majorBits = 6
30+
minorBits = 10
31+
MaxMajor = 1<<majorBits - 1
32+
MaxMinor = 1<<minorBits - 1
33+
)
34+
35+
type Version struct {
36+
Major uint8
37+
Minor uint16
38+
}
39+
40+
// Serialize encodes v into the first VersionSize bytes of b.
41+
func (v Version) Serialize(b []byte) {
42+
if v.Major > MaxMajor || v.Minor > MaxMinor {
43+
panic(fmt.Sprintf("BSUP version %s out of range", v))
44+
}
45+
binary.LittleEndian.PutUint16(b, uint16(v.Major)<<minorBits|v.Minor)
46+
}
47+
48+
// Deserialize decodes v from the first VersionSize bytes of b.
49+
func (v *Version) Deserialize(b []byte) {
50+
u := binary.LittleEndian.Uint16(b)
51+
v.Major = uint8(u >> minorBits)
52+
v.Minor = u & MaxMinor
53+
}
54+
55+
func (v Version) String() string {
56+
return fmt.Sprintf("%d.%d", v.Major, v.Minor)
57+
}
58+
59+
func checkVersion(version Version) error {
60+
if version.Major != CurrentVersion.Major || (CurrentVersion.Major == 0 && version.Minor != CurrentVersion.Minor) {
61+
return fmt.Errorf("version mismatch: expected %s, found %s", CurrentVersion, version)
62+
}
63+
return nil
64+
}

‎bsup/ztests/const.yaml‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@ inputs:
1212
outputs:
1313
- name: stdout
1414
data: |
15-
type ColumnHeader={Version:uint16,FrameSize:uint64,Root:uint32,MetadataSize:uint64,TypedefsSize:uint64,FusedTypeSize:uint64}
16-
{Version:28,FrameSize:205,Root:0,MetadataSize:162,TypedefsSize:0,FusedTypeSize:1}::ColumnHeader
15+
type Version={Major:uint8,Minor:uint16}
16+
type ColumnHeader={Version:Version,FrameSize:uint64,Root:uint32,MetadataSize:uint64,TypedefsSize:uint64,FusedTypeSize:uint64}
17+
{Version:{Major:0,Minor:28},FrameSize:205,Root:0,MetadataSize:162,TypedefsSize:0,FusedTypeSize:1}::ColumnHeader
1718
type Const={Value:any,Count:uint32}
1819
{Value:1::any,Count:3}::Const
1920
{Kind:"ColumnFrameFusedType",Type:<int64>}
20-
type SuperFooter={Version:uint16,FooterSize:uint64,FusedTypeSize:uint64,StatsSize:uint64,SuperFrameSize:uint64}
21-
{Version:28,FooterSize:68,FusedTypeSize:1,StatsSize:21,SuperFrameSize:205}::SuperFooter
21+
type SuperFooter={Version:Version,FooterSize:uint64,FusedTypeSize:uint64,StatsSize:uint64,SuperFrameSize:uint64}
22+
{Version:{Major:0,Minor:28},FooterSize:68,FusedTypeSize:1,StatsSize:21,SuperFrameSize:205}::SuperFooter
2223
{Kind:"SuperFrameFusedType",Type:<int64>}

0 commit comments

Comments
 (0)