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 }