1 package guts_cli
2
3
4
5
6
7 import (
8 "errors"
9 "fmt"
10 "io"
11 "os"
12 "unsafe"
13 )
14
15 var (
16
17 ErrCorrupt = errors.New("invalid value")
18 )
19
20
21 const PageHeaderSize = 16
22
23
24 const magic uint32 = 0xED0CDAED
25
26
27 const maxAllocSize = 0xFFFFFFF
28
29
30 const (
31 branchPageFlag = 0x01
32 leafPageFlag = 0x02
33 metaPageFlag = 0x04
34 freelistPageFlag = 0x10
35 )
36
37
38 const bucketLeafFlag = 0x01
39
40
41 type Pgid uint64
42
43
44 type txid uint64
45
46
47 type Meta struct {
48 magic uint32
49 version uint32
50 pageSize uint32
51 flags uint32
52 root Bucket
53 freelist Pgid
54 pgid Pgid
55 txid txid
56 checksum uint64
57 }
58
59 func LoadPageMeta(buf []byte) *Meta {
60 return (*Meta)(unsafe.Pointer(&buf[PageHeaderSize]))
61 }
62
63 func (m *Meta) RootBucket() *Bucket {
64 return &m.root
65 }
66
67 func (m *Meta) Txid() uint64 {
68 return uint64(m.txid)
69 }
70
71 func (m *Meta) Print(w io.Writer) {
72 fmt.Fprintf(w, "Version: %d\n", m.version)
73 fmt.Fprintf(w, "Page Size: %d bytes\n", m.pageSize)
74 fmt.Fprintf(w, "Flags: %08x\n", m.flags)
75 fmt.Fprintf(w, "Root: <pgid=%d>\n", m.root.root)
76 fmt.Fprintf(w, "Freelist: <pgid=%d>\n", m.freelist)
77 fmt.Fprintf(w, "HWM: <pgid=%d>\n", m.pgid)
78 fmt.Fprintf(w, "Txn ID: %d\n", m.txid)
79 fmt.Fprintf(w, "Checksum: %016x\n", m.checksum)
80 fmt.Fprintf(w, "\n")
81 }
82
83
84 type Bucket struct {
85 root Pgid
86 sequence uint64
87 }
88
89 const bucketHeaderSize = int(unsafe.Sizeof(Bucket{}))
90
91 func LoadBucket(buf []byte) *Bucket {
92 return (*Bucket)(unsafe.Pointer(&buf[0]))
93 }
94
95 func (b *Bucket) String() string {
96 return fmt.Sprintf("<pgid=%d,seq=%d>", b.root, b.sequence)
97 }
98
99 func (b *Bucket) RootPage() Pgid {
100 return b.root
101 }
102
103 func (b *Bucket) InlinePage(v []byte) *Page {
104 return (*Page)(unsafe.Pointer(&v[bucketHeaderSize]))
105 }
106
107
108 type Page struct {
109 id Pgid
110 flags uint16
111 count uint16
112 overflow uint32
113 ptr uintptr
114 }
115
116 func LoadPage(buf []byte) *Page {
117 return (*Page)(unsafe.Pointer(&buf[0]))
118 }
119
120 func (p *Page) FreelistPageCount() int {
121
122 if p.count == 0xFFFF {
123 return int(((*[maxAllocSize]Pgid)(unsafe.Pointer(&p.ptr)))[0])
124 } else {
125 return int(p.count)
126 }
127 }
128
129 func (p *Page) FreelistPagePages() []Pgid {
130
131 idx := 0
132 if p.count == 0xFFFF {
133 idx = 1
134 }
135 return (*[maxAllocSize]Pgid)(unsafe.Pointer(&p.ptr))[idx:p.FreelistPageCount()]
136 }
137
138 func (p *Page) Overflow() uint32 {
139 return p.overflow
140 }
141
142 func (p *Page) String() string {
143 return fmt.Sprintf("ID: %d, Type: %s, count: %d, overflow: %d", p.id, p.Type(), p.count, p.overflow)
144 }
145
146
147
148
149 func (p *Page) Type() string {
150 if (p.flags & branchPageFlag) != 0 {
151 return "branch"
152 } else if (p.flags & leafPageFlag) != 0 {
153 return "leaf"
154 } else if (p.flags & metaPageFlag) != 0 {
155 return "meta"
156 } else if (p.flags & freelistPageFlag) != 0 {
157 return "freelist"
158 }
159 return fmt.Sprintf("unknown<%02x>", p.flags)
160 }
161
162 func (p *Page) Count() uint16 {
163 return p.count
164 }
165
166 func (p *Page) Id() Pgid {
167 return p.id
168 }
169
170
171 func (p *Page) LeafPageElement(index uint16) *LeafPageElement {
172 n := &((*[0x7FFFFFF]LeafPageElement)(unsafe.Pointer(&p.ptr)))[index]
173 return n
174 }
175
176
177 func (p *Page) BranchPageElement(index uint16) *BranchPageElement {
178 return &((*[0x7FFFFFF]BranchPageElement)(unsafe.Pointer(&p.ptr)))[index]
179 }
180
181 func (p *Page) SetId(target Pgid) {
182 p.id = target
183 }
184
185 func (p *Page) SetCount(target uint16) {
186 p.count = target
187 }
188
189 func (p *Page) SetOverflow(target uint32) {
190 p.overflow = target
191 }
192
193
194 type BranchPageElement struct {
195 pos uint32
196 ksize uint32
197 pgid Pgid
198 }
199
200
201 func (n *BranchPageElement) Key() []byte {
202 buf := (*[maxAllocSize]byte)(unsafe.Pointer(n))
203 return buf[n.pos : n.pos+n.ksize]
204 }
205
206 func (n *BranchPageElement) PgId() Pgid {
207 return n.pgid
208 }
209
210
211 type LeafPageElement struct {
212 flags uint32
213 pos uint32
214 ksize uint32
215 vsize uint32
216 }
217
218
219 func (n *LeafPageElement) Key() []byte {
220 buf := (*[maxAllocSize]byte)(unsafe.Pointer(n))
221 return buf[n.pos : n.pos+n.ksize]
222 }
223
224
225 func (n *LeafPageElement) Value() []byte {
226 buf := (*[maxAllocSize]byte)(unsafe.Pointer(n))
227 return buf[n.pos+n.ksize : n.pos+n.ksize+n.vsize]
228 }
229
230 func (n *LeafPageElement) IsBucketEntry() bool {
231 return n.flags&uint32(bucketLeafFlag) != 0
232 }
233
234 func (n *LeafPageElement) Bucket() *Bucket {
235 if n.IsBucketEntry() {
236 return LoadBucket(n.Value())
237 } else {
238 return nil
239 }
240 }
241
242
243
244 func ReadPage(path string, pageID uint64) (*Page, []byte, error) {
245
246 pageSize, hwm, err := ReadPageAndHWMSize(path)
247 if err != nil {
248 return nil, nil, fmt.Errorf("read Page size: %s", err)
249 }
250
251
252 f, err := os.Open(path)
253 if err != nil {
254 return nil, nil, err
255 }
256 defer f.Close()
257
258
259 buf := make([]byte, pageSize)
260 if n, err := f.ReadAt(buf, int64(pageID*pageSize)); err != nil {
261 return nil, nil, err
262 } else if n != len(buf) {
263 return nil, nil, io.ErrUnexpectedEOF
264 }
265
266
267 p := LoadPage(buf)
268 if p.id != Pgid(pageID) {
269 return nil, nil, fmt.Errorf("error: %w due to unexpected Page id: %d != %d", ErrCorrupt, p.id, pageID)
270 }
271 overflowN := p.overflow
272 if overflowN >= uint32(hwm)-3 {
273 return nil, nil, fmt.Errorf("error: %w, Page claims to have %d overflow pages (>=hwm=%d). Interrupting to avoid risky OOM", ErrCorrupt, overflowN, hwm)
274 }
275
276
277 buf = make([]byte, (uint64(overflowN)+1)*pageSize)
278 if n, err := f.ReadAt(buf, int64(pageID*pageSize)); err != nil {
279 return nil, nil, err
280 } else if n != len(buf) {
281 return nil, nil, io.ErrUnexpectedEOF
282 }
283 p = LoadPage(buf)
284 if p.id != Pgid(pageID) {
285 return nil, nil, fmt.Errorf("error: %w due to unexpected Page id: %d != %d", ErrCorrupt, p.id, pageID)
286 }
287
288 return p, buf, nil
289 }
290
291 func WritePage(path string, pageBuf []byte) error {
292 page := LoadPage(pageBuf)
293 pageSize, _, err := ReadPageAndHWMSize(path)
294 if err != nil {
295 return err
296 }
297 expectedLen := pageSize * (uint64(page.Overflow()) + 1)
298 if expectedLen != uint64(len(pageBuf)) {
299 return fmt.Errorf("WritePage: len(buf):%d != pageSize*(overflow+1):%d", len(pageBuf), expectedLen)
300 }
301 f, err := os.OpenFile(path, os.O_WRONLY, 0)
302 if err != nil {
303 return err
304 }
305 defer f.Close()
306 _, err = f.WriteAt(pageBuf, int64(page.Id())*int64(pageSize))
307 return err
308 }
309
310
311
312 func ReadPageAndHWMSize(path string) (uint64, Pgid, error) {
313
314 f, err := os.Open(path)
315 if err != nil {
316 return 0, 0, err
317 }
318 defer f.Close()
319
320
321 buf := make([]byte, 4096)
322 if _, err := io.ReadFull(f, buf); err != nil {
323 return 0, 0, err
324 }
325
326
327 m := LoadPageMeta(buf)
328 if m.magic != magic {
329 return 0, 0, fmt.Errorf("the Meta Page has wrong (unexpected) magic")
330 }
331 return uint64(m.pageSize), Pgid(m.pgid), nil
332 }
333
334
335 func GetRootPage(path string) (root Pgid, activeMeta Pgid, err error) {
336 _, buf0, err0 := ReadPage(path, 0)
337 if err0 != nil {
338 return 0, 0, err0
339 }
340 m0 := LoadPageMeta(buf0)
341 _, buf1, err1 := ReadPage(path, 1)
342 if err1 != nil {
343 return 0, 1, err1
344 }
345 m1 := LoadPageMeta(buf1)
346 if m0.txid < m1.txid {
347 return m1.root.root, 1, nil
348 } else {
349 return m0.root.root, 0, nil
350 }
351 }
352
View as plain text