-
Notifications
You must be signed in to change notification settings - Fork 4
/
memory.go
158 lines (143 loc) · 4.09 KB
/
memory.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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package storage
import (
"fmt"
"sort"
"zircon/apis"
)
type MemoryStorage struct {
isClosed bool
chunks map[apis.ChunkNum]map[apis.Version][]byte
latest map[apis.ChunkNum]apis.Version
}
// Creates an in-memory-only location to store data, and construct an interface by which a chunkserver can store chunks
func ConfigureMemoryStorage() (ChunkStorage, error) {
return &MemoryStorage{
chunks: map[apis.ChunkNum]map[apis.Version][]byte{},
latest: map[apis.ChunkNum]apis.Version{},
}, nil
}
// returns semi-fake storage usage stats for testing
func (m *MemoryStorage) StatsForTesting() int {
if m.isClosed {
panic("attempt to use closed MemoryStorage")
}
chunkCount := 0
for _, v := range m.chunks {
chunkCount += len(v)
}
entryCount := len(m.chunks) + len(m.latest) + chunkCount
// let's approximate 32 bytes per hash table entry
// and 8 MB per chunk of data
return entryCount*32 + chunkCount*int(apis.MaxChunkSize)
}
func (m *MemoryStorage) assertOpen() {
if m.isClosed {
panic("attempt to use closed MemoryStorage")
}
}
func (m *MemoryStorage) ListChunksWithData() ([]apis.ChunkNum, error) {
m.assertOpen()
result := make([]apis.ChunkNum, 0, len(m.chunks))
for k, v := range m.chunks {
if len(v) > 0 {
result = append(result, k)
}
}
return result, nil
}
func (m *MemoryStorage) ListVersions(chunk apis.ChunkNum) ([]apis.Version, error) {
m.assertOpen()
versionMap := m.chunks[chunk]
if versionMap == nil {
return nil, nil
}
result := make([]apis.Version, 0, len(versionMap))
for k, _ := range versionMap {
result = append(result, k)
}
sort.Slice(result, func(i, j int) bool {
return result[i] < result[j]
})
return result, nil
}
func (m *MemoryStorage) ReadVersion(chunk apis.ChunkNum, version apis.Version) ([]byte, error) {
m.assertOpen()
if versionMap := m.chunks[chunk]; versionMap != nil {
if data, found := versionMap[version]; found {
ndata := make([]byte, len(data))
copy(ndata, data)
return ndata, nil
}
}
return nil, fmt.Errorf("no such chunk/version combination: %d/%d", chunk, version)
}
func (m *MemoryStorage) WriteVersion(chunk apis.ChunkNum, version apis.Version, data []byte) error {
m.assertOpen()
if len(data) > apis.MaxChunkSize {
return fmt.Errorf("chunk is too large: %d/%s = data[%d]", chunk, version, len(data))
}
versionMap := m.chunks[chunk]
if versionMap == nil {
versionMap = map[apis.Version][]byte{}
m.chunks[chunk] = versionMap
}
existing, exists := versionMap[version]
if exists {
return fmt.Errorf("chunk/version combination already exists: %d/%d = data[%d]", chunk, version, len(existing))
}
ndata := make([]byte, len(data))
copy(ndata, data)
versionMap[version] = ndata
return nil
}
func (m *MemoryStorage) DeleteVersion(chunk apis.ChunkNum, version apis.Version) error {
m.assertOpen()
versionMap := m.chunks[chunk]
if versionMap == nil {
return fmt.Errorf("chunk/version combination does not exist: %d/%d", chunk, version)
}
_, exists := versionMap[version]
if !exists {
return fmt.Errorf("chunk/version combination does not exist: %d/%d", chunk, version)
}
delete(versionMap, version)
if len(versionMap) == 0 {
delete(m.chunks, chunk)
}
return nil
}
func (m *MemoryStorage) ListChunksWithLatest() ([]apis.ChunkNum, error) {
m.assertOpen()
result := make([]apis.ChunkNum, 0, len(m.latest))
for k, _ := range m.latest {
result = append(result, k)
}
return result, nil
}
func (m *MemoryStorage) GetLatestVersion(chunk apis.ChunkNum) (apis.Version, error) {
m.assertOpen()
if version, found := m.latest[chunk]; found {
return version, nil
}
return 0, fmt.Errorf("no latest version for chunk: %d", chunk)
}
func (m *MemoryStorage) SetLatestVersion(chunk apis.ChunkNum, latest apis.Version) error {
m.assertOpen()
m.latest[chunk] = latest
return nil
}
func (m *MemoryStorage) DeleteLatestVersion(chunk apis.ChunkNum) error {
m.assertOpen()
_, found := m.latest[chunk]
if found {
delete(m.latest, chunk)
return nil
} else {
return fmt.Errorf("cannot delete nonexistent latest version for chunk: %d", chunk)
}
}
func (m *MemoryStorage) Close() {
m.chunks = nil
m.latest = nil
m.isClosed = true
}