github.com/rawahars/moby@v24.0.4+incompatible/libnetwork/bitseq/sequence.go (about)

     1  // Package bitseq provides a structure and utilities for representing a long
     2  // bitmask which is persisted in a datastore. It is backed by [bitmap.Bitmap]
     3  // which operates directly on the encoded representation, without uncompressing.
     4  package bitseq
     5  
     6  import (
     7  	"encoding/json"
     8  	"fmt"
     9  	"sync"
    10  
    11  	"github.com/docker/docker/libnetwork/bitmap"
    12  	"github.com/docker/docker/libnetwork/datastore"
    13  	"github.com/docker/docker/libnetwork/types"
    14  )
    15  
    16  var (
    17  	// ErrNoBitAvailable is returned when no more bits are available to set
    18  	ErrNoBitAvailable = bitmap.ErrNoBitAvailable
    19  	// ErrBitAllocated is returned when the specific bit requested is already set
    20  	ErrBitAllocated = bitmap.ErrBitAllocated
    21  )
    22  
    23  // Handle contains the sequence representing the bitmask and its identifier
    24  type Handle struct {
    25  	app      string
    26  	id       string
    27  	dbIndex  uint64
    28  	dbExists bool
    29  	store    datastore.DataStore
    30  	bm       *bitmap.Bitmap
    31  	mu       sync.Mutex
    32  }
    33  
    34  // NewHandle returns a thread-safe instance of the bitmask handler
    35  func NewHandle(app string, ds datastore.DataStore, id string, numElements uint64) (*Handle, error) {
    36  	h := &Handle{
    37  		bm:    bitmap.New(numElements),
    38  		app:   app,
    39  		id:    id,
    40  		store: ds,
    41  	}
    42  
    43  	if h.store == nil {
    44  		return h, nil
    45  	}
    46  
    47  	// Get the initial status from the ds if present.
    48  	if err := h.store.GetObject(datastore.Key(h.Key()...), h); err != nil && err != datastore.ErrKeyNotFound {
    49  		return nil, err
    50  	}
    51  
    52  	// If the handle is not in store, write it.
    53  	if !h.Exists() {
    54  		if err := h.writeToStore(); err != nil {
    55  			return nil, fmt.Errorf("failed to write bitsequence to store: %v", err)
    56  		}
    57  	}
    58  
    59  	return h, nil
    60  }
    61  
    62  func (h *Handle) getCopy() *Handle {
    63  	return &Handle{
    64  		bm:       bitmap.Copy(h.bm),
    65  		app:      h.app,
    66  		id:       h.id,
    67  		dbIndex:  h.dbIndex,
    68  		dbExists: h.dbExists,
    69  		store:    h.store,
    70  	}
    71  }
    72  
    73  // SetAnyInRange atomically sets the first unset bit in the specified range in the sequence and returns the corresponding ordinal
    74  func (h *Handle) SetAnyInRange(start, end uint64, serial bool) (uint64, error) {
    75  	return h.apply(func(b *bitmap.Bitmap) (uint64, error) { return b.SetAnyInRange(start, end, serial) })
    76  }
    77  
    78  // SetAny atomically sets the first unset bit in the sequence and returns the corresponding ordinal
    79  func (h *Handle) SetAny(serial bool) (uint64, error) {
    80  	return h.apply(func(b *bitmap.Bitmap) (uint64, error) { return b.SetAny(serial) })
    81  }
    82  
    83  // Set atomically sets the corresponding bit in the sequence
    84  func (h *Handle) Set(ordinal uint64) error {
    85  	_, err := h.apply(func(b *bitmap.Bitmap) (uint64, error) { return 0, b.Set(ordinal) })
    86  	return err
    87  }
    88  
    89  // Unset atomically unsets the corresponding bit in the sequence
    90  func (h *Handle) Unset(ordinal uint64) error {
    91  	_, err := h.apply(func(b *bitmap.Bitmap) (uint64, error) { return 0, b.Unset(ordinal) })
    92  	return err
    93  }
    94  
    95  // IsSet atomically checks if the ordinal bit is set. In case ordinal
    96  // is outside of the bit sequence limits, false is returned.
    97  func (h *Handle) IsSet(ordinal uint64) bool {
    98  	h.mu.Lock()
    99  	defer h.mu.Unlock()
   100  	return h.bm.IsSet(ordinal)
   101  }
   102  
   103  // set/reset the bit
   104  func (h *Handle) apply(op func(*bitmap.Bitmap) (uint64, error)) (uint64, error) {
   105  	for {
   106  		var store datastore.DataStore
   107  		h.mu.Lock()
   108  		store = h.store
   109  		if store != nil {
   110  			h.mu.Unlock() // The lock is acquired in the GetObject
   111  			if err := store.GetObject(datastore.Key(h.Key()...), h); err != nil && err != datastore.ErrKeyNotFound {
   112  				return 0, err
   113  			}
   114  			h.mu.Lock() // Acquire the lock back
   115  		}
   116  
   117  		// Create a private copy of h and work on it
   118  		nh := h.getCopy()
   119  
   120  		ret, err := op(nh.bm)
   121  		if err != nil {
   122  			h.mu.Unlock()
   123  			return ret, err
   124  		}
   125  
   126  		if h.store != nil {
   127  			h.mu.Unlock()
   128  			// Attempt to write private copy to store
   129  			if err := nh.writeToStore(); err != nil {
   130  				if _, ok := err.(types.RetryError); !ok {
   131  					return ret, fmt.Errorf("internal failure while setting the bit: %v", err)
   132  				}
   133  				// Retry
   134  				continue
   135  			}
   136  			h.mu.Lock()
   137  		}
   138  
   139  		// Previous atomic push was successful. Save private copy to local copy
   140  		h.bm = nh.bm
   141  		h.dbExists = nh.dbExists
   142  		h.dbIndex = nh.dbIndex
   143  		h.mu.Unlock()
   144  		return ret, nil
   145  	}
   146  }
   147  
   148  // Destroy removes from the datastore the data belonging to this handle
   149  func (h *Handle) Destroy() error {
   150  	for {
   151  		if err := h.deleteFromStore(); err != nil {
   152  			if _, ok := err.(types.RetryError); !ok {
   153  				return fmt.Errorf("internal failure while destroying the sequence: %v", err)
   154  			}
   155  			// Fetch latest
   156  			if err := h.store.GetObject(datastore.Key(h.Key()...), h); err != nil {
   157  				if err == datastore.ErrKeyNotFound { // already removed
   158  					return nil
   159  				}
   160  				return fmt.Errorf("failed to fetch from store when destroying the sequence: %v", err)
   161  			}
   162  			continue
   163  		}
   164  		return nil
   165  	}
   166  }
   167  
   168  // Bits returns the length of the bit sequence
   169  func (h *Handle) Bits() uint64 {
   170  	h.mu.Lock()
   171  	defer h.mu.Unlock()
   172  	return h.bm.Bits()
   173  }
   174  
   175  // Unselected returns the number of bits which are not selected
   176  func (h *Handle) Unselected() uint64 {
   177  	h.mu.Lock()
   178  	defer h.mu.Unlock()
   179  	return h.bm.Unselected()
   180  }
   181  
   182  func (h *Handle) String() string {
   183  	h.mu.Lock()
   184  	defer h.mu.Unlock()
   185  	return fmt.Sprintf("App: %s, ID: %s, DBIndex: 0x%x, %s",
   186  		h.app, h.id, h.dbIndex, h.bm)
   187  }
   188  
   189  type jsonMessage struct {
   190  	ID       string         `json:"id"`
   191  	Sequence *bitmap.Bitmap `json:"sequence"`
   192  }
   193  
   194  // MarshalJSON encodes h into a JSON message.
   195  func (h *Handle) MarshalJSON() ([]byte, error) {
   196  	h.mu.Lock()
   197  	defer h.mu.Unlock()
   198  	m := jsonMessage{ID: h.id, Sequence: h.bm}
   199  	return json.Marshal(m)
   200  }
   201  
   202  // UnmarshalJSON decodes a JSON message into h.
   203  func (h *Handle) UnmarshalJSON(data []byte) error {
   204  	var m jsonMessage
   205  	if err := json.Unmarshal(data, &m); err != nil {
   206  		return err
   207  	}
   208  
   209  	h.mu.Lock()
   210  	defer h.mu.Unlock()
   211  	h.id, h.bm = m.ID, m.Sequence
   212  	return nil
   213  }