-
Notifications
You must be signed in to change notification settings - Fork 1
/
ipkvs.go
131 lines (103 loc) · 2.12 KB
/
ipkvs.go
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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package ipkvs
import (
"errors"
"sync"
"gopkg.in/vmihailenco/msgpack.v2"
)
const (
// Memory word size. Must be 8 for 64bit or 4 for 32bit
wordSize = 8
// Block size in words
blockSize = 4
// Page size in blocks
pageSize = 524288
)
type (
IpKVs struct {
sync.RWMutex
entries map[uint64]uint
freed map[uint]struct{}
pages []page
nextBlock uint
Logger LoggerFunc
}
LoggerFunc func(msg string, args ...interface{})
)
var (
ErrorBigValue = errors.New("value is too big")
ErrorFound = errors.New("key already found")
)
func NewIpKvs() *IpKVs {
return &IpKVs{
entries: map[uint64]uint{},
freed: map[uint]struct{}{},
pages: []page{},
nextBlock: 0,
}
}
func (c *IpKVs) block() uint {
for r, _ := range c.freed {
delete(c.freed, r)
return r
}
r := c.nextBlock
c.nextBlock += 1
return r
}
func (c *IpKVs) address(block uint) (int, int) {
return int(block / uint(pageSize)),
int(block % uint(pageSize))
}
func (c *IpKVs) CreateMsgPack(key string, value interface{}) error {
d, err := msgpack.Marshal(value)
if err != nil {
return err
}
return c.Create(key, d)
}
func (c *IpKVs) Create(key string, value []byte) error {
if len(value) > blockSize*wordSize {
return ErrorBigValue
}
hash := FNV1a(key)
if _, ok := c.entries[hash]; ok {
return ErrorFound
}
c.Lock()
defer c.Unlock()
b := c.block()
p, o := c.address(b)
for len(c.pages) < p+1 {
c.pages = append(c.pages, page{})
}
c.pages[p][o].number = b
for i := 0; i < len(value); i += 1 {
c.pages[p][o].data[i] = value[i]
}
c.pages[p][o].len = len(value)
c.entries[hash] = b
return nil
}
func (c *IpKVs) ReadMsgPack(key string, value interface{}) error {
return msgpack.Unmarshal(c.Read(key), value)
}
func (c *IpKVs) Read(key string) []byte {
hash := FNV1a(key)
c.RLock()
defer c.RUnlock()
b, ok := c.entries[hash]
if !ok {
return nil
}
p, o := c.address(b)
return c.pages[p][o].data[:c.pages[p][o].len]
}
func (c *IpKVs) Delete(key string) {
hash := FNV1a(key)
c.Lock()
defer c.Unlock()
if block, ok := c.entries[hash]; ok {
delete(c.entries, hash)
c.freed[block] = struct{}{}
}
}