-
Notifications
You must be signed in to change notification settings - Fork 4.7k
/
allocator.go
103 lines (89 loc) · 2.6 KB
/
allocator.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
package netid
import (
"errors"
"k8s.io/kubernetes/pkg/registry/core/service/allocator"
)
// Interface manages the allocation of netids out of a range.
// Interface should be threadsafe.
type Interface interface {
Allocate(uint32) error
AllocateNext() (uint32, error)
Release(uint32) error
Has(uint32) bool
}
var (
ErrFull = errors.New("range is full")
ErrNotInRange = errors.New("provided netid is not in the valid range")
ErrAllocated = errors.New("provided netid is already allocated")
)
type Allocator struct {
netIDRange *NetIDRange
alloc allocator.Interface
}
// Allocator implements allocator Interface
var _ Interface = &Allocator{}
// New creates a Allocator over a netid Range, calling allocatorFactory to construct the backing store.
func New(r *NetIDRange, allocatorFactory allocator.AllocatorFactory) *Allocator {
return &Allocator{
netIDRange: r,
alloc: allocatorFactory(int(r.Size), r.String()),
}
}
// Helper that wraps New, for creating a range backed by an in-memory store.
func NewInMemory(r *NetIDRange) *Allocator {
return New(r, func(max int, rangeSpec string) allocator.Interface {
return allocator.NewAllocationMap(max, rangeSpec)
})
}
// Free returns the count of netid left in the range.
func (r *Allocator) Free() int {
return r.alloc.Free()
}
// Allocate attempts to reserve the provided netid. ErrNotInRange or
// ErrAllocated will be returned if the netid is not valid for this range
// or has already been reserved.
func (r *Allocator) Allocate(id uint32) error {
ok, offset := r.netIDRange.Contains(id)
if !ok {
return ErrNotInRange
}
allocated, err := r.alloc.Allocate(int(offset))
if err != nil {
return err
}
if !allocated {
return ErrAllocated
}
return nil
}
// AllocateNext reserves one of the netids from the pool. ErrFull may
// be returned if there are no netids left.
func (r *Allocator) AllocateNext() (uint32, error) {
offset, ok, err := r.alloc.AllocateNext()
if err != nil {
return 0, err
}
if !ok {
return 0, ErrFull
}
return r.netIDRange.Base + uint32(offset), nil
}
// Release releases the netid back to the pool. Releasing an
// unallocated netid or a netid out of the range is a no-op and
// returns no error.
func (r *Allocator) Release(id uint32) error {
ok, offset := r.netIDRange.Contains(id)
if !ok {
return nil
}
return r.alloc.Release(int(offset))
}
// Has returns true if the provided netid is already allocated and a call
// to Allocate(netid) would fail with ErrAllocated.
func (r *Allocator) Has(id uint32) bool {
ok, offset := r.netIDRange.Contains(id)
if !ok {
return false
}
return r.alloc.Has(int(offset))
}