blob: b5c16997891807525c9264eca5555fcb55a715f7 [file] [log] [blame]
khenaidood948f772021-08-11 17:49:24 -04001package bbolt
2
3import (
4 "fmt"
5 "os"
6 "reflect"
7 "sort"
8 "unsafe"
9)
10
11const pageHeaderSize = unsafe.Sizeof(page{})
12
13const minKeysPerPage = 2
14
15const branchPageElementSize = unsafe.Sizeof(branchPageElement{})
16const leafPageElementSize = unsafe.Sizeof(leafPageElement{})
17
18const (
19 branchPageFlag = 0x01
20 leafPageFlag = 0x02
21 metaPageFlag = 0x04
22 freelistPageFlag = 0x10
23)
24
25const (
26 bucketLeafFlag = 0x01
27)
28
29type pgid uint64
30
31type page struct {
32 id pgid
33 flags uint16
34 count uint16
35 overflow uint32
36}
37
38// typ returns a human readable page type string used for debugging.
39func (p *page) typ() string {
40 if (p.flags & branchPageFlag) != 0 {
41 return "branch"
42 } else if (p.flags & leafPageFlag) != 0 {
43 return "leaf"
44 } else if (p.flags & metaPageFlag) != 0 {
45 return "meta"
46 } else if (p.flags & freelistPageFlag) != 0 {
47 return "freelist"
48 }
49 return fmt.Sprintf("unknown<%02x>", p.flags)
50}
51
52// meta returns a pointer to the metadata section of the page.
53func (p *page) meta() *meta {
54 return (*meta)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + unsafe.Sizeof(*p)))
55}
56
57// leafPageElement retrieves the leaf node by index
58func (p *page) leafPageElement(index uint16) *leafPageElement {
59 off := uintptr(index) * unsafe.Sizeof(leafPageElement{})
60 return (*leafPageElement)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + unsafe.Sizeof(*p) + off))
61}
62
63// leafPageElements retrieves a list of leaf nodes.
64func (p *page) leafPageElements() []leafPageElement {
65 if p.count == 0 {
66 return nil
67 }
68 return *(*[]leafPageElement)(unsafe.Pointer(&reflect.SliceHeader{
69 Data: uintptr(unsafe.Pointer(p)) + unsafe.Sizeof(*p),
70 Len: int(p.count),
71 Cap: int(p.count),
72 }))
73}
74
75// branchPageElement retrieves the branch node by index
76func (p *page) branchPageElement(index uint16) *branchPageElement {
77 off := uintptr(index) * unsafe.Sizeof(branchPageElement{})
78 return (*branchPageElement)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + unsafe.Sizeof(*p) + off))
79}
80
81// branchPageElements retrieves a list of branch nodes.
82func (p *page) branchPageElements() []branchPageElement {
83 if p.count == 0 {
84 return nil
85 }
86 return *(*[]branchPageElement)(unsafe.Pointer(&reflect.SliceHeader{
87 Data: uintptr(unsafe.Pointer(p)) + unsafe.Sizeof(*p),
88 Len: int(p.count),
89 Cap: int(p.count),
90 }))
91}
92
93// dump writes n bytes of the page to STDERR as hex output.
94func (p *page) hexdump(n int) {
95 buf := *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
96 Data: uintptr(unsafe.Pointer(p)),
97 Len: n,
98 Cap: n,
99 }))
100 fmt.Fprintf(os.Stderr, "%x\n", buf)
101}
102
103type pages []*page
104
105func (s pages) Len() int { return len(s) }
106func (s pages) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
107func (s pages) Less(i, j int) bool { return s[i].id < s[j].id }
108
109// branchPageElement represents a node on a branch page.
110type branchPageElement struct {
111 pos uint32
112 ksize uint32
113 pgid pgid
114}
115
116// key returns a byte slice of the node key.
117func (n *branchPageElement) key() []byte {
118 return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
119 Data: uintptr(unsafe.Pointer(n)) + uintptr(n.pos),
120 Len: int(n.ksize),
121 Cap: int(n.ksize),
122 }))
123}
124
125// leafPageElement represents a node on a leaf page.
126type leafPageElement struct {
127 flags uint32
128 pos uint32
129 ksize uint32
130 vsize uint32
131}
132
133// key returns a byte slice of the node key.
134func (n *leafPageElement) key() []byte {
135 return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
136 Data: uintptr(unsafe.Pointer(n)) + uintptr(n.pos),
137 Len: int(n.ksize),
138 Cap: int(n.ksize),
139 }))
140}
141
142// value returns a byte slice of the node value.
143func (n *leafPageElement) value() []byte {
144 return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
145 Data: uintptr(unsafe.Pointer(n)) + uintptr(n.pos) + uintptr(n.ksize),
146 Len: int(n.vsize),
147 Cap: int(n.vsize),
148 }))
149}
150
151// PageInfo represents human readable information about a page.
152type PageInfo struct {
153 ID int
154 Type string
155 Count int
156 OverflowCount int
157}
158
159type pgids []pgid
160
161func (s pgids) Len() int { return len(s) }
162func (s pgids) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
163func (s pgids) Less(i, j int) bool { return s[i] < s[j] }
164
165// merge returns the sorted union of a and b.
166func (a pgids) merge(b pgids) pgids {
167 // Return the opposite slice if one is nil.
168 if len(a) == 0 {
169 return b
170 }
171 if len(b) == 0 {
172 return a
173 }
174 merged := make(pgids, len(a)+len(b))
175 mergepgids(merged, a, b)
176 return merged
177}
178
179// mergepgids copies the sorted union of a and b into dst.
180// If dst is too small, it panics.
181func mergepgids(dst, a, b pgids) {
182 if len(dst) < len(a)+len(b) {
183 panic(fmt.Errorf("mergepgids bad len %d < %d + %d", len(dst), len(a), len(b)))
184 }
185 // Copy in the opposite slice if one is nil.
186 if len(a) == 0 {
187 copy(dst, b)
188 return
189 }
190 if len(b) == 0 {
191 copy(dst, a)
192 return
193 }
194
195 // Merged will hold all elements from both lists.
196 merged := dst[:0]
197
198 // Assign lead to the slice with a lower starting value, follow to the higher value.
199 lead, follow := a, b
200 if b[0] < a[0] {
201 lead, follow = b, a
202 }
203
204 // Continue while there are elements in the lead.
205 for len(lead) > 0 {
206 // Merge largest prefix of lead that is ahead of follow[0].
207 n := sort.Search(len(lead), func(i int) bool { return lead[i] > follow[0] })
208 merged = append(merged, lead[:n]...)
209 if n >= len(lead) {
210 break
211 }
212
213 // Swap lead and follow.
214 lead, follow = follow, lead[n:]
215 }
216
217 // Append what's left in follow.
218 _ = append(merged, follow...)
219}