mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-31 07:20:13 +00:00
Add a ForEach() to bitmap allocator
This commit is contained in:
parent
6fd22784a4
commit
f75bed8682
@ -26,5 +26,5 @@ go_test(
|
||||
],
|
||||
library = "go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [],
|
||||
deps = ["//vendor:k8s.io/client-go/pkg/util/sets"],
|
||||
)
|
||||
|
@ -124,6 +124,33 @@ func (r *AllocationBitmap) Release(offset int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
const (
|
||||
// Find the size of a big.Word in bytes.
|
||||
notZero = uint64(^big.Word(0))
|
||||
wordPower = (notZero>>8)&1 + (notZero>>16)&1 + (notZero>>32)&1
|
||||
wordSize = 1 << wordPower
|
||||
)
|
||||
|
||||
// ForEach calls the provided function for each allocated bit. The
|
||||
// AllocationBitmap may not be modified while this loop is running.
|
||||
func (r *AllocationBitmap) ForEach(fn func(int)) {
|
||||
r.lock.Lock()
|
||||
defer r.lock.Unlock()
|
||||
|
||||
words := r.allocated.Bits()
|
||||
for wordIdx, word := range words {
|
||||
bit := 0
|
||||
for word > 0 {
|
||||
if (word & 1) != 0 {
|
||||
fn((wordIdx * wordSize * 8) + bit)
|
||||
word = word &^ 1
|
||||
}
|
||||
bit++
|
||||
word = word >> 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Has returns true if the provided item is already allocated and a call
|
||||
// to Allocate(offset) would fail.
|
||||
func (r *AllocationBitmap) Has(offset int) bool {
|
||||
|
@ -18,6 +18,8 @@ package allocator
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/client-go/pkg/util/sets"
|
||||
)
|
||||
|
||||
func TestAllocate(t *testing.T) {
|
||||
@ -82,6 +84,37 @@ func TestRelease(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestForEach(t *testing.T) {
|
||||
testCases := []sets.Int{
|
||||
sets.NewInt(),
|
||||
sets.NewInt(0),
|
||||
sets.NewInt(0, 2, 5, 9),
|
||||
sets.NewInt(0, 1, 2, 3, 4, 5, 6, 7, 8, 9),
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
m := NewAllocationMap(10, "test")
|
||||
for offset := range tc {
|
||||
if ok, _ := m.Allocate(offset); !ok {
|
||||
t.Errorf("[%d] error allocate offset %v", i, offset)
|
||||
}
|
||||
if !m.Has(offset) {
|
||||
t.Errorf("[%d] expect offset %v allocated", i, offset)
|
||||
}
|
||||
}
|
||||
calls := sets.NewInt()
|
||||
m.ForEach(func(i int) {
|
||||
calls.Insert(i)
|
||||
})
|
||||
if len(calls) != len(tc) {
|
||||
t.Errorf("[%d] expected %d calls, got %d", i, len(tc), len(calls))
|
||||
}
|
||||
if !calls.Equal(tc) {
|
||||
t.Errorf("[%d] expected calls to equal testcase: %v vs %v", i, calls.List(), tc.List())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSnapshotAndRestore(t *testing.T) {
|
||||
offset := 3
|
||||
m := NewAllocationMap(10, "test")
|
||||
|
@ -144,6 +144,12 @@ func (e *Etcd) Release(item int) error {
|
||||
})
|
||||
}
|
||||
|
||||
func (e *Etcd) ForEach(fn func(int)) {
|
||||
e.lock.Lock()
|
||||
defer e.lock.Unlock()
|
||||
e.alloc.ForEach(fn)
|
||||
}
|
||||
|
||||
// tryUpdate performs a read-update to persist the latest snapshot state of allocation.
|
||||
func (e *Etcd) tryUpdate(fn func() error) error {
|
||||
err := e.storage.GuaranteedUpdate(context.TODO(), e.baseKey, &api.RangeAllocation{}, true, nil,
|
||||
|
@ -22,6 +22,7 @@ type Interface interface {
|
||||
Allocate(int) (bool, error)
|
||||
AllocateNext() (int, bool, error)
|
||||
Release(int) error
|
||||
ForEach(func(int))
|
||||
|
||||
// For testing
|
||||
Has(int) bool
|
||||
|
@ -25,7 +25,6 @@ go_library(
|
||||
"//pkg/apis/storage/v1beta1/util:go_default_library",
|
||||
"//pkg/client/clientset_generated/clientset:go_default_library",
|
||||
"//pkg/labels:go_default_library",
|
||||
"//pkg/registry/core/service/allocator:go_default_library",
|
||||
"//pkg/types:go_default_library",
|
||||
"//pkg/util/exec:go_default_library",
|
||||
"//pkg/util/mount:go_default_library",
|
||||
|
@ -25,8 +25,6 @@ package glusterfs
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
|
||||
"k8s.io/kubernetes/pkg/registry/core/service/allocator"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -51,7 +49,11 @@ var _ Rangeable = &MinMaxAllocator{}
|
||||
// Rangeable is an Interface that can adjust its min/max range.
|
||||
// Rangeable should be threadsafe
|
||||
type Rangeable interface {
|
||||
allocator.Interface
|
||||
Allocate(int) (bool, error)
|
||||
AllocateNext() (int, bool, error)
|
||||
Release(int) error
|
||||
Has(int) bool
|
||||
Free() int
|
||||
SetRange(min, max int) error
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user