|
@@ -17,10 +17,10 @@ import (
|
|
|
// If needed we can think of making these configurable
|
|
|
const (
|
|
|
blockLen = uint32(32)
|
|
|
- blockBytes = blockLen / 8
|
|
|
+ blockBytes = uint64(blockLen / 8)
|
|
|
blockMAX = uint32(1<<blockLen - 1)
|
|
|
blockFirstBit = uint32(1) << (blockLen - 1)
|
|
|
- invalidPos = blockMAX
|
|
|
+ invalidPos = uint64(0xFFFFFFFFFFFFFFFF)
|
|
|
)
|
|
|
|
|
|
var (
|
|
@@ -29,8 +29,8 @@ var (
|
|
|
|
|
|
// Handle contains the sequece representing the bitmask and its identifier
|
|
|
type Handle struct {
|
|
|
- bits uint32
|
|
|
- unselected uint32
|
|
|
+ bits uint64
|
|
|
+ unselected uint64
|
|
|
head *sequence
|
|
|
app string
|
|
|
id string
|
|
@@ -41,7 +41,7 @@ type Handle struct {
|
|
|
}
|
|
|
|
|
|
// NewHandle returns a thread-safe instance of the bitmask handler
|
|
|
-func NewHandle(app string, ds datastore.DataStore, id string, numElements uint32) (*Handle, error) {
|
|
|
+func NewHandle(app string, ds datastore.DataStore, id string, numElements uint64) (*Handle, error) {
|
|
|
h := &Handle{
|
|
|
app: app,
|
|
|
id: id,
|
|
@@ -76,7 +76,7 @@ func NewHandle(app string, ds datastore.DataStore, id string, numElements uint32
|
|
|
// sequence represents a recurring sequence of 32 bits long bitmasks
|
|
|
type sequence struct {
|
|
|
block uint32 // block is a symbol representing 4 byte long allocation bitmask
|
|
|
- count uint32 // number of consecutive blocks (symbols)
|
|
|
+ count uint64 // number of consecutive blocks (symbols)
|
|
|
next *sequence // next sequence
|
|
|
}
|
|
|
|
|
@@ -92,7 +92,7 @@ func (s *sequence) toString() string {
|
|
|
}
|
|
|
|
|
|
// GetAvailableBit returns the position of the first unset bit in the bitmask represented by this sequence
|
|
|
-func (s *sequence) getAvailableBit(from uint32) (uint32, uint32, error) {
|
|
|
+func (s *sequence) getAvailableBit(from uint64) (uint64, uint64, error) {
|
|
|
if s.block == blockMAX || s.count == 0 {
|
|
|
return invalidPos, invalidPos, errNoBitAvailable
|
|
|
}
|
|
@@ -145,9 +145,9 @@ func (s *sequence) toByteArray() ([]byte, error) {
|
|
|
|
|
|
p := s
|
|
|
for p != nil {
|
|
|
- b := make([]byte, 8)
|
|
|
+ b := make([]byte, 12)
|
|
|
binary.BigEndian.PutUint32(b[0:], p.block)
|
|
|
- binary.BigEndian.PutUint32(b[4:], p.count)
|
|
|
+ binary.BigEndian.PutUint64(b[4:], p.count)
|
|
|
bb = append(bb, b...)
|
|
|
p = p.next
|
|
|
}
|
|
@@ -158,7 +158,7 @@ func (s *sequence) toByteArray() ([]byte, error) {
|
|
|
// fromByteArray construct the sequence from the byte array
|
|
|
func (s *sequence) fromByteArray(data []byte) error {
|
|
|
l := len(data)
|
|
|
- if l%8 != 0 {
|
|
|
+ if l%12 != 0 {
|
|
|
return fmt.Errorf("cannot deserialize byte sequence of lenght %d (%v)", l, data)
|
|
|
}
|
|
|
|
|
@@ -166,8 +166,8 @@ func (s *sequence) fromByteArray(data []byte) error {
|
|
|
i := 0
|
|
|
for {
|
|
|
p.block = binary.BigEndian.Uint32(data[i : i+4])
|
|
|
- p.count = binary.BigEndian.Uint32(data[i+4 : i+8])
|
|
|
- i += 8
|
|
|
+ p.count = binary.BigEndian.Uint64(data[i+4 : i+12])
|
|
|
+ i += 12
|
|
|
if i == l {
|
|
|
break
|
|
|
}
|
|
@@ -192,7 +192,7 @@ func (h *Handle) getCopy() *Handle {
|
|
|
}
|
|
|
|
|
|
// 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 uint32) (uint32, error) {
|
|
|
+func (h *Handle) SetAnyInRange(start, end uint64) (uint64, error) {
|
|
|
if end-start <= 0 || end >= h.bits {
|
|
|
return invalidPos, fmt.Errorf("invalid bit range [%d, %d]", start, end)
|
|
|
}
|
|
@@ -203,7 +203,7 @@ func (h *Handle) SetAnyInRange(start, end uint32) (uint32, error) {
|
|
|
}
|
|
|
|
|
|
// SetAny atomically sets the first unset bit in the sequence and returns the corresponding ordinal
|
|
|
-func (h *Handle) SetAny() (uint32, error) {
|
|
|
+func (h *Handle) SetAny() (uint64, error) {
|
|
|
if h.Unselected() == 0 {
|
|
|
return invalidPos, errNoBitAvailable
|
|
|
}
|
|
@@ -211,7 +211,7 @@ func (h *Handle) SetAny() (uint32, error) {
|
|
|
}
|
|
|
|
|
|
// Set atomically sets the corresponding bit in the sequence
|
|
|
-func (h *Handle) Set(ordinal uint32) error {
|
|
|
+func (h *Handle) Set(ordinal uint64) error {
|
|
|
if err := h.validateOrdinal(ordinal); err != nil {
|
|
|
return err
|
|
|
}
|
|
@@ -220,7 +220,7 @@ func (h *Handle) Set(ordinal uint32) error {
|
|
|
}
|
|
|
|
|
|
// Unset atomically unsets the corresponding bit in the sequence
|
|
|
-func (h *Handle) Unset(ordinal uint32) error {
|
|
|
+func (h *Handle) Unset(ordinal uint64) error {
|
|
|
if err := h.validateOrdinal(ordinal); err != nil {
|
|
|
return err
|
|
|
}
|
|
@@ -230,7 +230,7 @@ func (h *Handle) Unset(ordinal uint32) error {
|
|
|
|
|
|
// IsSet atomically checks if the ordinal bit is set. In case ordinal
|
|
|
// is outside of the bit sequence limits, false is returned.
|
|
|
-func (h *Handle) IsSet(ordinal uint32) bool {
|
|
|
+func (h *Handle) IsSet(ordinal uint64) bool {
|
|
|
if err := h.validateOrdinal(ordinal); err != nil {
|
|
|
return false
|
|
|
}
|
|
@@ -241,11 +241,11 @@ func (h *Handle) IsSet(ordinal uint32) bool {
|
|
|
}
|
|
|
|
|
|
// set/reset the bit
|
|
|
-func (h *Handle) set(ordinal, start, end uint32, any bool, release bool) (uint32, error) {
|
|
|
+func (h *Handle) set(ordinal, start, end uint64, any bool, release bool) (uint64, error) {
|
|
|
var (
|
|
|
- bitPos uint32
|
|
|
- bytePos uint32
|
|
|
- ret uint32
|
|
|
+ bitPos uint64
|
|
|
+ bytePos uint64
|
|
|
+ ret uint64
|
|
|
err error
|
|
|
)
|
|
|
|
|
@@ -309,7 +309,7 @@ func (h *Handle) set(ordinal, start, end uint32, any bool, release bool) (uint32
|
|
|
}
|
|
|
|
|
|
// checks is needed because to cover the case where the number of bits is not a multiple of blockLen
|
|
|
-func (h *Handle) validateOrdinal(ordinal uint32) error {
|
|
|
+func (h *Handle) validateOrdinal(ordinal uint64) error {
|
|
|
if ordinal >= h.bits {
|
|
|
return fmt.Errorf("bit does not belong to the sequence")
|
|
|
}
|
|
@@ -341,9 +341,9 @@ func (h *Handle) ToByteArray() ([]byte, error) {
|
|
|
|
|
|
h.Lock()
|
|
|
defer h.Unlock()
|
|
|
- ba := make([]byte, 8)
|
|
|
- binary.BigEndian.PutUint32(ba[0:], h.bits)
|
|
|
- binary.BigEndian.PutUint32(ba[4:], h.unselected)
|
|
|
+ ba := make([]byte, 16)
|
|
|
+ binary.BigEndian.PutUint64(ba[0:], h.bits)
|
|
|
+ binary.BigEndian.PutUint64(ba[8:], h.unselected)
|
|
|
bm, err := h.head.toByteArray()
|
|
|
if err != nil {
|
|
|
return nil, fmt.Errorf("failed to serialize head: %s", err.Error())
|
|
@@ -360,27 +360,27 @@ func (h *Handle) FromByteArray(ba []byte) error {
|
|
|
}
|
|
|
|
|
|
nh := &sequence{}
|
|
|
- err := nh.fromByteArray(ba[8:])
|
|
|
+ err := nh.fromByteArray(ba[16:])
|
|
|
if err != nil {
|
|
|
return fmt.Errorf("failed to deserialize head: %s", err.Error())
|
|
|
}
|
|
|
|
|
|
h.Lock()
|
|
|
h.head = nh
|
|
|
- h.bits = binary.BigEndian.Uint32(ba[0:4])
|
|
|
- h.unselected = binary.BigEndian.Uint32(ba[4:8])
|
|
|
+ h.bits = binary.BigEndian.Uint64(ba[0:8])
|
|
|
+ h.unselected = binary.BigEndian.Uint64(ba[8:16])
|
|
|
h.Unlock()
|
|
|
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
// Bits returns the length of the bit sequence
|
|
|
-func (h *Handle) Bits() uint32 {
|
|
|
+func (h *Handle) Bits() uint64 {
|
|
|
return h.bits
|
|
|
}
|
|
|
|
|
|
// Unselected returns the number of bits which are not selected
|
|
|
-func (h *Handle) Unselected() uint32 {
|
|
|
+func (h *Handle) Unselected() uint64 {
|
|
|
h.Lock()
|
|
|
defer h.Unlock()
|
|
|
return h.unselected
|
|
@@ -426,7 +426,7 @@ func (h *Handle) UnmarshalJSON(data []byte) error {
|
|
|
}
|
|
|
|
|
|
// getFirstAvailable looks for the first unset bit in passed mask starting from start
|
|
|
-func getFirstAvailable(head *sequence, start uint32) (uint32, uint32, error) {
|
|
|
+func getFirstAvailable(head *sequence, start uint64) (uint64, uint64, error) {
|
|
|
// Find sequence which contains the start bit
|
|
|
byteStart, bitStart := ordinalToPos(start)
|
|
|
current, _, _, inBlockBytePos := findSequence(head, byteStart)
|
|
@@ -450,7 +450,7 @@ func getFirstAvailable(head *sequence, start uint32) (uint32, uint32, error) {
|
|
|
|
|
|
// 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 uint32) (uint32, uint32, error) {
|
|
|
+func checkIfAvailable(head *sequence, ordinal uint64) (uint64, uint64, error) {
|
|
|
bytePos, bitPos := ordinalToPos(ordinal)
|
|
|
|
|
|
// Find the sequence containing this byte
|
|
@@ -470,7 +470,7 @@ func checkIfAvailable(head *sequence, ordinal uint32) (uint32, uint32, error) {
|
|
|
// sequence containing the byte (current), the pointer to the previous sequence,
|
|
|
// the number of blocks preceding the block containing the byte inside the current sequence.
|
|
|
// If bytePos is outside of the list, function will return (nil, nil, 0, invalidPos)
|
|
|
-func findSequence(head *sequence, bytePos uint32) (*sequence, *sequence, uint32, uint32) {
|
|
|
+func findSequence(head *sequence, bytePos uint64) (*sequence, *sequence, uint64, uint64) {
|
|
|
// Find the sequence containing this byte
|
|
|
previous := head
|
|
|
current := head
|
|
@@ -511,7 +511,7 @@ func findSequence(head *sequence, bytePos uint32) (*sequence, *sequence, uint32,
|
|
|
// A) block is first in current: [prev seq] [new] [modified current seq] [next seq]
|
|
|
// B) block is last in current: [prev seq] [modified current seq] [new] [next seq]
|
|
|
// C) block is in the middle of current: [prev seq] [curr pre] [new] [curr post] [next seq]
|
|
|
-func pushReservation(bytePos, bitPos uint32, head *sequence, release bool) *sequence {
|
|
|
+func pushReservation(bytePos, bitPos uint64, head *sequence, release bool) *sequence {
|
|
|
// Store list's head
|
|
|
newHead := head
|
|
|
|
|
@@ -599,18 +599,18 @@ func mergeSequences(seq *sequence) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-func getNumBlocks(numBits uint32) uint32 {
|
|
|
- numBlocks := numBits / blockLen
|
|
|
- if numBits%blockLen != 0 {
|
|
|
+func getNumBlocks(numBits uint64) uint64 {
|
|
|
+ numBlocks := numBits / uint64(blockLen)
|
|
|
+ if numBits%uint64(blockLen) != 0 {
|
|
|
numBlocks++
|
|
|
}
|
|
|
return numBlocks
|
|
|
}
|
|
|
|
|
|
-func ordinalToPos(ordinal uint32) (uint32, uint32) {
|
|
|
+func ordinalToPos(ordinal uint64) (uint64, uint64) {
|
|
|
return ordinal / 8, ordinal % 8
|
|
|
}
|
|
|
|
|
|
-func posToOrdinal(bytePos, bitPos uint32) uint32 {
|
|
|
+func posToOrdinal(bytePos, bitPos uint64) uint64 {
|
|
|
return bytePos*8 + bitPos
|
|
|
}
|