aboutsummaryrefslogtreecommitdiff
path: root/sys.go
blob: ec1b858d4c4cbc295e23ab0d6b4d03a4945d5c9c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package bolt

import (
	"sort"
	"unsafe"
)

// sys represents a in-memory system page.
type sys struct {
	pgid    pgid
	buckets map[string]*bucket
}

// size returns the size of the page after serialization.
func (s *sys) size() int {
	var size int = pageHeaderSize
	for key, _ := range s.buckets {
		size += int(unsafe.Sizeof(bucket{})) + len(key)
	}
	return size
}

// get retrieves a bucket by name.
func (s *sys) get(key string) *bucket {
	return s.buckets[key]
}

// put sets a new value for a bucket.
func (s *sys) put(key string, b *bucket) {
	s.buckets[key] = b
}

// del deletes a bucket by name.
func (s *sys) del(key string) {
	if b := s.buckets[key]; b != nil {
		delete(s.buckets, key)
	}
}

// read initializes the data from an on-disk page.
func (s *sys) read(p *page) {
	s.pgid = p.id
	s.buckets = make(map[string]*bucket)

	var buckets []*bucket
	var keys []string

	// Read buckets.
	nodes := (*[maxNodesPerPage]bucket)(unsafe.Pointer(&p.ptr))
	for i := 0; i < int(p.count); i++ {
		node := &nodes[i]
		buckets = append(buckets, node)
	}

	// Read keys.
	buf := (*[maxAllocSize]byte)(unsafe.Pointer(&nodes[p.count]))[:]
	for i := 0; i < int(p.count); i++ {
		size := int(buf[0])
		buf = buf[1:]
		keys = append(keys, string(buf[:size]))
		buf = buf[size:]
	}

	// Associate keys and buckets.
	for index, key := range keys {
		b := &bucket{buckets[index].root}
		s.buckets[key] = b
	}
}

// write writes the items onto a page.
func (s *sys) write(p *page) {
	// Initialize page.
	p.flags |= p_sys
	p.count = uint16(len(s.buckets))

	// Sort keys.
	var keys []string
	for key, _ := range s.buckets {
		keys = append(keys, key)
	}
	sort.StringSlice(keys).Sort()

	// Write each bucket to the page.
	buckets := (*[maxNodesPerPage]bucket)(unsafe.Pointer(&p.ptr))
	for index, key := range keys {
		buckets[index] = *s.buckets[key]
	}

	// Write each key to the page.
	buf := (*[maxAllocSize]byte)(unsafe.Pointer(&buckets[p.count]))[:]
	for _, key := range keys {
		buf[0] = byte(len(key))
		buf = buf[1:]
		copy(buf, []byte(key))
		buf = buf[len(key):]
	}
}