Skip to content

Commit

Permalink
Merge pull request #1788 from abhi/ipam_alloc
Browse files Browse the repository at this point in the history
Serializing bitseq alloc
  • Loading branch information
Flavio Crisciani committed Oct 3, 2017
2 parents 7447e54 + a2bcac0 commit 2154459
Show file tree
Hide file tree
Showing 12 changed files with 450 additions and 72 deletions.
49 changes: 39 additions & 10 deletions bitseq/sequence.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ type Handle struct {
id string
dbIndex uint64
dbExists bool
curr uint64
store datastore.DataStore
sync.Mutex
}
Expand Down Expand Up @@ -193,34 +194,35 @@ func (h *Handle) getCopy() *Handle {
dbIndex: h.dbIndex,
dbExists: h.dbExists,
store: h.store,
curr: h.curr,
}
}

// SetAnyInRange atomically sets the first unset bit in the specified range in the sequence and returns the corresponding ordinal
func (h *Handle) SetAnyInRange(start, end uint64) (uint64, error) {
func (h *Handle) SetAnyInRange(start, end uint64, serial bool) (uint64, error) {
if end < start || end >= h.bits {
return invalidPos, fmt.Errorf("invalid bit range [%d, %d]", start, end)
}
if h.Unselected() == 0 {
return invalidPos, ErrNoBitAvailable
}
return h.set(0, start, end, true, false)
return h.set(0, start, end, true, false, serial)
}

// SetAny atomically sets the first unset bit in the sequence and returns the corresponding ordinal
func (h *Handle) SetAny() (uint64, error) {
func (h *Handle) SetAny(serial bool) (uint64, error) {
if h.Unselected() == 0 {
return invalidPos, ErrNoBitAvailable
}
return h.set(0, 0, h.bits-1, true, false)
return h.set(0, 0, h.bits-1, true, false, serial)
}

// Set atomically sets the corresponding bit in the sequence
func (h *Handle) Set(ordinal uint64) error {
if err := h.validateOrdinal(ordinal); err != nil {
return err
}
_, err := h.set(ordinal, 0, 0, false, false)
_, err := h.set(ordinal, 0, 0, false, false, false)
return err
}

Expand All @@ -229,7 +231,7 @@ func (h *Handle) Unset(ordinal uint64) error {
if err := h.validateOrdinal(ordinal); err != nil {
return err
}
_, err := h.set(ordinal, 0, 0, false, true)
_, err := h.set(ordinal, 0, 0, false, true, false)
return err
}

Expand Down Expand Up @@ -298,7 +300,7 @@ func (h *Handle) CheckConsistency() error {
}

// set/reset the bit
func (h *Handle) set(ordinal, start, end uint64, any bool, release bool) (uint64, error) {
func (h *Handle) set(ordinal, start, end uint64, any bool, release bool, serial bool) (uint64, error) {
var (
bitPos uint64
bytePos uint64
Expand All @@ -308,6 +310,7 @@ func (h *Handle) set(ordinal, start, end uint64, any bool, release bool) (uint64

for {
var store datastore.DataStore
curr := uint64(0)
h.Lock()
store = h.store
h.Unlock()
Expand All @@ -318,15 +321,18 @@ func (h *Handle) set(ordinal, start, end uint64, any bool, release bool) (uint64
}

h.Lock()
if serial {
curr = h.curr
}
// Get position if available
if release {
bytePos, bitPos = ordinalToPos(ordinal)
} else {
if any {
bytePos, bitPos, err = getFirstAvailable(h.head, start)
bytePos, bitPos, err = getAvailableFromCurrent(h.head, start, curr, end)
ret = posToOrdinal(bytePos, bitPos)
if end < ret {
err = ErrNoBitAvailable
if err == nil {
h.curr = ret + 1
}
} else {
bytePos, bitPos, err = checkIfAvailable(h.head, ordinal)
Expand Down Expand Up @@ -515,6 +521,29 @@ func getFirstAvailable(head *sequence, start uint64) (uint64, uint64, error) {
return invalidPos, invalidPos, ErrNoBitAvailable
}

// getAvailableFromCurrent will look for available ordinal from the current ordinal.
// If none found then it will loop back to the start to check of the available bit.
// This can be further optimized to check from start till curr in case of a rollover
func getAvailableFromCurrent(head *sequence, start, curr, end uint64) (uint64, uint64, error) {
var bytePos, bitPos uint64
if curr != 0 && curr > start {
bytePos, bitPos, _ = getFirstAvailable(head, curr)
ret := posToOrdinal(bytePos, bitPos)
if end < ret {
goto begin
}
return bytePos, bitPos, nil
}

begin:
bytePos, bitPos, _ = getFirstAvailable(head, start)
ret := posToOrdinal(bytePos, bitPos)
if end < ret {
return invalidPos, invalidPos, ErrNoBitAvailable
}
return bytePos, bitPos, nil
}

// checkIfAvailable checks if the bit correspondent to the specified ordinal is unset
// If the ordinal is beyond the sequence limits, a negative response is returned
func checkIfAvailable(head *sequence, ordinal uint64) (uint64, uint64, error) {
Expand Down
Loading

0 comments on commit 2154459

Please sign in to comment.