Forráskód Böngészése

Add bitseq package

- Initial version
- It allows handling reservation/release of a finite set
  of resources through large bitmask.
- It represents the bitmask as a list of equal
  consecutive 32 bits long bitmask symbols.
  It basically operates on a run-length encoding
  of the bitmask without encode/decode processing.

Signed-off-by: Alessandro Boch <aboch@docker.com>
Alessandro Boch 10 éve
szülő
commit
5034c9bb11
2 módosított fájl, 594 hozzáadás és 0 törlés
  1. 261 0
      libnetwork/bitseq/sequence.go
  2. 333 0
      libnetwork/bitseq/sequence_test.go

+ 261 - 0
libnetwork/bitseq/sequence.go

@@ -0,0 +1,261 @@
+// Package bitseq provides a structure and utilities for representing long bitmask
+// as sequence of run-lenght encoded blocks. It operates direclty on the encoded
+// representation, it does not decode/encode.
+package bitseq
+
+import (
+	"fmt"
+)
+
+// Block Sequence constants
+// If needed we can think of making these configurable
+const (
+	blockLen      = 32
+	blockBytes    = blockLen / 8
+	blockMAX      = 1<<blockLen - 1
+	blockFirstBit = 1 << (blockLen - 1)
+)
+
+// Sequence reresents a recurring sequence of 32 bits long bitmasks
+type Sequence struct {
+	Block uint32    // block representing 4 byte long allocation bitmask
+	Count uint32    // number of consecutive blocks
+	Next  *Sequence // next sequence
+}
+
+// New returns a sequence initialized to represent a bitmaks of numElements bits
+func New(numElements uint32) *Sequence {
+	return &Sequence{Block: 0x0, Count: getNumBlocks(numElements), Next: nil}
+}
+
+// String returns a string representation of the block sequence starting from this block
+func (s *Sequence) String() string {
+	var nextBlock string
+	if s.Next == nil {
+		nextBlock = "end"
+	} else {
+		nextBlock = s.Next.String()
+	}
+	return fmt.Sprintf("(0x%x, %d)->%s", s.Block, s.Count, nextBlock)
+}
+
+// GetAvailableBit returns the position of the first unset bit in the bitmask represented by this sequence
+func (s *Sequence) GetAvailableBit() (bytePos, bitPos int) {
+	if s.Block == blockMAX || s.Count == 0 {
+		return -1, -1
+	}
+	bits := 0
+	bitSel := uint32(blockFirstBit)
+	for bitSel > 0 && s.Block&bitSel != 0 {
+		bitSel >>= 1
+		bits++
+	}
+	return bits / 8, bits % 8
+}
+
+// Equal checks if this sequence is equal to the passed one
+func (s *Sequence) Equal(o *Sequence) bool {
+	this := s
+	other := o
+	for this != nil {
+		if other == nil {
+			return false
+		}
+		if this.Block != other.Block || this.Count != other.Count {
+			return false
+		}
+		this = this.Next
+		other = other.Next
+	}
+	// Check if other is longer than this
+	if other != nil {
+		return false
+	}
+	return true
+}
+
+// GetFirstAvailable looks for the first unset bit in passed mask
+func GetFirstAvailable(head *Sequence) (int, int) {
+	byteIndex := 0
+	current := head
+	for current != nil {
+		if current.Block != blockMAX {
+			bytePos, bitPos := current.GetAvailableBit()
+			return byteIndex + bytePos, bitPos
+		}
+		byteIndex += int(current.Count * blockBytes)
+		current = current.Next
+	}
+	return -1, -1
+}
+
+// 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 int) (int, int) {
+	bytePos := ordinal / 8
+	bitPos := ordinal % 8
+
+	// Find the Sequence containing this byte
+	current, _, _, inBlockBytePos := findSequence(head, bytePos)
+
+	if current != nil {
+		// Check whether the bit corresponding to the ordinal address is unset
+		bitSel := uint32(blockFirstBit >> uint(inBlockBytePos*8+bitPos))
+		if current.Block&bitSel == 0 {
+			return bytePos, bitPos
+		}
+	}
+
+	return -1, -1
+}
+
+// Given the byte position and the sequences list head, return the pointer to the
+// 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, -1)
+func findSequence(head *Sequence, bytePos int) (*Sequence, *Sequence, uint32, int) {
+	// Find the Sequence containing this byte
+	previous := head
+	current := head
+	n := bytePos
+	for current.Next != nil && n >= int(current.Count*blockBytes) { // Nil check for less than 32 addresses masks
+		n -= int(current.Count * blockBytes)
+		previous = current
+		current = current.Next
+	}
+
+	// If byte is outside of the list, let caller know
+	if n >= int(current.Count*blockBytes) {
+		return nil, nil, 0, -1
+	}
+
+	// Find the byte position inside the block and the number of blocks
+	// preceding the block containing the byte inside this sequence
+	precBlocks := uint32(n / blockBytes)
+	inBlockBytePos := bytePos % blockBytes
+
+	return current, previous, precBlocks, inBlockBytePos
+}
+
+// PushReservation pushes the bit reservation inside the bitmask.
+// Given byte and bit positions, identify the sequence (current) which holds the block containing the affected bit.
+// Create a new block with the modified bit according to the operation (allocate/release).
+// Create a new Sequence containing the new Block and insert it in the proper position.
+// Remove current sequence if empty.
+// Check if new Sequence can be merged with neighbour (previous/Next) sequences.
+//
+//
+// Identify "current" Sequence containing block:
+//                                      [prev seq] [current seq] [Next seq]
+//
+// Based on block position, resulting list of sequences can be any of three forms:
+//
+//        Block position                        Resulting list of sequences
+// 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 int, head *Sequence, release bool) *Sequence {
+	// Store list's head
+	newHead := head
+
+	// Find the Sequence containing this byte
+	current, previous, precBlocks, inBlockBytePos := findSequence(head, bytePos)
+	if current == nil {
+		return newHead
+	}
+
+	// Construct updated block
+	bitSel := uint32(blockFirstBit >> uint(inBlockBytePos*8+bitPos))
+	newBlock := current.Block
+	if release {
+		newBlock &^= bitSel
+	} else {
+		newBlock |= bitSel
+	}
+
+	// Quit if it was a redundant request
+	if current.Block == newBlock {
+		return newHead
+	}
+
+	// Current Sequence inevitably looses one block, upadate Count
+	current.Count--
+
+	// Create new sequence
+	newSequence := &Sequence{Block: newBlock, Count: 1}
+
+	// Insert the new sequence in the list based on block position
+	if precBlocks == 0 { // First in sequence (A)
+		newSequence.Next = current
+		if current == head {
+			newHead = newSequence
+			previous = newHead
+		} else {
+			previous.Next = newSequence
+		}
+		removeCurrentIfEmpty(&newHead, newSequence, current)
+		mergeSequences(previous)
+	} else if precBlocks == current.Count-2 { // Last in sequence (B)
+		newSequence.Next = current.Next
+		current.Next = newSequence
+		mergeSequences(current)
+	} else { // In between the sequence (C)
+		currPre := &Sequence{Block: current.Block, Count: precBlocks, Next: newSequence}
+		currPost := current
+		currPost.Count -= precBlocks
+		newSequence.Next = currPost
+		if currPost == head {
+			newHead = currPre
+		} else {
+			previous.Next = currPre
+		}
+		// No merging or empty current possible here
+	}
+
+	return newHead
+}
+
+// Removes the current sequence from the list if empty, adjusting the head pointer if needed
+func removeCurrentIfEmpty(head **Sequence, previous, current *Sequence) {
+	if current.Count == 0 {
+		if current == *head {
+			*head = current.Next
+		} else {
+			previous.Next = current.Next
+			current = current.Next
+		}
+	}
+}
+
+// Given a pointer to a Sequence, it checks if it can be merged with any following sequences
+// It stops when no more merging is possible.
+// TODO: Optimization: only attempt merge from start to end sequence, no need to scan till the end of the list
+func mergeSequences(seq *Sequence) {
+	if seq != nil {
+		// Merge all what possible from seq
+		for seq.Next != nil && seq.Block == seq.Next.Block {
+			seq.Count += seq.Next.Count
+			seq.Next = seq.Next.Next
+		}
+		// Move to Next
+		mergeSequences(seq.Next)
+	}
+}
+
+// Serialize converts the sequence into a byte array
+func Serialize(head *Sequence) ([]byte, error) {
+	return nil, nil
+}
+
+// Deserialize decodes the byte array into a sequence
+func Deserialize(data []byte) (*Sequence, error) {
+	return nil, nil
+}
+
+func getNumBlocks(numBits uint32) uint32 {
+	numBlocks := numBits / blockLen
+	if numBits%blockLen != 0 {
+		numBlocks++
+	}
+	return numBlocks
+}

+ 333 - 0
libnetwork/bitseq/sequence_test.go

@@ -0,0 +1,333 @@
+package bitseq
+
+import (
+	"testing"
+)
+
+func TestSequenceGetAvailableBit(t *testing.T) {
+	input := []struct {
+		head    *Sequence
+		bytePos int
+		bitPos  int
+	}{
+		{&Sequence{Block: 0x0, Count: 0}, -1, -1},
+		{&Sequence{Block: 0x0, Count: 1}, 0, 0},
+		{&Sequence{Block: 0x0, Count: 100}, 0, 0},
+
+		{&Sequence{Block: 0x80000000, Count: 0}, -1, -1},
+		{&Sequence{Block: 0x80000000, Count: 1}, 0, 1},
+		{&Sequence{Block: 0x80000000, Count: 100}, 0, 1},
+
+		{&Sequence{Block: 0xFF000000, Count: 0}, -1, -1},
+		{&Sequence{Block: 0xFF000000, Count: 1}, 1, 0},
+		{&Sequence{Block: 0xFF000000, Count: 100}, 1, 0},
+
+		{&Sequence{Block: 0xFF800000, Count: 0}, -1, -1},
+		{&Sequence{Block: 0xFF800000, Count: 1}, 1, 1},
+		{&Sequence{Block: 0xFF800000, Count: 100}, 1, 1},
+
+		{&Sequence{Block: 0xFFC0FF00, Count: 0}, -1, -1},
+		{&Sequence{Block: 0xFFC0FF00, Count: 1}, 1, 2},
+		{&Sequence{Block: 0xFFC0FF00, Count: 100}, 1, 2},
+
+		{&Sequence{Block: 0xFFE0FF00, Count: 0}, -1, -1},
+		{&Sequence{Block: 0xFFE0FF00, Count: 1}, 1, 3},
+		{&Sequence{Block: 0xFFE0FF00, Count: 100}, 1, 3},
+
+		{&Sequence{Block: 0xFFFEFF00, Count: 0}, -1, -1},
+		{&Sequence{Block: 0xFFFEFF00, Count: 1}, 1, 7},
+		{&Sequence{Block: 0xFFFEFF00, Count: 100}, 1, 7},
+
+		{&Sequence{Block: 0xFFFFC0FF, Count: 0}, -1, -1},
+		{&Sequence{Block: 0xFFFFC0FF, Count: 1}, 2, 2},
+		{&Sequence{Block: 0xFFFFC0FF, Count: 100}, 2, 2},
+
+		{&Sequence{Block: 0xFFFFFF00, Count: 0}, -1, -1},
+		{&Sequence{Block: 0xFFFFFF00, Count: 1}, 3, 0},
+		{&Sequence{Block: 0xFFFFFF00, Count: 100}, 3, 0},
+
+		{&Sequence{Block: 0xFFFFFFFE, Count: 0}, -1, -1},
+		{&Sequence{Block: 0xFFFFFFFE, Count: 1}, 3, 7},
+		{&Sequence{Block: 0xFFFFFFFE, Count: 100}, 3, 7},
+
+		{&Sequence{Block: 0xFFFFFFFF, Count: 0}, -1, -1},
+		{&Sequence{Block: 0xFFFFFFFF, Count: 1}, -1, -1},
+		{&Sequence{Block: 0xFFFFFFFF, Count: 100}, -1, -1},
+	}
+
+	for n, i := range input {
+		b, bb := i.head.GetAvailableBit()
+		if b != i.bytePos || bb != i.bitPos {
+			t.Fatalf("Error in Sequence.getAvailableBit() (%d).\nExp: (%d, %d)\nGot: (%d, %d),", n, i.bytePos, i.bitPos, b, bb)
+		}
+	}
+}
+
+func TestSequenceEqual(t *testing.T) {
+	input := []struct {
+		first    *Sequence
+		second   *Sequence
+		areEqual bool
+	}{
+		{&Sequence{Block: 0x0, Count: 8, Next: nil}, &Sequence{Block: 0x0, Count: 8}, true},
+		{&Sequence{Block: 0x0, Count: 0, Next: nil}, &Sequence{Block: 0x0, Count: 0}, true},
+		{&Sequence{Block: 0x0, Count: 2, Next: nil}, &Sequence{Block: 0x0, Count: 1, Next: &Sequence{Block: 0x0, Count: 1}}, false},
+		{&Sequence{Block: 0x0, Count: 2, Next: &Sequence{Block: 0x1, Count: 1}}, &Sequence{Block: 0x0, Count: 2}, false},
+
+		{&Sequence{Block: 0x12345678, Count: 8, Next: nil}, &Sequence{Block: 0x12345678, Count: 8}, true},
+		{&Sequence{Block: 0x12345678, Count: 8, Next: nil}, &Sequence{Block: 0x12345678, Count: 9}, false},
+		{&Sequence{Block: 0x12345678, Count: 1, Next: &Sequence{Block: 0XFFFFFFFF, Count: 1}}, &Sequence{Block: 0x12345678, Count: 1}, false},
+		{&Sequence{Block: 0x12345678, Count: 1}, &Sequence{Block: 0x12345678, Count: 1, Next: &Sequence{Block: 0XFFFFFFFF, Count: 1}}, false},
+	}
+
+	for n, i := range input {
+		if i.areEqual != i.first.Equal(i.second) {
+			t.Fatalf("Error in Sequence.Equal() (%d).\nExp: %t\nGot: %t,", n, i.areEqual, !i.areEqual)
+		}
+	}
+}
+
+func TestGetFirstAvailable(t *testing.T) {
+	input := []struct {
+		mask    *Sequence
+		bytePos int
+		bitPos  int
+	}{
+		{&Sequence{Block: 0xffffffff, Count: 2048}, -1, -1},
+		{&Sequence{Block: 0x0, Count: 8}, 0, 0},
+		{&Sequence{Block: 0x80000000, Count: 8}, 0, 1},
+		{&Sequence{Block: 0xC0000000, Count: 8}, 0, 2},
+		{&Sequence{Block: 0xE0000000, Count: 8}, 0, 3},
+		{&Sequence{Block: 0xF0000000, Count: 8}, 0, 4},
+		{&Sequence{Block: 0xF8000000, Count: 8}, 0, 5},
+		{&Sequence{Block: 0xFC000000, Count: 8}, 0, 6},
+		{&Sequence{Block: 0xFE000000, Count: 8}, 0, 7},
+
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0x00000000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}, 4, 0},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0x80000000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}, 4, 1},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xC0000000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}, 4, 2},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xE0000000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}, 4, 3},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xF0000000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}, 4, 4},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xF8000000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}, 4, 5},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xFC000000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}, 4, 6},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xFE000000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}, 4, 7},
+
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xFF000000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}, 5, 0},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xFF800000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}, 5, 1},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xFFC00000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}, 5, 2},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xFFE00000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}, 5, 3},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xFFF00000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}, 5, 4},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xFFF80000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}, 5, 5},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xFFFC0000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}, 5, 6},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xFFFE0000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}, 5, 7},
+
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xfffffffe, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}, 7, 7},
+
+		{&Sequence{Block: 0xffffffff, Count: 2, Next: &Sequence{Block: 0x0, Count: 6}}, 8, 0},
+	}
+
+	for n, i := range input {
+		bytePos, bitPos := GetFirstAvailable(i.mask)
+		if bytePos != i.bytePos || bitPos != i.bitPos {
+			t.Fatalf("Error in (%d) getFirstAvailable(). Expected (%d, %d). Got (%d, %d)", n, i.bytePos, i.bitPos, bytePos, bitPos)
+		}
+	}
+}
+
+func TestFindSequence(t *testing.T) {
+	input := []struct {
+		head           *Sequence
+		bytePos        int
+		precBlocks     uint32
+		inBlockBytePos int
+	}{
+		{&Sequence{Block: 0xffffffff, Count: 0}, 0, 0, -1},
+		{&Sequence{Block: 0xffffffff, Count: 0}, 31, 0, -1},
+		{&Sequence{Block: 0xffffffff, Count: 0}, 100, 0, -1},
+
+		{&Sequence{Block: 0x0, Count: 1}, 0, 0, 0},
+		{&Sequence{Block: 0x0, Count: 1}, 1, 0, 1},
+		{&Sequence{Block: 0x0, Count: 1}, 31, 0, -1},
+		{&Sequence{Block: 0x0, Count: 1}, 60, 0, -1},
+
+		{&Sequence{Block: 0xffffffff, Count: 10}, 0, 0, 0},
+		{&Sequence{Block: 0xffffffff, Count: 10}, 3, 0, 3},
+		{&Sequence{Block: 0xffffffff, Count: 10}, 4, 1, 0},
+		{&Sequence{Block: 0xffffffff, Count: 10}, 7, 1, 3},
+		{&Sequence{Block: 0xffffffff, Count: 10}, 8, 2, 0},
+		{&Sequence{Block: 0xffffffff, Count: 10}, 39, 9, 3},
+
+		{&Sequence{Block: 0xffffffff, Count: 10, Next: &Sequence{Block: 0xcc000000, Count: 10}}, 79, 9, 3},
+		{&Sequence{Block: 0xffffffff, Count: 10, Next: &Sequence{Block: 0xcc000000, Count: 10}}, 80, 0, -1},
+	}
+
+	for n, i := range input {
+		_, _, precBlocks, inBlockBytePos := findSequence(i.head, i.bytePos)
+		if precBlocks != i.precBlocks || inBlockBytePos != i.inBlockBytePos {
+			t.Fatalf("Error in (%d) findSequence(). Expected (%d, %d). Got (%d, %d)", n, i.precBlocks, i.inBlockBytePos, precBlocks, inBlockBytePos)
+		}
+	}
+}
+
+func TestCheckIfAvailable(t *testing.T) {
+	input := []struct {
+		head    *Sequence
+		ordinal int
+		bytePos int
+		bitPos  int
+	}{
+		{&Sequence{Block: 0xffffffff, Count: 0}, 0, -1, -1},
+		{&Sequence{Block: 0xffffffff, Count: 0}, 31, -1, -1},
+		{&Sequence{Block: 0xffffffff, Count: 0}, 100, -1, -1},
+
+		{&Sequence{Block: 0x0, Count: 1}, 0, 0, 0},
+		{&Sequence{Block: 0x0, Count: 1}, 1, 0, 1},
+		{&Sequence{Block: 0x0, Count: 1}, 31, 3, 7},
+		{&Sequence{Block: 0x0, Count: 1}, 60, -1, -1},
+
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0x800000ff, Count: 1}}, 31, -1, -1},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0x800000ff, Count: 1}}, 32, -1, -1},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0x800000ff, Count: 1}}, 33, 4, 1},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xC00000ff, Count: 1}}, 33, -1, -1},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xC00000ff, Count: 1}}, 34, 4, 2},
+
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xC00000ff, Count: 1, Next: &Sequence{Block: 0x0, Count: 1}}}, 55, 6, 7},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xC00000ff, Count: 1, Next: &Sequence{Block: 0x0, Count: 1}}}, 56, -1, -1},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xC00000ff, Count: 1, Next: &Sequence{Block: 0x0, Count: 1}}}, 63, -1, -1},
+
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xC00000ff, Count: 1, Next: &Sequence{Block: 0x0, Count: 1}}}, 64, 8, 0},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xC00000ff, Count: 1, Next: &Sequence{Block: 0x0, Count: 1}}}, 95, 11, 7},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xC00000ff, Count: 1, Next: &Sequence{Block: 0x0, Count: 1}}}, 96, -1, -1},
+	}
+
+	for n, i := range input {
+		bytePos, bitPos := CheckIfAvailable(i.head, i.ordinal)
+		if bytePos != i.bytePos || bitPos != i.bitPos {
+			t.Fatalf("Error in (%d) checkIfAvailable(ord:%d). Expected (%d, %d). Got (%d, %d)", n, i.ordinal, i.bytePos, i.bitPos, bytePos, bitPos)
+		}
+	}
+}
+
+func TestMergeSequences(t *testing.T) {
+	input := []struct {
+		original *Sequence
+		merged   *Sequence
+	}{
+		{&Sequence{Block: 0xFE000000, Count: 8, Next: &Sequence{Block: 0xFE000000, Count: 2}}, &Sequence{Block: 0xFE000000, Count: 10}},
+		{&Sequence{Block: 0xFFFFFFFF, Count: 8, Next: &Sequence{Block: 0xFFFFFFFF, Count: 1}}, &Sequence{Block: 0xFFFFFFFF, Count: 9}},
+		{&Sequence{Block: 0xFFFFFFFF, Count: 1, Next: &Sequence{Block: 0xFFFFFFFF, Count: 8}}, &Sequence{Block: 0xFFFFFFFF, Count: 9}},
+
+		{&Sequence{Block: 0xFFFFFFF0, Count: 8, Next: &Sequence{Block: 0xFFFFFFF0, Count: 1}}, &Sequence{Block: 0xFFFFFFF0, Count: 9}},
+		{&Sequence{Block: 0xFFFFFFF0, Count: 1, Next: &Sequence{Block: 0xFFFFFFF0, Count: 8}}, &Sequence{Block: 0xFFFFFFF0, Count: 9}},
+
+		{&Sequence{Block: 0xFE, Count: 8, Next: &Sequence{Block: 0xFE, Count: 1, Next: &Sequence{Block: 0xFE, Count: 5}}}, &Sequence{Block: 0xFE, Count: 14}},
+		{&Sequence{Block: 0xFE, Count: 8, Next: &Sequence{Block: 0xFE, Count: 1, Next: &Sequence{Block: 0xFE, Count: 5, Next: &Sequence{Block: 0xFF, Count: 1}}}},
+			&Sequence{Block: 0xFE, Count: 14, Next: &Sequence{Block: 0xFF, Count: 1}}},
+
+		// No merge
+		{&Sequence{Block: 0xFE, Count: 8, Next: &Sequence{Block: 0xF8, Count: 1, Next: &Sequence{Block: 0xFE, Count: 5}}},
+			&Sequence{Block: 0xFE, Count: 8, Next: &Sequence{Block: 0xF8, Count: 1, Next: &Sequence{Block: 0xFE, Count: 5}}}},
+
+		// No merge from head: // Merge function tries to merge from passed head. If it can't merge with Next, it does not reattempt with Next as head
+		{&Sequence{Block: 0xFE, Count: 8, Next: &Sequence{Block: 0xFF, Count: 1, Next: &Sequence{Block: 0xFF, Count: 5}}},
+			&Sequence{Block: 0xFE, Count: 8, Next: &Sequence{Block: 0xFF, Count: 6}}},
+	}
+
+	for n, i := range input {
+		mergeSequences(i.original)
+		for !i.merged.Equal(i.original) {
+			t.Fatalf("Error in (%d) mergeSequences().\nExp: %s\nGot: %s,", n, i.merged, i.original)
+		}
+	}
+}
+
+func TestPushReservation(t *testing.T) {
+	input := []struct {
+		mask    *Sequence
+		bytePos int
+		bitPos  int
+		newMask *Sequence
+	}{
+		// Create first Sequence and fill in 8 addresses starting from address 0
+		{&Sequence{Block: 0x0, Count: 8, Next: nil}, 0, 0, &Sequence{Block: 0x80000000, Count: 1, Next: &Sequence{Block: 0x0, Count: 7, Next: nil}}},
+		{&Sequence{Block: 0x80000000, Count: 8}, 0, 1, &Sequence{Block: 0xC0000000, Count: 1, Next: &Sequence{Block: 0x80000000, Count: 7, Next: nil}}},
+		{&Sequence{Block: 0xC0000000, Count: 8}, 0, 2, &Sequence{Block: 0xE0000000, Count: 1, Next: &Sequence{Block: 0xC0000000, Count: 7, Next: nil}}},
+		{&Sequence{Block: 0xE0000000, Count: 8}, 0, 3, &Sequence{Block: 0xF0000000, Count: 1, Next: &Sequence{Block: 0xE0000000, Count: 7, Next: nil}}},
+		{&Sequence{Block: 0xF0000000, Count: 8}, 0, 4, &Sequence{Block: 0xF8000000, Count: 1, Next: &Sequence{Block: 0xF0000000, Count: 7, Next: nil}}},
+		{&Sequence{Block: 0xF8000000, Count: 8}, 0, 5, &Sequence{Block: 0xFC000000, Count: 1, Next: &Sequence{Block: 0xF8000000, Count: 7, Next: nil}}},
+		{&Sequence{Block: 0xFC000000, Count: 8}, 0, 6, &Sequence{Block: 0xFE000000, Count: 1, Next: &Sequence{Block: 0xFC000000, Count: 7, Next: nil}}},
+		{&Sequence{Block: 0xFE000000, Count: 8}, 0, 7, &Sequence{Block: 0xFF000000, Count: 1, Next: &Sequence{Block: 0xFE000000, Count: 7, Next: nil}}},
+
+		{&Sequence{Block: 0x80000000, Count: 1, Next: &Sequence{Block: 0x0, Count: 7}}, 0, 1, &Sequence{Block: 0xC0000000, Count: 1, Next: &Sequence{Block: 0x0, Count: 7, Next: nil}}},
+
+		// Create second Sequence and fill in 8 addresses starting from address 32
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0x00000000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6, Next: nil}}}, 4, 0,
+			&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0x80000000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0x80000000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}, 4, 1,
+			&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xC0000000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xC0000000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}, 4, 2,
+			&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xE0000000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xE0000000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}, 4, 3,
+			&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xF0000000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xF0000000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}, 4, 4,
+			&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xF8000000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xF8000000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}, 4, 5,
+			&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xFC000000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xFC000000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}, 4, 6,
+			&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xFE000000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xFE000000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}, 4, 7,
+			&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xFF000000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}},
+		// fill in 8 addresses starting from address 40
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xFF000000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}, 5, 0,
+			&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xFF800000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xFF800000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}, 5, 1,
+			&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xFFC00000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xFFC00000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}, 5, 2,
+			&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xFFE00000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xFFE00000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}, 5, 3,
+			&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xFFF00000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xFFF00000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}, 5, 4,
+			&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xFFF80000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xFFF80000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}, 5, 5,
+			&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xFFFC0000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xFFFC0000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}, 5, 6,
+			&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xFFFE0000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xFFFE0000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}, 5, 7,
+			&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xFFFF0000, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 6}}}},
+
+		// Insert new Sequence
+		{&Sequence{Block: 0xffffffff, Count: 2, Next: &Sequence{Block: 0x0, Count: 6}}, 8, 0,
+			&Sequence{Block: 0xffffffff, Count: 2, Next: &Sequence{Block: 0x80000000, Count: 1, Next: &Sequence{Block: 0x0, Count: 5}}}},
+		{&Sequence{Block: 0xffffffff, Count: 2, Next: &Sequence{Block: 0x80000000, Count: 1, Next: &Sequence{Block: 0x0, Count: 5}}}, 8, 1,
+			&Sequence{Block: 0xffffffff, Count: 2, Next: &Sequence{Block: 0xC0000000, Count: 1, Next: &Sequence{Block: 0x0, Count: 5}}}},
+
+		// Merge affected with Next
+		{&Sequence{Block: 0xffffffff, Count: 7, Next: &Sequence{Block: 0xfffffffe, Count: 2, Next: &Sequence{Block: 0xffffffff, Count: 1}}}, 31, 7,
+			&Sequence{Block: 0xffffffff, Count: 8, Next: &Sequence{Block: 0xfffffffe, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 1}}}},
+		{&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xfffffffc, Count: 1, Next: &Sequence{Block: 0xfffffffe, Count: 6}}}, 7, 6,
+			&Sequence{Block: 0xffffffff, Count: 1, Next: &Sequence{Block: 0xfffffffe, Count: 7}}},
+
+		// Merge affected with Next and Next.Next
+		{&Sequence{Block: 0xffffffff, Count: 7, Next: &Sequence{Block: 0xfffffffe, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 1}}}, 31, 7,
+			&Sequence{Block: 0xffffffff, Count: 9}},
+		{&Sequence{Block: 0xffffffff, Count: 7, Next: &Sequence{Block: 0xfffffffe, Count: 1}}, 31, 7,
+			&Sequence{Block: 0xffffffff, Count: 8}},
+
+		// Merge affected with previous and Next
+		{&Sequence{Block: 0xffffffff, Count: 7, Next: &Sequence{Block: 0xfffffffe, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 1}}}, 31, 7,
+			&Sequence{Block: 0xffffffff, Count: 9}},
+
+		// Redundant push: No change
+		{&Sequence{Block: 0xffff0000, Count: 1}, 0, 0, &Sequence{Block: 0xffff0000, Count: 1}},
+		{&Sequence{Block: 0xffff0000, Count: 7}, 25, 7, &Sequence{Block: 0xffff0000, Count: 7}},
+		{&Sequence{Block: 0xffffffff, Count: 7, Next: &Sequence{Block: 0xfffffffe, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 1}}}, 7, 7,
+			&Sequence{Block: 0xffffffff, Count: 7, Next: &Sequence{Block: 0xfffffffe, Count: 1, Next: &Sequence{Block: 0xffffffff, Count: 1}}}},
+	}
+
+	for n, i := range input {
+		mask := PushReservation(i.bytePos, i.bitPos, i.mask, false)
+		if !mask.Equal(i.newMask) {
+			t.Fatalf("Error in (%d) pushReservation():\n%s + (%d,%d):\nExp: %s\nGot: %s,", n, i.mask, i.bytePos, i.bitPos, i.newMask, mask)
+		}
+	}
+}