-
Notifications
You must be signed in to change notification settings - Fork 24
/
resource_id.go
94 lines (79 loc) · 1.68 KB
/
resource_id.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
// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later
package x
import (
"errors"
"math/big"
"sync"
)
func (c *Conn) AllocID() (uint32, error) {
return c.ridAllocator.alloc()
}
func (c *Conn) FreeID(rid uint32) error {
return c.ridAllocator.free(rid)
}
func (c *Conn) IDUsedCount() int {
return c.ridAllocator.usedCount()
}
type resourceIdAllocator struct {
mu sync.Mutex
base uint32
mask uint32
last uint32
bitmap *big.Int
allAllocated bool
}
func (ra *resourceIdAllocator) init(base, mask uint32) {
ra.base = base
ra.mask = mask
ra.bitmap = big.NewInt(0)
}
var errOutOfResourceIds = errors.New("out of resource ids")
func (ra *resourceIdAllocator) alloc() (uint32, error) {
ra.mu.Lock()
defer ra.mu.Unlock()
if ra.allAllocated {
return 0, errOutOfResourceIds
}
i := ra.last
for ra.bitmap.Bit(int(i)) == 1 {
i++
if i > ra.mask {
i = 0
}
if i == ra.last {
ra.allAllocated = true
return 0, errOutOfResourceIds
}
}
ra.bitmap.SetBit(ra.bitmap, int(i), 1)
ra.last = i
return ra.base | i, nil
}
func (ra *resourceIdAllocator) free(rid uint32) error {
ra.mu.Lock()
defer ra.mu.Unlock()
i := rid & ra.mask
if rid-i != ra.base {
return errors.New("resource id outside range")
}
if ra.bitmap.Bit(int(i)) == 0 {
return errors.New("resource id not used")
}
ra.bitmap.SetBit(ra.bitmap, int(i), 0)
ra.allAllocated = false
return nil
}
func (ra *resourceIdAllocator) usedCount() int {
ra.mu.Lock()
count := 0
bitLen := ra.bitmap.BitLen()
for i := 0; i < bitLen; i++ {
if ra.bitmap.Bit(i) == 1 {
count++
}
}
ra.mu.Unlock()
return count
}