Skip to content

Commit

Permalink
fstree: introduce combined file versioning
Browse files Browse the repository at this point in the history
We may want to have something more complex in future versions (like #2925 or
others) and we don't have a lot of safe bytes to use in place of 0x7F. So
let's have a byte for format version.

This is an incompatible change, but this code was never in production.

Signed-off-by: Roman Khimov <[email protected]>
  • Loading branch information
roman-khimov committed Nov 26, 2024
1 parent b243841 commit dfa8068
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 5 deletions.
3 changes: 2 additions & 1 deletion pkg/local_object_storage/blobstor/fstree/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,15 @@ can not collide with protobuf-encoded or ZSTD-compressed data. Files using
this prefix can contain an unspecified number of objects (configured via
[WithCombinedCountLimit]) that all follow the same serialization pattern:
- the first byte is magic 0x7F described above
- one byte version of the subsequent structure (currently zero only)
- 32-byte OID of the next object then
- 4-byte BE integer length of the next object
- followed by protobuf-encoded or ZSTD-compressed object data (of the length
specified in the previous field)
Overall the structure is like this:
[0x7F [OID A] [uint32 size]][object A][0x7F [OID B] [uint32 size]][object B]...
[0x7F 0x00 [OID A] [uint32 size]][object A][0x7F 0x00 [OID B] [uint32 size]][object B]...
Even though this file contains several objects it has hard links for all of
them in the FS tree, so finding a file containing some object doesn't require
Expand Down
18 changes: 14 additions & 4 deletions pkg/local_object_storage/blobstor/fstree/fstree.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ const (
combinedLenSize = 4

// combinedIDOff is the offset from the start of the combined prefix to OID.
combinedIDOff = 1
combinedIDOff = 2

// combinedLengthOff is the offset from the start of the combined prefix to object length.
combinedLengthOff = combinedIDOff + oid.Size
Expand Down Expand Up @@ -365,6 +365,16 @@ func getRawObjectBytes(id oid.ID, p string) ([]byte, error) {
return data, nil
}

// parseCombinedPrefix checks the given array for combined data prefix and
// returns a subslice with OID and object length if so (nil and 0 otherwise).
func parseCombinedPrefix(p [combinedDataOff]byte) ([]byte, uint32) {
if p[0] != combinedPrefix || p[1] != 0 { // Only version 0 is supported now.
return nil, 0
}
return p[combinedIDOff:combinedLengthOff],
binary.BigEndian.Uint32(p[combinedLengthOff:combinedDataOff])
}

func extractCombinedObject(id oid.ID, f *os.File) ([]byte, error) {
var (
comBuf [combinedDataOff]byte
Expand All @@ -383,7 +393,8 @@ func extractCombinedObject(id oid.ID, f *os.File) ([]byte, error) {
}
return nil, err
}
if comBuf[0] != combinedPrefix {
thisOID, l := parseCombinedPrefix(comBuf)
if thisOID == nil {
st, err := f.Stat()
if err != nil {
return nil, err
Expand All @@ -401,8 +412,7 @@ func extractCombinedObject(id oid.ID, f *os.File) ([]byte, error) {
return data, nil
}
isCombined = true
var l = binary.BigEndian.Uint32(comBuf[combinedLengthOff:combinedDataOff])
if bytes.Equal(comBuf[combinedIDOff:combinedLengthOff], id[:]) {
if bytes.Equal(thisOID, id[:]) {
data = make([]byte, l)
_, err = io.ReadFull(f, data)
if err != nil {
Expand Down

0 comments on commit dfa8068

Please sign in to comment.