init headers
This commit is contained in:
parent
91a26dd76e
commit
a35d6b836a
3 changed files with 137 additions and 0 deletions
69
pkg/headers/headers.go
Normal file
69
pkg/headers/headers.go
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
// Package headers provides headers for the db binary files
|
||||||
|
package headers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Headers struct {
|
||||||
|
HeaderString []byte // Header string
|
||||||
|
PageSize uint64 // Page size for chunks
|
||||||
|
DBVersion uint16 // Version of the db
|
||||||
|
|
||||||
|
// Reserved for future use.
|
||||||
|
WAL bool // Enable write-ahead-logging
|
||||||
|
Commit []byte // SHA256 sum of the current DB - Could be switched to ULID/UUID in future.
|
||||||
|
}
|
||||||
|
|
||||||
|
// constant HeaderString
|
||||||
|
const HeaderString = "zutto/db/"
|
||||||
|
|
||||||
|
//Commit data length - mapped to be 32 bytes for now, to match SHA256SUM
|
||||||
|
const CommitDataLength = 32
|
||||||
|
|
||||||
|
// Static lengths of the headers HeaderString length(uint16, 2 bytes)- Pagesize (uint64, 8 bytes) + DBVersion (int16, 2 bytes) + WAL (int8//bool, 1 byte) + Commit (SHA256 32 bytes)
|
||||||
|
const StaticHeadersLength = 13 + CommitDataLength
|
||||||
|
|
||||||
|
// Generate generates []byte output from the headers
|
||||||
|
func (h *Headers) Generate() *[]byte {
|
||||||
|
var HeaderStringLength int = len(h.HeaderString)
|
||||||
|
|
||||||
|
//Output array
|
||||||
|
var data []byte = make([]byte, HeaderStringLength+StaticHeadersLength)
|
||||||
|
|
||||||
|
//Headerstring
|
||||||
|
binary.LittleEndian.PutUint16(data[0:2], uint16(HeaderStringLength))
|
||||||
|
copy(data[2:2+HeaderStringLength], h.HeaderString[:])
|
||||||
|
|
||||||
|
//add the simpler metadata
|
||||||
|
binary.LittleEndian.PutUint64(data[2+HeaderStringLength:10+HeaderStringLength], h.PageSize)
|
||||||
|
binary.LittleEndian.PutUint16(data[10+HeaderStringLength:12+HeaderStringLength], h.DBVersion)
|
||||||
|
|
||||||
|
//Convert bool-value to byte with a helper function true = byte(1), false = byte(0)
|
||||||
|
data[12+HeaderStringLength] = ToSingleByte(h.WAL)
|
||||||
|
|
||||||
|
//commit data, extr
|
||||||
|
copy(data[13+HeaderStringLength:13+CommitDataLength+HeaderStringLength], h.Commit[0:CommitDataLength])
|
||||||
|
|
||||||
|
return &data
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse parses the headers
|
||||||
|
// Accepts 2 parameters, Input *[]byte's and Padding
|
||||||
|
// Returns error in case of errors.
|
||||||
|
func (h *Headers) Parse(Input *[]byte, Padding int) error {
|
||||||
|
if Padding+len((*Input)) < StaticHeadersLength {
|
||||||
|
return errors.New("Input was not correct length")
|
||||||
|
}
|
||||||
|
|
||||||
|
var HeaderStringLength int = int(binary.LittleEndian.Uint16((*Input)[Padding : Padding+2]))
|
||||||
|
h.HeaderString = (*Input)[2+Padding : Padding+2+HeaderStringLength]
|
||||||
|
h.PageSize = binary.LittleEndian.Uint64((*Input)[2+HeaderStringLength+Padding : Padding+10+HeaderStringLength])
|
||||||
|
h.DBVersion = binary.LittleEndian.Uint16((*Input)[10+HeaderStringLength+Padding : Padding+12+HeaderStringLength])
|
||||||
|
|
||||||
|
h.WAL = ByteToBool((*Input)[12+HeaderStringLength])
|
||||||
|
h.Commit = ((*Input)[13+HeaderStringLength+Padding : Padding+13+CommitDataLength+HeaderStringLength])
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
33
pkg/headers/headers_test.go
Normal file
33
pkg/headers/headers_test.go
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
package headers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestHeaders_Generate(t *testing.T) {
|
||||||
|
|
||||||
|
h := Headers{
|
||||||
|
HeaderString: []byte(HeaderString),
|
||||||
|
PageSize: uint64(256 ^ 2),
|
||||||
|
DBVersion: uint16(1),
|
||||||
|
|
||||||
|
WAL: true,
|
||||||
|
Commit: make([]byte, CommitDataLength),
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := rand.Read(h.Commit[:CommitDataLength])
|
||||||
|
if err != nil {
|
||||||
|
t.Error("Failed to generate random string")
|
||||||
|
}
|
||||||
|
|
||||||
|
output := h.Generate()
|
||||||
|
|
||||||
|
h2 := Headers{}
|
||||||
|
h2.Parse(output, 0)
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(h, h2) {
|
||||||
|
t.Error("deepequal failed")
|
||||||
|
}
|
||||||
|
}
|
35
pkg/headers/helper.go
Normal file
35
pkg/headers/helper.go
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
package headers
|
||||||
|
|
||||||
|
// ByteHelper provides helping functions to less-fun-types
|
||||||
|
type SingleByteType interface {
|
||||||
|
bool | ~uint8
|
||||||
|
}
|
||||||
|
type BoolType interface {
|
||||||
|
bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func ByteToBool(Input byte) bool {
|
||||||
|
if byte(1) == Input {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToSingleByte converts single-byte types, such as int8 and bool to single bytes.
|
||||||
|
func ToSingleByte[T SingleByteType](input T) byte {
|
||||||
|
switch input := any(input).(type) {
|
||||||
|
case uint8:
|
||||||
|
return byte(input)
|
||||||
|
case int8:
|
||||||
|
return byte(input)
|
||||||
|
case bool:
|
||||||
|
if input {
|
||||||
|
return byte(1)
|
||||||
|
} else {
|
||||||
|
return byte(0)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return byte(-0)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue