2023-01-20 13:51:15 -05:00
|
|
|
// 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.
|
2015-06-12 12:03:33 -07:00
|
|
|
package bitseq
|
|
|
|
|
|
|
|
import (
|
2015-10-05 14:53:25 -07:00
|
|
|
"encoding/json"
|
2015-06-12 12:03:33 -07:00
|
|
|
"fmt"
|
2015-06-14 10:21:59 -07:00
|
|
|
"sync"
|
2015-06-12 15:06:42 -07:00
|
|
|
|
2023-01-20 13:51:15 -05:00
|
|
|
"github.com/docker/docker/libnetwork/bitmap"
|
2021-04-06 00:24:47 +00:00
|
|
|
"github.com/docker/docker/libnetwork/datastore"
|
|
|
|
"github.com/docker/docker/libnetwork/types"
|
2017-07-26 14:18:31 -07:00
|
|
|
"github.com/sirupsen/logrus"
|
2015-06-12 12:03:33 -07:00
|
|
|
)
|
|
|
|
|
2015-06-24 12:10:54 -07:00
|
|
|
var (
|
2015-10-20 17:05:01 -07:00
|
|
|
// ErrNoBitAvailable is returned when no more bits are available to set
|
2023-01-20 13:51:15 -05:00
|
|
|
ErrNoBitAvailable = bitmap.ErrNoBitAvailable
|
2015-10-20 17:05:01 -07:00
|
|
|
// ErrBitAllocated is returned when the specific bit requested is already set
|
2023-01-20 13:51:15 -05:00
|
|
|
ErrBitAllocated = bitmap.ErrBitAllocated
|
2015-06-24 12:10:54 -07:00
|
|
|
)
|
|
|
|
|
2018-09-07 11:43:42 +08:00
|
|
|
// Handle contains the sequence representing the bitmask and its identifier
|
2015-06-13 13:35:43 -07:00
|
|
|
type Handle struct {
|
2023-01-20 13:51:15 -05:00
|
|
|
app string
|
|
|
|
id string
|
|
|
|
dbIndex uint64
|
|
|
|
dbExists bool
|
|
|
|
store datastore.DataStore
|
|
|
|
bm *bitmap.Bitmap
|
2023-01-20 13:54:26 -05:00
|
|
|
mu sync.Mutex
|
2015-06-13 13:35:43 -07:00
|
|
|
}
|
|
|
|
|
2015-06-14 10:21:59 -07:00
|
|
|
// NewHandle returns a thread-safe instance of the bitmask handler
|
2015-10-08 20:04:13 -07:00
|
|
|
func NewHandle(app string, ds datastore.DataStore, id string, numElements uint64) (*Handle, error) {
|
2015-06-15 11:43:02 -07:00
|
|
|
h := &Handle{
|
2023-01-20 13:51:15 -05:00
|
|
|
bm: bitmap.New(numElements),
|
|
|
|
app: app,
|
|
|
|
id: id,
|
|
|
|
store: ds,
|
2015-06-13 13:35:43 -07:00
|
|
|
}
|
2015-06-15 18:28:00 -07:00
|
|
|
|
|
|
|
if h.store == nil {
|
2015-06-16 14:46:51 -07:00
|
|
|
return h, nil
|
2015-06-15 18:28:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get the initial status from the ds if present.
|
2015-07-04 16:48:09 -07:00
|
|
|
if err := h.store.GetObject(datastore.Key(h.Key()...), h); err != nil && err != datastore.ErrKeyNotFound {
|
2015-06-18 15:13:38 -07:00
|
|
|
return nil, err
|
2015-06-15 18:28:00 -07:00
|
|
|
}
|
2015-06-18 12:06:11 -07:00
|
|
|
|
2015-10-03 20:23:26 -07:00
|
|
|
// 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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-04 16:48:09 -07:00
|
|
|
return h, nil
|
2015-06-13 13:35:43 -07:00
|
|
|
}
|
|
|
|
|
2015-06-24 12:10:54 -07:00
|
|
|
func (h *Handle) getCopy() *Handle {
|
|
|
|
return &Handle{
|
2023-01-20 13:51:15 -05:00
|
|
|
bm: bitmap.Copy(h.bm),
|
|
|
|
app: h.app,
|
|
|
|
id: h.id,
|
|
|
|
dbIndex: h.dbIndex,
|
|
|
|
dbExists: h.dbExists,
|
|
|
|
store: h.store,
|
2015-06-24 12:10:54 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-17 15:16:21 -07:00
|
|
|
// SetAnyInRange atomically sets the first unset bit in the specified range in the sequence and returns the corresponding ordinal
|
2017-05-31 19:41:21 -07:00
|
|
|
func (h *Handle) SetAnyInRange(start, end uint64, serial bool) (uint64, error) {
|
2023-01-20 13:51:15 -05:00
|
|
|
return h.apply(func(b *bitmap.Bitmap) (uint64, error) { return b.SetAnyInRange(start, end, serial) })
|
2015-09-17 15:16:21 -07:00
|
|
|
}
|
|
|
|
|
2015-06-24 12:10:54 -07:00
|
|
|
// SetAny atomically sets the first unset bit in the sequence and returns the corresponding ordinal
|
2017-05-31 19:41:21 -07:00
|
|
|
func (h *Handle) SetAny(serial bool) (uint64, error) {
|
2023-01-20 13:51:15 -05:00
|
|
|
return h.apply(func(b *bitmap.Bitmap) (uint64, error) { return b.SetAny(serial) })
|
2015-06-24 12:10:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Set atomically sets the corresponding bit in the sequence
|
2015-10-08 20:04:13 -07:00
|
|
|
func (h *Handle) Set(ordinal uint64) error {
|
2023-01-20 13:51:15 -05:00
|
|
|
_, err := h.apply(func(b *bitmap.Bitmap) (uint64, error) { return 0, b.Set(ordinal) })
|
2015-06-24 12:10:54 -07:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unset atomically unsets the corresponding bit in the sequence
|
2015-10-08 20:04:13 -07:00
|
|
|
func (h *Handle) Unset(ordinal uint64) error {
|
2023-01-20 13:51:15 -05:00
|
|
|
_, err := h.apply(func(b *bitmap.Bitmap) (uint64, error) { return 0, b.Unset(ordinal) })
|
2015-06-24 12:10:54 -07:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsSet atomically checks if the ordinal bit is set. In case ordinal
|
|
|
|
// is outside of the bit sequence limits, false is returned.
|
2015-10-08 20:04:13 -07:00
|
|
|
func (h *Handle) IsSet(ordinal uint64) bool {
|
2023-01-20 13:54:26 -05:00
|
|
|
h.mu.Lock()
|
|
|
|
defer h.mu.Unlock()
|
2023-01-20 13:51:15 -05:00
|
|
|
return h.bm.IsSet(ordinal)
|
2016-01-11 13:03:52 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// CheckConsistency checks if the bit sequence is in an inconsistent state and attempts to fix it.
|
|
|
|
// It looks for a corruption signature that may happen in docker 1.9.0 and 1.9.1.
|
|
|
|
func (h *Handle) CheckConsistency() error {
|
|
|
|
for {
|
2023-01-20 13:54:26 -05:00
|
|
|
h.mu.Lock()
|
2016-01-11 13:03:52 -08:00
|
|
|
store := h.store
|
2023-01-20 13:54:26 -05:00
|
|
|
h.mu.Unlock()
|
2016-01-11 13:03:52 -08:00
|
|
|
|
|
|
|
if store != nil {
|
|
|
|
if err := store.GetObject(datastore.Key(h.Key()...), h); err != nil && err != datastore.ErrKeyNotFound {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-20 13:54:26 -05:00
|
|
|
h.mu.Lock()
|
2016-01-11 13:03:52 -08:00
|
|
|
nh := h.getCopy()
|
2023-01-20 13:54:26 -05:00
|
|
|
h.mu.Unlock()
|
2016-01-11 13:03:52 -08:00
|
|
|
|
2023-01-20 13:51:15 -05:00
|
|
|
if !nh.bm.CheckConsistency() {
|
2016-01-11 13:03:52 -08:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := nh.writeToStore(); err != nil {
|
|
|
|
if _, ok := err.(types.RetryError); !ok {
|
|
|
|
return fmt.Errorf("internal failure while fixing inconsistent bitsequence: %v", err)
|
|
|
|
}
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2016-10-31 22:26:14 -06:00
|
|
|
logrus.Infof("Fixed inconsistent bit sequence in datastore:\n%s\n%s", h, nh)
|
2016-01-11 13:03:52 -08:00
|
|
|
|
2023-01-20 13:54:26 -05:00
|
|
|
h.mu.Lock()
|
2023-01-20 13:51:15 -05:00
|
|
|
h.bm = nh.bm
|
2023-01-20 13:54:26 -05:00
|
|
|
h.mu.Unlock()
|
2016-01-11 13:03:52 -08:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-24 12:10:54 -07:00
|
|
|
// set/reset the bit
|
2023-01-20 13:51:15 -05:00
|
|
|
func (h *Handle) apply(op func(*bitmap.Bitmap) (uint64, error)) (uint64, error) {
|
2015-06-24 12:10:54 -07:00
|
|
|
for {
|
2015-11-30 13:18:52 -08:00
|
|
|
var store datastore.DataStore
|
2023-01-20 13:54:26 -05:00
|
|
|
h.mu.Lock()
|
2015-11-30 13:18:52 -08:00
|
|
|
store = h.store
|
|
|
|
if store != nil {
|
2023-01-20 13:54:26 -05:00
|
|
|
h.mu.Unlock() // The lock is acquired in the GetObject
|
2015-11-30 13:18:52 -08:00
|
|
|
if err := store.GetObject(datastore.Key(h.Key()...), h); err != nil && err != datastore.ErrKeyNotFound {
|
2023-01-20 13:51:15 -05:00
|
|
|
return 0, err
|
2015-10-05 04:24:44 -07:00
|
|
|
}
|
2023-01-20 13:54:26 -05:00
|
|
|
h.mu.Lock() // Acquire the lock back
|
2015-10-05 04:24:44 -07:00
|
|
|
}
|
2015-06-24 12:10:54 -07:00
|
|
|
|
2015-09-04 18:15:54 -07:00
|
|
|
// Create a private copy of h and work on it
|
2015-06-24 12:10:54 -07:00
|
|
|
nh := h.getCopy()
|
|
|
|
|
2023-01-20 13:51:15 -05:00
|
|
|
ret, err := op(nh.bm)
|
|
|
|
if err != nil {
|
2023-01-20 13:54:26 -05:00
|
|
|
h.mu.Unlock()
|
2023-01-20 13:51:15 -05:00
|
|
|
return ret, err
|
2015-06-24 12:10:54 -07:00
|
|
|
}
|
|
|
|
|
2018-03-08 10:34:40 -08:00
|
|
|
if h.store != nil {
|
2023-01-20 13:54:26 -05:00
|
|
|
h.mu.Unlock()
|
2018-03-08 10:34:40 -08:00
|
|
|
// 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
|
2015-06-24 12:10:54 -07:00
|
|
|
}
|
2023-01-20 13:54:26 -05:00
|
|
|
h.mu.Lock()
|
2015-06-24 12:10:54 -07:00
|
|
|
}
|
|
|
|
|
2017-05-22 02:25:52 +00:00
|
|
|
// Previous atomic push was successful. Save private copy to local copy
|
2023-01-20 13:51:15 -05:00
|
|
|
h.bm = nh.bm
|
2015-06-24 12:10:54 -07:00
|
|
|
h.dbExists = nh.dbExists
|
|
|
|
h.dbIndex = nh.dbIndex
|
2023-01-20 13:54:26 -05:00
|
|
|
h.mu.Unlock()
|
2015-06-24 12:10:54 -07:00
|
|
|
return ret, nil
|
2015-06-15 18:28:00 -07:00
|
|
|
}
|
2015-06-24 12:10:54 -07:00
|
|
|
}
|
2015-06-15 18:28:00 -07:00
|
|
|
|
2015-06-16 14:46:51 -07:00
|
|
|
// Destroy removes from the datastore the data belonging to this handle
|
2015-09-22 13:20:55 -07:00
|
|
|
func (h *Handle) Destroy() error {
|
2015-10-03 16:11:50 -07:00
|
|
|
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
|
|
|
|
}
|
2015-06-16 14:46:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Bits returns the length of the bit sequence
|
2015-10-08 20:04:13 -07:00
|
|
|
func (h *Handle) Bits() uint64 {
|
2023-01-20 13:54:26 -05:00
|
|
|
h.mu.Lock()
|
|
|
|
defer h.mu.Unlock()
|
2023-01-20 13:51:15 -05:00
|
|
|
return h.bm.Bits()
|
2015-06-16 14:46:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Unselected returns the number of bits which are not selected
|
2015-10-08 20:04:13 -07:00
|
|
|
func (h *Handle) Unselected() uint64 {
|
2023-01-20 13:54:26 -05:00
|
|
|
h.mu.Lock()
|
|
|
|
defer h.mu.Unlock()
|
2023-01-20 13:51:15 -05:00
|
|
|
return h.bm.Unselected()
|
2015-06-16 14:46:51 -07:00
|
|
|
}
|
|
|
|
|
2015-06-24 15:02:08 -07:00
|
|
|
func (h *Handle) String() string {
|
2023-01-20 13:54:26 -05:00
|
|
|
h.mu.Lock()
|
|
|
|
defer h.mu.Unlock()
|
2023-01-20 13:51:15 -05:00
|
|
|
return fmt.Sprintf("App: %s, ID: %s, DBIndex: 0x%x, %s",
|
|
|
|
h.app, h.id, h.dbIndex, h.bm)
|
2015-06-24 15:02:08 -07:00
|
|
|
}
|
|
|
|
|
2023-01-20 13:51:15 -05:00
|
|
|
// MarshalJSON encodes h into a JSON message.
|
2015-10-05 14:53:25 -07:00
|
|
|
func (h *Handle) MarshalJSON() ([]byte, error) {
|
|
|
|
m := map[string]interface{}{
|
|
|
|
"id": h.id,
|
|
|
|
}
|
|
|
|
|
2023-01-20 13:51:15 -05:00
|
|
|
b, err := func() ([]byte, error) {
|
2023-01-20 13:54:26 -05:00
|
|
|
h.mu.Lock()
|
|
|
|
defer h.mu.Unlock()
|
2023-01-20 13:51:15 -05:00
|
|
|
return h.bm.MarshalBinary()
|
|
|
|
}()
|
2015-10-05 14:53:25 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
m["sequence"] = b
|
|
|
|
return json.Marshal(m)
|
|
|
|
}
|
|
|
|
|
2023-01-20 13:51:15 -05:00
|
|
|
// UnmarshalJSON decodes a JSON message into h.
|
2015-10-05 14:53:25 -07:00
|
|
|
func (h *Handle) UnmarshalJSON(data []byte) error {
|
|
|
|
var (
|
|
|
|
m map[string]interface{}
|
|
|
|
b []byte
|
|
|
|
err error
|
|
|
|
)
|
|
|
|
if err = json.Unmarshal(data, &m); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
h.id = m["id"].(string)
|
|
|
|
bi, _ := json.Marshal(m["sequence"])
|
|
|
|
if err := json.Unmarshal(bi, &b); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2015-06-12 12:03:33 -07:00
|
|
|
|
2023-01-20 13:54:26 -05:00
|
|
|
h.mu.Lock()
|
|
|
|
defer h.mu.Unlock()
|
2023-01-20 13:51:15 -05:00
|
|
|
if err := h.bm.UnmarshalBinary(b); err != nil {
|
|
|
|
return err
|
2015-06-12 12:03:33 -07:00
|
|
|
}
|
2023-01-20 13:51:15 -05:00
|
|
|
return nil
|
2015-06-24 12:10:54 -07:00
|
|
|
}
|