123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- // Package bitseq provides a structure and utilities for representing a long
- // bitmask which is persisted in a datastore. It is backed by [bitmap.Bitmap]
- // which operates directly on the encoded representation, without uncompressing.
- package bitseq
- import (
- "encoding/json"
- "fmt"
- "sync"
- "github.com/docker/docker/libnetwork/bitmap"
- "github.com/docker/docker/libnetwork/datastore"
- "github.com/docker/docker/libnetwork/types"
- )
- var (
- // ErrNoBitAvailable is returned when no more bits are available to set
- ErrNoBitAvailable = bitmap.ErrNoBitAvailable
- // ErrBitAllocated is returned when the specific bit requested is already set
- ErrBitAllocated = bitmap.ErrBitAllocated
- )
- // Handle contains the sequence representing the bitmask and its identifier
- type Handle struct {
- app string
- id string
- dbIndex uint64
- dbExists bool
- store datastore.DataStore
- bm *bitmap.Bitmap
- mu sync.Mutex
- }
- // NewHandle returns a thread-safe instance of the bitmask handler
- func NewHandle(app string, ds datastore.DataStore, id string, numElements uint64) (*Handle, error) {
- h := &Handle{
- bm: bitmap.New(numElements),
- app: app,
- id: id,
- store: ds,
- }
- if h.store == nil {
- return h, nil
- }
- // Get the initial status from the ds if present.
- if err := h.store.GetObject(datastore.Key(h.Key()...), h); err != nil && err != datastore.ErrKeyNotFound {
- return nil, err
- }
- // If the handle is not in store, write it.
- if !h.Exists() {
- if err := h.writeToStore(); err != nil {
- return nil, fmt.Errorf("failed to write bitsequence to store: %v", err)
- }
- }
- return h, nil
- }
- func (h *Handle) getCopy() *Handle {
- return &Handle{
- bm: bitmap.Copy(h.bm),
- app: h.app,
- id: h.id,
- dbIndex: h.dbIndex,
- dbExists: h.dbExists,
- store: h.store,
- }
- }
- // 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, serial bool) (uint64, error) {
- return h.apply(func(b *bitmap.Bitmap) (uint64, error) { return b.SetAnyInRange(start, end, serial) })
- }
- // SetAny atomically sets the first unset bit in the sequence and returns the corresponding ordinal
- func (h *Handle) SetAny(serial bool) (uint64, error) {
- return h.apply(func(b *bitmap.Bitmap) (uint64, error) { return b.SetAny(serial) })
- }
- // Set atomically sets the corresponding bit in the sequence
- func (h *Handle) Set(ordinal uint64) error {
- _, err := h.apply(func(b *bitmap.Bitmap) (uint64, error) { return 0, b.Set(ordinal) })
- return err
- }
- // Unset atomically unsets the corresponding bit in the sequence
- func (h *Handle) Unset(ordinal uint64) error {
- _, err := h.apply(func(b *bitmap.Bitmap) (uint64, error) { return 0, b.Unset(ordinal) })
- return err
- }
- // 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 uint64) bool {
- h.mu.Lock()
- defer h.mu.Unlock()
- return h.bm.IsSet(ordinal)
- }
- // set/reset the bit
- func (h *Handle) apply(op func(*bitmap.Bitmap) (uint64, error)) (uint64, error) {
- for {
- var store datastore.DataStore
- h.mu.Lock()
- store = h.store
- if store != nil {
- h.mu.Unlock() // The lock is acquired in the GetObject
- if err := store.GetObject(datastore.Key(h.Key()...), h); err != nil && err != datastore.ErrKeyNotFound {
- return 0, err
- }
- h.mu.Lock() // Acquire the lock back
- }
- // Create a private copy of h and work on it
- nh := h.getCopy()
- ret, err := op(nh.bm)
- if err != nil {
- h.mu.Unlock()
- return ret, err
- }
- if h.store != nil {
- h.mu.Unlock()
- // Attempt to write private copy to store
- if err := nh.writeToStore(); err != nil {
- if _, ok := err.(types.RetryError); !ok {
- return ret, fmt.Errorf("internal failure while setting the bit: %v", err)
- }
- // Retry
- continue
- }
- h.mu.Lock()
- }
- // Previous atomic push was successful. Save private copy to local copy
- h.bm = nh.bm
- h.dbExists = nh.dbExists
- h.dbIndex = nh.dbIndex
- h.mu.Unlock()
- return ret, nil
- }
- }
- // Destroy removes from the datastore the data belonging to this handle
- func (h *Handle) Destroy() error {
- for {
- if err := h.deleteFromStore(); err != nil {
- if _, ok := err.(types.RetryError); !ok {
- return fmt.Errorf("internal failure while destroying the sequence: %v", err)
- }
- // Fetch latest
- if err := h.store.GetObject(datastore.Key(h.Key()...), h); err != nil {
- if err == datastore.ErrKeyNotFound { // already removed
- return nil
- }
- return fmt.Errorf("failed to fetch from store when destroying the sequence: %v", err)
- }
- continue
- }
- return nil
- }
- }
- // Bits returns the length of the bit sequence
- func (h *Handle) Bits() uint64 {
- h.mu.Lock()
- defer h.mu.Unlock()
- return h.bm.Bits()
- }
- // Unselected returns the number of bits which are not selected
- func (h *Handle) Unselected() uint64 {
- h.mu.Lock()
- defer h.mu.Unlock()
- return h.bm.Unselected()
- }
- func (h *Handle) String() string {
- h.mu.Lock()
- defer h.mu.Unlock()
- return fmt.Sprintf("App: %s, ID: %s, DBIndex: 0x%x, %s",
- h.app, h.id, h.dbIndex, h.bm)
- }
- type jsonMessage struct {
- ID string `json:"id"`
- Sequence *bitmap.Bitmap `json:"sequence"`
- }
- // MarshalJSON encodes h into a JSON message.
- func (h *Handle) MarshalJSON() ([]byte, error) {
- h.mu.Lock()
- defer h.mu.Unlock()
- m := jsonMessage{ID: h.id, Sequence: h.bm}
- return json.Marshal(m)
- }
- // UnmarshalJSON decodes a JSON message into h.
- func (h *Handle) UnmarshalJSON(data []byte) error {
- var m jsonMessage
- if err := json.Unmarshal(data, &m); err != nil {
- return err
- }
- h.mu.Lock()
- defer h.mu.Unlock()
- h.id, h.bm = m.ID, m.Sequence
- return nil
- }
|