github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/libnetwork/bitmap/sequence.go (about)

     1  // Package bitmap provides a datatype for long vectors of bits.
     2  package bitmap
     3  
     4  import (
     5  	"encoding/binary"
     6  	"encoding/json"
     7  	"errors"
     8  	"fmt"
     9  )
    10  
    11  // block sequence constants
    12  // If needed we can think of making these configurable
    13  const (
    14  	blockLen      = uint32(32)
    15  	blockBytes    = uint64(blockLen / 8)
    16  	blockMAX      = uint32(1<<blockLen - 1)
    17  	blockFirstBit = uint32(1) << (blockLen - 1)
    18  	invalidPos    = uint64(0xFFFFFFFFFFFFFFFF)
    19  )
    20  
    21  var (
    22  	// ErrNoBitAvailable is returned when no more bits are available to set
    23  	ErrNoBitAvailable = errors.New("no bit available")
    24  	// ErrBitAllocated is returned when the specific bit requested is already set
    25  	ErrBitAllocated = errors.New("requested bit is already allocated")
    26  )
    27  
    28  // https://github.com/golang/go/issues/8005#issuecomment-190753527
    29  type noCopy struct{}
    30  
    31  func (noCopy) Lock() {}
    32  
    33  // Bitmap is a fixed-length bit vector. It is not safe for concurrent use.
    34  //
    35  // The data is stored as a list of run-length encoded blocks. It operates
    36  // directly on the encoded representation, without decompressing.
    37  type Bitmap struct {
    38  	bits       uint64
    39  	unselected uint64
    40  	head       *sequence
    41  	curr       uint64
    42  
    43  	// Shallow copies would share the same head pointer but a copy of the
    44  	// unselected count. Mutating the sequence through one would change the
    45  	// bits for all copies but only update that one copy's unselected count,
    46  	// which would result in subtle bugs.
    47  	noCopy noCopy
    48  }
    49  
    50  // NewHandle returns a new Bitmap of ordinals in the interval [0, n).
    51  func New(n uint64) *Bitmap {
    52  	return &Bitmap{
    53  		bits:       n,
    54  		unselected: n,
    55  		head: &sequence{
    56  			block: 0x0,
    57  			count: getNumBlocks(n),
    58  		},
    59  	}
    60  }
    61  
    62  // Copy returns a deep copy of b.
    63  func Copy(b *Bitmap) *Bitmap {
    64  	return &Bitmap{
    65  		bits:       b.bits,
    66  		unselected: b.unselected,
    67  		head:       b.head.getCopy(),
    68  		curr:       b.curr,
    69  	}
    70  }
    71  
    72  // sequence represents a recurring sequence of 32 bits long bitmasks
    73  type sequence struct {
    74  	block uint32    // block is a symbol representing 4 byte long allocation bitmask
    75  	count uint64    // number of consecutive blocks (symbols)
    76  	next  *sequence // next sequence
    77  }
    78  
    79  // String returns a string representation of the block sequence starting from this block
    80  func (s *sequence) toString() string {
    81  	var nextBlock string
    82  	if s.next == nil {
    83  		nextBlock = "end"
    84  	} else {
    85  		nextBlock = s.next.toString()
    86  	}
    87  	return fmt.Sprintf("(0x%x, %d)->%s", s.block, s.count, nextBlock)
    88  }
    89  
    90  // GetAvailableBit returns the position of the first unset bit in the bitmask represented by this sequence
    91  func (s *sequence) getAvailableBit(from uint64) (uint64, uint64, error) {
    92  	if s.block == blockMAX || s.count == 0 {
    93  		return invalidPos, invalidPos, ErrNoBitAvailable
    94  	}
    95  	bits := from
    96  	bitSel := blockFirstBit >> from
    97  	for bitSel > 0 && s.block&bitSel != 0 {
    98  		bitSel >>= 1
    99  		bits++
   100  	}
   101  	// Check if the loop exited because it could not
   102  	// find any available bit int block  starting from
   103  	// "from". Return invalid pos in that case.
   104  	if bitSel == 0 {
   105  		return invalidPos, invalidPos, ErrNoBitAvailable
   106  	}
   107  	return bits / 8, bits % 8, nil
   108  }
   109  
   110  // GetCopy returns a copy of the linked list rooted at this node
   111  func (s *sequence) getCopy() *sequence {
   112  	n := &sequence{block: s.block, count: s.count}
   113  	pn := n
   114  	ps := s.next
   115  	for ps != nil {
   116  		pn.next = &sequence{block: ps.block, count: ps.count}
   117  		pn = pn.next
   118  		ps = ps.next
   119  	}
   120  	return n
   121  }
   122  
   123  // Equal checks if this sequence is equal to the passed one
   124  func (s *sequence) equal(o *sequence) bool {
   125  	this := s
   126  	other := o
   127  	for this != nil {
   128  		if other == nil {
   129  			return false
   130  		}
   131  		if this.block != other.block || this.count != other.count {
   132  			return false
   133  		}
   134  		this = this.next
   135  		other = other.next
   136  	}
   137  	return other == nil
   138  }
   139  
   140  // ToByteArray converts the sequence into a byte array
   141  func (s *sequence) toByteArray() ([]byte, error) {
   142  	var bb []byte
   143  
   144  	p := s
   145  	b := make([]byte, 12)
   146  	for p != nil {
   147  		binary.BigEndian.PutUint32(b[0:], p.block)
   148  		binary.BigEndian.PutUint64(b[4:], p.count)
   149  		bb = append(bb, b...)
   150  		p = p.next
   151  	}
   152  
   153  	return bb, nil
   154  }
   155  
   156  // fromByteArray construct the sequence from the byte array
   157  func (s *sequence) fromByteArray(data []byte) error {
   158  	l := len(data)
   159  	if l%12 != 0 {
   160  		return fmt.Errorf("cannot deserialize byte sequence of length %d (%v)", l, data)
   161  	}
   162  
   163  	p := s
   164  	i := 0
   165  	for {
   166  		p.block = binary.BigEndian.Uint32(data[i : i+4])
   167  		p.count = binary.BigEndian.Uint64(data[i+4 : i+12])
   168  		i += 12
   169  		if i == l {
   170  			break
   171  		}
   172  		p.next = &sequence{}
   173  		p = p.next
   174  	}
   175  
   176  	return nil
   177  }
   178  
   179  // SetAnyInRange sets the first unset bit in the range [start, end] and returns
   180  // the ordinal of the set bit.
   181  //
   182  // When serial=true, the bitmap is scanned starting from the ordinal following
   183  // the bit most recently set by [Bitmap.SetAny] or [Bitmap.SetAnyInRange].
   184  func (h *Bitmap) SetAnyInRange(start, end uint64, serial bool) (uint64, error) {
   185  	if end < start || end >= h.bits {
   186  		return invalidPos, fmt.Errorf("invalid bit range [%d, %d)", start, end)
   187  	}
   188  	if h.Unselected() == 0 {
   189  		return invalidPos, ErrNoBitAvailable
   190  	}
   191  	return h.set(0, start, end, true, false, serial)
   192  }
   193  
   194  // SetAny sets the first unset bit in the sequence and returns the ordinal of
   195  // the set bit.
   196  //
   197  // When serial=true, the bitmap is scanned starting from the ordinal following
   198  // the bit most recently set by [Bitmap.SetAny] or [Bitmap.SetAnyInRange].
   199  func (h *Bitmap) SetAny(serial bool) (uint64, error) {
   200  	if h.Unselected() == 0 {
   201  		return invalidPos, ErrNoBitAvailable
   202  	}
   203  	return h.set(0, 0, h.bits-1, true, false, serial)
   204  }
   205  
   206  // Set atomically sets the corresponding bit in the sequence
   207  func (h *Bitmap) Set(ordinal uint64) error {
   208  	if err := h.validateOrdinal(ordinal); err != nil {
   209  		return err
   210  	}
   211  	_, err := h.set(ordinal, 0, 0, false, false, false)
   212  	return err
   213  }
   214  
   215  // Unset atomically unsets the corresponding bit in the sequence
   216  func (h *Bitmap) Unset(ordinal uint64) error {
   217  	if err := h.validateOrdinal(ordinal); err != nil {
   218  		return err
   219  	}
   220  	_, err := h.set(ordinal, 0, 0, false, true, false)
   221  	return err
   222  }
   223  
   224  // IsSet atomically checks if the ordinal bit is set. In case ordinal
   225  // is outside of the bit sequence limits, false is returned.
   226  func (h *Bitmap) IsSet(ordinal uint64) bool {
   227  	if err := h.validateOrdinal(ordinal); err != nil {
   228  		return false
   229  	}
   230  	_, _, err := checkIfAvailable(h.head, ordinal)
   231  	return err != nil
   232  }
   233  
   234  // set/reset the bit
   235  func (h *Bitmap) set(ordinal, start, end uint64, any bool, release bool, serial bool) (uint64, error) {
   236  	var (
   237  		bitPos  uint64
   238  		bytePos uint64
   239  		ret     uint64
   240  		err     error
   241  	)
   242  
   243  	curr := uint64(0)
   244  	if serial {
   245  		curr = h.curr
   246  	}
   247  	// Get position if available
   248  	if release {
   249  		bytePos, bitPos = ordinalToPos(ordinal)
   250  	} else {
   251  		if any {
   252  			bytePos, bitPos, err = getAvailableFromCurrent(h.head, start, curr, end)
   253  			ret = posToOrdinal(bytePos, bitPos)
   254  			if err == nil {
   255  				h.curr = ret + 1
   256  			}
   257  		} else {
   258  			bytePos, bitPos, err = checkIfAvailable(h.head, ordinal)
   259  			ret = ordinal
   260  		}
   261  	}
   262  	if err != nil {
   263  		return ret, err
   264  	}
   265  
   266  	h.head = pushReservation(bytePos, bitPos, h.head, release)
   267  	if release {
   268  		h.unselected++
   269  	} else {
   270  		h.unselected--
   271  	}
   272  
   273  	return ret, nil
   274  }
   275  
   276  // checks is needed because to cover the case where the number of bits is not a multiple of blockLen
   277  func (h *Bitmap) validateOrdinal(ordinal uint64) error {
   278  	if ordinal >= h.bits {
   279  		return errors.New("bit does not belong to the sequence")
   280  	}
   281  	return nil
   282  }
   283  
   284  // MarshalBinary encodes h into a binary representation.
   285  func (h *Bitmap) MarshalBinary() ([]byte, error) {
   286  	ba := make([]byte, 16)
   287  	binary.BigEndian.PutUint64(ba[0:], h.bits)
   288  	binary.BigEndian.PutUint64(ba[8:], h.unselected)
   289  	bm, err := h.head.toByteArray()
   290  	if err != nil {
   291  		return nil, fmt.Errorf("failed to serialize head: %v", err)
   292  	}
   293  	ba = append(ba, bm...)
   294  
   295  	return ba, nil
   296  }
   297  
   298  // UnmarshalBinary decodes a binary representation of a Bitmap value which was
   299  // generated using [Bitmap.MarshalBinary].
   300  //
   301  // The scan position for serial [Bitmap.SetAny] and [Bitmap.SetAnyInRange]
   302  // operations is neither unmarshaled nor reset.
   303  func (h *Bitmap) UnmarshalBinary(ba []byte) error {
   304  	if ba == nil {
   305  		return errors.New("nil byte array")
   306  	}
   307  
   308  	nh := &sequence{}
   309  	err := nh.fromByteArray(ba[16:])
   310  	if err != nil {
   311  		return fmt.Errorf("failed to deserialize head: %v", err)
   312  	}
   313  
   314  	h.head = nh
   315  	h.bits = binary.BigEndian.Uint64(ba[0:8])
   316  	h.unselected = binary.BigEndian.Uint64(ba[8:16])
   317  	return nil
   318  }
   319  
   320  // Bits returns the length of the bit sequence
   321  func (h *Bitmap) Bits() uint64 {
   322  	return h.bits
   323  }
   324  
   325  // Unselected returns the number of bits which are not selected
   326  func (h *Bitmap) Unselected() uint64 {
   327  	return h.unselected
   328  }
   329  
   330  func (h *Bitmap) String() string {
   331  	return fmt.Sprintf("Bits: %d, Unselected: %d, Sequence: %s Curr:%d",
   332  		h.bits, h.unselected, h.head.toString(), h.curr)
   333  }
   334  
   335  // MarshalJSON encodes h into a JSON message
   336  func (h *Bitmap) MarshalJSON() ([]byte, error) {
   337  	b, err := h.MarshalBinary()
   338  	if err != nil {
   339  		return nil, err
   340  	}
   341  	return json.Marshal(b)
   342  }
   343  
   344  // UnmarshalJSON decodes JSON message into h
   345  func (h *Bitmap) UnmarshalJSON(data []byte) error {
   346  	var b []byte
   347  	if err := json.Unmarshal(data, &b); err != nil {
   348  		return err
   349  	}
   350  	return h.UnmarshalBinary(b)
   351  }
   352  
   353  // getFirstAvailable looks for the first unset bit in passed mask starting from start
   354  func getFirstAvailable(head *sequence, start uint64) (uint64, uint64, error) {
   355  	// Find sequence which contains the start bit
   356  	byteStart, bitStart := ordinalToPos(start)
   357  	current, _, precBlocks, inBlockBytePos := findSequence(head, byteStart)
   358  	// Derive the this sequence offsets
   359  	byteOffset := byteStart - inBlockBytePos
   360  	bitOffset := inBlockBytePos*8 + bitStart
   361  	for current != nil {
   362  		if current.block != blockMAX {
   363  			// If the current block is not full, check if there is any bit
   364  			// from the current bit in the current block. If not, before proceeding to the
   365  			// next block node, make sure we check for available bit in the next
   366  			// instance of the same block. Due to RLE same block signature will be
   367  			// compressed.
   368  		retry:
   369  			bytePos, bitPos, err := current.getAvailableBit(bitOffset)
   370  			if err != nil && precBlocks == current.count-1 {
   371  				// This is the last instance in the same block node,
   372  				// so move to the next block.
   373  				goto next
   374  			}
   375  			if err != nil {
   376  				// There are some more instances of the same block, so add the offset
   377  				// and be optimistic that you will find the available bit in the next
   378  				// instance of the same block.
   379  				bitOffset = 0
   380  				byteOffset += blockBytes
   381  				precBlocks++
   382  				goto retry
   383  			}
   384  			return byteOffset + bytePos, bitPos, err
   385  		}
   386  		// Moving to next block: Reset bit offset.
   387  	next:
   388  		bitOffset = 0
   389  		byteOffset += (current.count * blockBytes) - (precBlocks * blockBytes)
   390  		precBlocks = 0
   391  		current = current.next
   392  	}
   393  	return invalidPos, invalidPos, ErrNoBitAvailable
   394  }
   395  
   396  // getAvailableFromCurrent will look for available ordinal from the current ordinal.
   397  // If none found then it will loop back to the start to check of the available bit.
   398  // This can be further optimized to check from start till curr in case of a rollover
   399  func getAvailableFromCurrent(head *sequence, start, curr, end uint64) (uint64, uint64, error) {
   400  	var bytePos, bitPos uint64
   401  	var err error
   402  	if curr != 0 && curr > start {
   403  		bytePos, bitPos, err = getFirstAvailable(head, curr)
   404  		ret := posToOrdinal(bytePos, bitPos)
   405  		if end < ret || err != nil {
   406  			goto begin
   407  		}
   408  		return bytePos, bitPos, nil
   409  	}
   410  
   411  begin:
   412  	bytePos, bitPos, err = getFirstAvailable(head, start)
   413  	ret := posToOrdinal(bytePos, bitPos)
   414  	if end < ret || err != nil {
   415  		return invalidPos, invalidPos, ErrNoBitAvailable
   416  	}
   417  	return bytePos, bitPos, nil
   418  }
   419  
   420  // checkIfAvailable checks if the bit correspondent to the specified ordinal is unset
   421  // If the ordinal is beyond the sequence limits, a negative response is returned
   422  func checkIfAvailable(head *sequence, ordinal uint64) (uint64, uint64, error) {
   423  	bytePos, bitPos := ordinalToPos(ordinal)
   424  
   425  	// Find the sequence containing this byte
   426  	current, _, _, inBlockBytePos := findSequence(head, bytePos)
   427  	if current != nil {
   428  		// Check whether the bit corresponding to the ordinal address is unset
   429  		bitSel := blockFirstBit >> (inBlockBytePos*8 + bitPos)
   430  		if current.block&bitSel == 0 {
   431  			return bytePos, bitPos, nil
   432  		}
   433  	}
   434  
   435  	return invalidPos, invalidPos, ErrBitAllocated
   436  }
   437  
   438  // Given the byte position and the sequences list head, return the pointer to the
   439  // sequence containing the byte (current), the pointer to the previous sequence,
   440  // the number of blocks preceding the block containing the byte inside the current sequence.
   441  // If bytePos is outside of the list, function will return (nil, nil, 0, invalidPos)
   442  func findSequence(head *sequence, bytePos uint64) (*sequence, *sequence, uint64, uint64) {
   443  	// Find the sequence containing this byte
   444  	previous := head
   445  	current := head
   446  	n := bytePos
   447  	for current.next != nil && n >= (current.count*blockBytes) { // Nil check for less than 32 addresses masks
   448  		n -= (current.count * blockBytes)
   449  		previous = current
   450  		current = current.next
   451  	}
   452  
   453  	// If byte is outside of the list, let caller know
   454  	if n >= (current.count * blockBytes) {
   455  		return nil, nil, 0, invalidPos
   456  	}
   457  
   458  	// Find the byte position inside the block and the number of blocks
   459  	// preceding the block containing the byte inside this sequence
   460  	precBlocks := n / blockBytes
   461  	inBlockBytePos := bytePos % blockBytes
   462  
   463  	return current, previous, precBlocks, inBlockBytePos
   464  }
   465  
   466  // PushReservation pushes the bit reservation inside the bitmask.
   467  // Given byte and bit positions, identify the sequence (current) which holds the block containing the affected bit.
   468  // Create a new block with the modified bit according to the operation (allocate/release).
   469  // Create a new sequence containing the new block and insert it in the proper position.
   470  // Remove current sequence if empty.
   471  // Check if new sequence can be merged with neighbour (previous/next) sequences.
   472  //
   473  // Identify "current" sequence containing block:
   474  //
   475  //	[prev seq] [current seq] [next seq]
   476  //
   477  // Based on block position, resulting list of sequences can be any of three forms:
   478  //
   479  // block position                        Resulting list of sequences
   480  //
   481  // A) block is first in current:         [prev seq] [new] [modified current seq] [next seq]
   482  // B) block is last in current:          [prev seq] [modified current seq] [new] [next seq]
   483  // C) block is in the middle of current: [prev seq] [curr pre] [new] [curr post] [next seq]
   484  func pushReservation(bytePos, bitPos uint64, head *sequence, release bool) *sequence {
   485  	// Store list's head
   486  	newHead := head
   487  
   488  	// Find the sequence containing this byte
   489  	current, previous, precBlocks, inBlockBytePos := findSequence(head, bytePos)
   490  	if current == nil {
   491  		return newHead
   492  	}
   493  
   494  	// Construct updated block
   495  	bitSel := blockFirstBit >> (inBlockBytePos*8 + bitPos)
   496  	newBlock := current.block
   497  	if release {
   498  		newBlock &^= bitSel
   499  	} else {
   500  		newBlock |= bitSel
   501  	}
   502  
   503  	// Quit if it was a redundant request
   504  	if current.block == newBlock {
   505  		return newHead
   506  	}
   507  
   508  	// Current sequence inevitably looses one block, upadate count
   509  	current.count--
   510  
   511  	// Create new sequence
   512  	newSequence := &sequence{block: newBlock, count: 1}
   513  
   514  	// Insert the new sequence in the list based on block position
   515  	if precBlocks == 0 { // First in sequence (A)
   516  		newSequence.next = current
   517  		if current == head {
   518  			newHead = newSequence
   519  			previous = newHead
   520  		} else {
   521  			previous.next = newSequence
   522  		}
   523  		removeCurrentIfEmpty(&newHead, newSequence, current)
   524  		mergeSequences(previous)
   525  	} else if precBlocks == current.count { // Last in sequence (B)
   526  		newSequence.next = current.next
   527  		current.next = newSequence
   528  		mergeSequences(current)
   529  	} else { // In between the sequence (C)
   530  		currPre := &sequence{block: current.block, count: precBlocks, next: newSequence}
   531  		currPost := current
   532  		currPost.count -= precBlocks
   533  		newSequence.next = currPost
   534  		if currPost == head {
   535  			newHead = currPre
   536  		} else {
   537  			previous.next = currPre
   538  		}
   539  		// No merging or empty current possible here
   540  	}
   541  
   542  	return newHead
   543  }
   544  
   545  // Removes the current sequence from the list if empty, adjusting the head pointer if needed
   546  func removeCurrentIfEmpty(head **sequence, previous, current *sequence) {
   547  	if current.count == 0 {
   548  		if current == *head {
   549  			*head = current.next
   550  		} else {
   551  			previous.next = current.next
   552  		}
   553  	}
   554  }
   555  
   556  // Given a pointer to a sequence, it checks if it can be merged with any following sequences
   557  // It stops when no more merging is possible.
   558  // TODO: Optimization: only attempt merge from start to end sequence, no need to scan till the end of the list
   559  func mergeSequences(seq *sequence) {
   560  	if seq != nil {
   561  		// Merge all what possible from seq
   562  		for seq.next != nil && seq.block == seq.next.block {
   563  			seq.count += seq.next.count
   564  			seq.next = seq.next.next
   565  		}
   566  		// Move to next
   567  		mergeSequences(seq.next)
   568  	}
   569  }
   570  
   571  func getNumBlocks(numBits uint64) uint64 {
   572  	numBlocks := numBits / uint64(blockLen)
   573  	if numBits%uint64(blockLen) != 0 {
   574  		numBlocks++
   575  	}
   576  	return numBlocks
   577  }
   578  
   579  func ordinalToPos(ordinal uint64) (uint64, uint64) {
   580  	return ordinal / 8, ordinal % 8
   581  }
   582  
   583  func posToOrdinal(bytePos, bitPos uint64) uint64 {
   584  	return bytePos*8 + bitPos
   585  }