-
Notifications
You must be signed in to change notification settings - Fork 881
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Serializing bitseq alloc #1788
Serializing bitseq alloc #1788
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -41,6 +41,7 @@ type Handle struct { | |
id string | ||
dbIndex uint64 | ||
dbExists bool | ||
curr uint64 | ||
store datastore.DataStore | ||
sync.Mutex | ||
} | ||
|
@@ -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 | ||
} | ||
|
||
|
@@ -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 | ||
} | ||
|
||
|
@@ -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 | ||
|
@@ -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() | ||
|
@@ -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) | ||
|
@@ -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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you don't really need a goto here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. avoding multiple condition in if. IMO this would be cleaner. |
||
} | ||
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) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when the last bit is allocated is there the risk that doing the +1 the number wraps to 0?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that will result in failure and cause the allocation from the start=