-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathalloc.go
84 lines (72 loc) · 1.57 KB
/
alloc.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
package alloc
import (
"sync"
"github.com/goose-lang/primitive"
)
type unit struct{}
type AddrSet = map[uint64]unit
// Allocator manages free disk blocks. It does not store its state durably, so
// the caller is responsible for returning its set of free disk blocks on
// recovery.
type Allocator struct {
m *sync.Mutex
free map[uint64]unit
}
func freeRange(start, sz uint64) AddrSet {
m := make(AddrSet)
end := start + sz
for i := start; i < end; i++ {
m[i] = unit{}
}
return m
}
// mapRemove deletes addresses in remove from m
//
// like m -= remove
func mapRemove(m AddrSet, remove AddrSet) {
for k := range remove {
delete(m, k)
}
}
// SetAdd adds addresses in add to m
//
// like m += add
func SetAdd(m AddrSet, add []uint64) {
for _, k := range add {
m[k] = unit{}
}
}
func New(start, sz uint64, used AddrSet) *Allocator {
free := freeRange(start, sz)
mapRemove(free, used)
return &Allocator{m: new(sync.Mutex), free: free}
}
func findKey(m map[uint64]unit) (uint64, bool) {
var found uint64 = 0
var ok bool = false
for k := range m {
if !ok {
found = k
ok = true
}
// TODO: goose doesn't support break in map iteration
}
return found, ok
}
// Reserve transfers ownership of a free block from the Allocator to the caller
//
// The initial contents of the block are arbitrary.
func (a *Allocator) Reserve() (uint64, bool) {
a.m.Lock()
k, ok := findKey(a.free)
delete(a.free, k)
primitive.Linearize()
a.m.Unlock()
return k, ok
}
func (a *Allocator) Free(addr uint64) {
a.m.Lock()
a.free[addr] = unit{}
primitive.Linearize()
a.m.Unlock()
}