blob: 055388604af81439feb90080b333b439f7af7869 [file] [log] [blame]
Abhay Kumara2ae5992025-11-10 14:02:24 +00001package common
2
3import (
4 "fmt"
5 "hash/fnv"
6 "io"
7 "unsafe"
8
9 "go.etcd.io/bbolt/errors"
10)
11
12type Meta struct {
13 magic uint32
14 version uint32
15 pageSize uint32
16 flags uint32
17 root InBucket
18 freelist Pgid
19 pgid Pgid
20 txid Txid
21 checksum uint64
22}
23
24// Validate checks the marker bytes and version of the meta page to ensure it matches this binary.
25func (m *Meta) Validate() error {
26 if m.magic != Magic {
27 return errors.ErrInvalid
28 } else if m.version != Version {
29 return errors.ErrVersionMismatch
30 } else if m.checksum != m.Sum64() {
31 return errors.ErrChecksum
32 }
33 return nil
34}
35
36// Copy copies one meta object to another.
37func (m *Meta) Copy(dest *Meta) {
38 *dest = *m
39}
40
41// Write writes the meta onto a page.
42func (m *Meta) Write(p *Page) {
43 if m.root.root >= m.pgid {
44 panic(fmt.Sprintf("root bucket pgid (%d) above high water mark (%d)", m.root.root, m.pgid))
45 } else if m.freelist >= m.pgid && m.freelist != PgidNoFreelist {
46 // TODO: reject pgidNoFreeList if !NoFreelistSync
47 panic(fmt.Sprintf("freelist pgid (%d) above high water mark (%d)", m.freelist, m.pgid))
48 }
49
50 // Page id is either going to be 0 or 1 which we can determine by the transaction ID.
51 p.id = Pgid(m.txid % 2)
52 p.SetFlags(MetaPageFlag)
53
54 // Calculate the checksum.
55 m.checksum = m.Sum64()
56
57 m.Copy(p.Meta())
58}
59
60// Sum64 generates the checksum for the meta.
61func (m *Meta) Sum64() uint64 {
62 var h = fnv.New64a()
63 _, _ = h.Write((*[unsafe.Offsetof(Meta{}.checksum)]byte)(unsafe.Pointer(m))[:])
64 return h.Sum64()
65}
66
67func (m *Meta) Magic() uint32 {
68 return m.magic
69}
70
71func (m *Meta) SetMagic(v uint32) {
72 m.magic = v
73}
74
75func (m *Meta) Version() uint32 {
76 return m.version
77}
78
79func (m *Meta) SetVersion(v uint32) {
80 m.version = v
81}
82
83func (m *Meta) PageSize() uint32 {
84 return m.pageSize
85}
86
87func (m *Meta) SetPageSize(v uint32) {
88 m.pageSize = v
89}
90
91func (m *Meta) Flags() uint32 {
92 return m.flags
93}
94
95func (m *Meta) SetFlags(v uint32) {
96 m.flags = v
97}
98
99func (m *Meta) SetRootBucket(b InBucket) {
100 m.root = b
101}
102
103func (m *Meta) RootBucket() *InBucket {
104 return &m.root
105}
106
107func (m *Meta) Freelist() Pgid {
108 return m.freelist
109}
110
111func (m *Meta) SetFreelist(v Pgid) {
112 m.freelist = v
113}
114
115func (m *Meta) IsFreelistPersisted() bool {
116 return m.freelist != PgidNoFreelist
117}
118
119func (m *Meta) Pgid() Pgid {
120 return m.pgid
121}
122
123func (m *Meta) SetPgid(id Pgid) {
124 m.pgid = id
125}
126
127func (m *Meta) Txid() Txid {
128 return m.txid
129}
130
131func (m *Meta) SetTxid(id Txid) {
132 m.txid = id
133}
134
135func (m *Meta) IncTxid() {
136 m.txid += 1
137}
138
139func (m *Meta) DecTxid() {
140 m.txid -= 1
141}
142
143func (m *Meta) Checksum() uint64 {
144 return m.checksum
145}
146
147func (m *Meta) SetChecksum(v uint64) {
148 m.checksum = v
149}
150
151func (m *Meta) Print(w io.Writer) {
152 fmt.Fprintf(w, "Version: %d\n", m.version)
153 fmt.Fprintf(w, "Page Size: %d bytes\n", m.pageSize)
154 fmt.Fprintf(w, "Flags: %08x\n", m.flags)
155 fmt.Fprintf(w, "Root: <pgid=%d>\n", m.root.root)
156 fmt.Fprintf(w, "Freelist: <pgid=%d>\n", m.freelist)
157 fmt.Fprintf(w, "HWM: <pgid=%d>\n", m.pgid)
158 fmt.Fprintf(w, "Txn ID: %d\n", m.txid)
159 fmt.Fprintf(w, "Checksum: %016x\n", m.checksum)
160 fmt.Fprintf(w, "\n")
161}