162 lines
3.0 KiB
Go
162 lines
3.0 KiB
Go
package common
|
|
|
|
import (
|
|
"fmt"
|
|
"hash/fnv"
|
|
"io"
|
|
"unsafe"
|
|
|
|
"go.etcd.io/bbolt/errors"
|
|
)
|
|
|
|
type Meta struct {
|
|
magic uint32
|
|
version uint32
|
|
pageSize uint32
|
|
flags uint32
|
|
root InBucket
|
|
freelist Pgid
|
|
pgid Pgid
|
|
txid Txid
|
|
checksum uint64
|
|
}
|
|
|
|
// Validate checks the marker bytes and version of the meta page to ensure it matches this binary.
|
|
func (m *Meta) Validate() error {
|
|
if m.magic != Magic {
|
|
return errors.ErrInvalid
|
|
} else if m.version != Version {
|
|
return errors.ErrVersionMismatch
|
|
} else if m.checksum != m.Sum64() {
|
|
return errors.ErrChecksum
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Copy copies one meta object to another.
|
|
func (m *Meta) Copy(dest *Meta) {
|
|
*dest = *m
|
|
}
|
|
|
|
// Write writes the meta onto a page.
|
|
func (m *Meta) Write(p *Page) {
|
|
if m.root.root >= m.pgid {
|
|
panic(fmt.Sprintf("root bucket pgid (%d) above high water mark (%d)", m.root.root, m.pgid))
|
|
} else if m.freelist >= m.pgid && m.freelist != PgidNoFreelist {
|
|
// TODO: reject pgidNoFreeList if !NoFreelistSync
|
|
panic(fmt.Sprintf("freelist pgid (%d) above high water mark (%d)", m.freelist, m.pgid))
|
|
}
|
|
|
|
// Page id is either going to be 0 or 1 which we can determine by the transaction ID.
|
|
p.id = Pgid(m.txid % 2)
|
|
p.SetFlags(MetaPageFlag)
|
|
|
|
// Calculate the checksum.
|
|
m.checksum = m.Sum64()
|
|
|
|
m.Copy(p.Meta())
|
|
}
|
|
|
|
// Sum64 generates the checksum for the meta.
|
|
func (m *Meta) Sum64() uint64 {
|
|
var h = fnv.New64a()
|
|
_, _ = h.Write((*[unsafe.Offsetof(Meta{}.checksum)]byte)(unsafe.Pointer(m))[:])
|
|
return h.Sum64()
|
|
}
|
|
|
|
func (m *Meta) Magic() uint32 {
|
|
return m.magic
|
|
}
|
|
|
|
func (m *Meta) SetMagic(v uint32) {
|
|
m.magic = v
|
|
}
|
|
|
|
func (m *Meta) Version() uint32 {
|
|
return m.version
|
|
}
|
|
|
|
func (m *Meta) SetVersion(v uint32) {
|
|
m.version = v
|
|
}
|
|
|
|
func (m *Meta) PageSize() uint32 {
|
|
return m.pageSize
|
|
}
|
|
|
|
func (m *Meta) SetPageSize(v uint32) {
|
|
m.pageSize = v
|
|
}
|
|
|
|
func (m *Meta) Flags() uint32 {
|
|
return m.flags
|
|
}
|
|
|
|
func (m *Meta) SetFlags(v uint32) {
|
|
m.flags = v
|
|
}
|
|
|
|
func (m *Meta) SetRootBucket(b InBucket) {
|
|
m.root = b
|
|
}
|
|
|
|
func (m *Meta) RootBucket() *InBucket {
|
|
return &m.root
|
|
}
|
|
|
|
func (m *Meta) Freelist() Pgid {
|
|
return m.freelist
|
|
}
|
|
|
|
func (m *Meta) SetFreelist(v Pgid) {
|
|
m.freelist = v
|
|
}
|
|
|
|
func (m *Meta) IsFreelistPersisted() bool {
|
|
return m.freelist != PgidNoFreelist
|
|
}
|
|
|
|
func (m *Meta) Pgid() Pgid {
|
|
return m.pgid
|
|
}
|
|
|
|
func (m *Meta) SetPgid(id Pgid) {
|
|
m.pgid = id
|
|
}
|
|
|
|
func (m *Meta) Txid() Txid {
|
|
return m.txid
|
|
}
|
|
|
|
func (m *Meta) SetTxid(id Txid) {
|
|
m.txid = id
|
|
}
|
|
|
|
func (m *Meta) IncTxid() {
|
|
m.txid += 1
|
|
}
|
|
|
|
func (m *Meta) DecTxid() {
|
|
m.txid -= 1
|
|
}
|
|
|
|
func (m *Meta) Checksum() uint64 {
|
|
return m.checksum
|
|
}
|
|
|
|
func (m *Meta) SetChecksum(v uint64) {
|
|
m.checksum = v
|
|
}
|
|
|
|
func (m *Meta) Print(w io.Writer) {
|
|
fmt.Fprintf(w, "Version: %d\n", m.version)
|
|
fmt.Fprintf(w, "Page Size: %d bytes\n", m.pageSize)
|
|
fmt.Fprintf(w, "Flags: %08x\n", m.flags)
|
|
fmt.Fprintf(w, "Root: <pgid=%d>\n", m.root.root)
|
|
fmt.Fprintf(w, "Freelist: <pgid=%d>\n", m.freelist)
|
|
fmt.Fprintf(w, "HWM: <pgid=%d>\n", m.pgid)
|
|
fmt.Fprintf(w, "Txn ID: %d\n", m.txid)
|
|
fmt.Fprintf(w, "Checksum: %016x\n", m.checksum)
|
|
fmt.Fprintf(w, "\n")
|
|
}
|