github.com/docker/engine@v22.0.0-20211208180946-d456264580cf+incompatible/libnetwork/bitseq/sequence.go (about) 1 // Package bitseq provides a structure and utilities for representing long bitmask 2 // as sequence of run-length encoded blocks. It operates directly on the encoded 3 // representation, it does not decode/encode. 4 package bitseq 5 6 import ( 7 "encoding/binary" 8 "encoding/json" 9 "errors" 10 "fmt" 11 "sync" 12 13 "github.com/docker/docker/libnetwork/datastore" 14 "github.com/docker/docker/libnetwork/types" 15 "github.com/sirupsen/logrus" 16 ) 17 18 // block sequence constants 19 // If needed we can think of making these configurable 20 const ( 21 blockLen = uint32(32) 22 blockBytes = uint64(blockLen / 8) 23 blockMAX = uint32(1<<blockLen - 1) 24 blockFirstBit = uint32(1) << (blockLen - 1) 25 invalidPos = uint64(0xFFFFFFFFFFFFFFFF) 26 ) 27 28 var ( 29 // ErrNoBitAvailable is returned when no more bits are available to set 30 ErrNoBitAvailable = errors.New("no bit available") 31 // ErrBitAllocated is returned when the specific bit requested is already set 32 ErrBitAllocated = errors.New("requested bit is already allocated") 33 ) 34 35 // Handle contains the sequence representing the bitmask and its identifier 36 type Handle struct { 37 bits uint64 38 unselected uint64 39 head *sequence 40 app string 41 id string 42 dbIndex uint64 43 dbExists bool 44 curr uint64 45 store datastore.DataStore 46 sync.Mutex 47 } 48 49 // NewHandle returns a thread-safe instance of the bitmask handler 50 func NewHandle(app string, ds datastore.DataStore, id string, numElements uint64) (*Handle, error) { 51 h := &Handle{ 52 app: app, 53 id: id, 54 store: ds, 55 bits: numElements, 56 unselected: numElements, 57 head: &sequence{ 58 block: 0x0, 59 count: getNumBlocks(numElements), 60 }, 61 } 62 63 if h.store == nil { 64 return h, nil 65 } 66 67 // Get the initial status from the ds if present. 68 if err := h.store.GetObject(datastore.Key(h.Key()...), h); err != nil && err != datastore.ErrKeyNotFound { 69 return nil, err 70 } 71 72 // If the handle is not in store, write it. 73 if !h.Exists() { 74 if err := h.writeToStore(); err != nil { 75 return nil, fmt.Errorf("failed to write bitsequence to store: %v", err) 76 } 77 } 78 79 return h, nil 80 } 81 82 // sequence represents a recurring sequence of 32 bits long bitmasks 83 type sequence struct { 84 block uint32 // block is a symbol representing 4 byte long allocation bitmask 85 count uint64 // number of consecutive blocks (symbols) 86 next *sequence // next sequence 87 } 88 89 // String returns a string representation of the block sequence starting from this block 90 func (s *sequence) toString() string { 91 var nextBlock string 92 if s.next == nil { 93 nextBlock = "end" 94 } else { 95 nextBlock = s.next.toString() 96 } 97 return fmt.Sprintf("(0x%x, %d)->%s", s.block, s.count, nextBlock) 98 } 99 100 // GetAvailableBit returns the position of the first unset bit in the bitmask represented by this sequence 101 func (s *sequence) getAvailableBit(from uint64) (uint64, uint64, error) { 102 if s.block == blockMAX || s.count == 0 { 103 return invalidPos, invalidPos, ErrNoBitAvailable 104 } 105 bits := from 106 bitSel := blockFirstBit >> from 107 for bitSel > 0 && s.block&bitSel != 0 { 108 bitSel >>= 1 109 bits++ 110 } 111 // Check if the loop exited because it could not 112 // find any available bit int block starting from 113 // "from". Return invalid pos in that case. 114 if bitSel == 0 { 115 return invalidPos, invalidPos, ErrNoBitAvailable 116 } 117 return bits / 8, bits % 8, nil 118 } 119 120 // GetCopy returns a copy of the linked list rooted at this node 121 func (s *sequence) getCopy() *sequence { 122 n := &sequence{block: s.block, count: s.count} 123 pn := n 124 ps := s.next 125 for ps != nil { 126 pn.next = &sequence{block: ps.block, count: ps.count} 127 pn = pn.next 128 ps = ps.next 129 } 130 return n 131 } 132 133 // Equal checks if this sequence is equal to the passed one 134 func (s *sequence) equal(o *sequence) bool { 135 this := s 136 other := o 137 for this != nil { 138 if other == nil { 139 return false 140 } 141 if this.block != other.block || this.count != other.count { 142 return false 143 } 144 this = this.next 145 other = other.next 146 } 147 return other == nil 148 } 149 150 // ToByteArray converts the sequence into a byte array 151 func (s *sequence) toByteArray() ([]byte, error) { 152 var bb []byte 153 154 p := s 155 for p != nil { 156 b := make([]byte, 12) 157 binary.BigEndian.PutUint32(b[0:], p.block) 158 binary.BigEndian.PutUint64(b[4:], p.count) 159 bb = append(bb, b...) 160 p = p.next 161 } 162 163 return bb, nil 164 } 165 166 // fromByteArray construct the sequence from the byte array 167 func (s *sequence) fromByteArray(data []byte) error { 168 l := len(data) 169 if l%12 != 0 { 170 return fmt.Errorf("cannot deserialize byte sequence of length %d (%v)", l, data) 171 } 172 173 p := s 174 i := 0 175 for { 176 p.block = binary.BigEndian.Uint32(data[i : i+4]) 177 p.count = binary.BigEndian.Uint64(data[i+4 : i+12]) 178 i += 12 179 if i == l { 180 break 181 } 182 p.next = &sequence{} 183 p = p.next 184 } 185 186 return nil 187 } 188 189 func (h *Handle) getCopy() *Handle { 190 return &Handle{ 191 bits: h.bits, 192 unselected: h.unselected, 193 head: h.head.getCopy(), 194 app: h.app, 195 id: h.id, 196 dbIndex: h.dbIndex, 197 dbExists: h.dbExists, 198 store: h.store, 199 curr: h.curr, 200 } 201 } 202 203 // SetAnyInRange atomically sets the first unset bit in the specified range in the sequence and returns the corresponding ordinal 204 func (h *Handle) SetAnyInRange(start, end uint64, serial bool) (uint64, error) { 205 if end < start || end >= h.bits { 206 return invalidPos, fmt.Errorf("invalid bit range [%d, %d]", start, end) 207 } 208 if h.Unselected() == 0 { 209 return invalidPos, ErrNoBitAvailable 210 } 211 return h.set(0, start, end, true, false, serial) 212 } 213 214 // SetAny atomically sets the first unset bit in the sequence and returns the corresponding ordinal 215 func (h *Handle) SetAny(serial bool) (uint64, error) { 216 if h.Unselected() == 0 { 217 return invalidPos, ErrNoBitAvailable 218 } 219 return h.set(0, 0, h.bits-1, true, false, serial) 220 } 221 222 // Set atomically sets the corresponding bit in the sequence 223 func (h *Handle) Set(ordinal uint64) error { 224 if err := h.validateOrdinal(ordinal); err != nil { 225 return err 226 } 227 _, err := h.set(ordinal, 0, 0, false, false, false) 228 return err 229 } 230 231 // Unset atomically unsets the corresponding bit in the sequence 232 func (h *Handle) Unset(ordinal uint64) error { 233 if err := h.validateOrdinal(ordinal); err != nil { 234 return err 235 } 236 _, err := h.set(ordinal, 0, 0, false, true, false) 237 return err 238 } 239 240 // IsSet atomically checks if the ordinal bit is set. In case ordinal 241 // is outside of the bit sequence limits, false is returned. 242 func (h *Handle) IsSet(ordinal uint64) bool { 243 if err := h.validateOrdinal(ordinal); err != nil { 244 return false 245 } 246 h.Lock() 247 _, _, err := checkIfAvailable(h.head, ordinal) 248 h.Unlock() 249 return err != nil 250 } 251 252 func (h *Handle) runConsistencyCheck() bool { 253 corrupted := false 254 for p, c := h.head, h.head.next; c != nil; c = c.next { 255 if c.count == 0 { 256 corrupted = true 257 p.next = c.next 258 continue // keep same p 259 } 260 p = c 261 } 262 return corrupted 263 } 264 265 // CheckConsistency checks if the bit sequence is in an inconsistent state and attempts to fix it. 266 // It looks for a corruption signature that may happen in docker 1.9.0 and 1.9.1. 267 func (h *Handle) CheckConsistency() error { 268 for { 269 h.Lock() 270 store := h.store 271 h.Unlock() 272 273 if store != nil { 274 if err := store.GetObject(datastore.Key(h.Key()...), h); err != nil && err != datastore.ErrKeyNotFound { 275 return err 276 } 277 } 278 279 h.Lock() 280 nh := h.getCopy() 281 h.Unlock() 282 283 if !nh.runConsistencyCheck() { 284 return nil 285 } 286 287 if err := nh.writeToStore(); err != nil { 288 if _, ok := err.(types.RetryError); !ok { 289 return fmt.Errorf("internal failure while fixing inconsistent bitsequence: %v", err) 290 } 291 continue 292 } 293 294 logrus.Infof("Fixed inconsistent bit sequence in datastore:\n%s\n%s", h, nh) 295 296 h.Lock() 297 h.head = nh.head 298 h.Unlock() 299 300 return nil 301 } 302 } 303 304 // set/reset the bit 305 func (h *Handle) set(ordinal, start, end uint64, any bool, release bool, serial bool) (uint64, error) { 306 var ( 307 bitPos uint64 308 bytePos uint64 309 ret uint64 310 err error 311 ) 312 313 for { 314 var store datastore.DataStore 315 curr := uint64(0) 316 h.Lock() 317 store = h.store 318 if store != nil { 319 h.Unlock() // The lock is acquired in the GetObject 320 if err := store.GetObject(datastore.Key(h.Key()...), h); err != nil && err != datastore.ErrKeyNotFound { 321 return ret, err 322 } 323 h.Lock() // Acquire the lock back 324 } 325 if serial { 326 curr = h.curr 327 } 328 // Get position if available 329 if release { 330 bytePos, bitPos = ordinalToPos(ordinal) 331 } else { 332 if any { 333 bytePos, bitPos, err = getAvailableFromCurrent(h.head, start, curr, end) 334 ret = posToOrdinal(bytePos, bitPos) 335 if err == nil { 336 h.curr = ret + 1 337 } 338 } else { 339 bytePos, bitPos, err = checkIfAvailable(h.head, ordinal) 340 ret = ordinal 341 } 342 } 343 if err != nil { 344 h.Unlock() 345 return ret, err 346 } 347 348 // Create a private copy of h and work on it 349 nh := h.getCopy() 350 351 nh.head = pushReservation(bytePos, bitPos, nh.head, release) 352 if release { 353 nh.unselected++ 354 } else { 355 nh.unselected-- 356 } 357 358 if h.store != nil { 359 h.Unlock() 360 // Attempt to write private copy to store 361 if err := nh.writeToStore(); err != nil { 362 if _, ok := err.(types.RetryError); !ok { 363 return ret, fmt.Errorf("internal failure while setting the bit: %v", err) 364 } 365 // Retry 366 continue 367 } 368 h.Lock() 369 } 370 371 // Previous atomic push was successful. Save private copy to local copy 372 h.unselected = nh.unselected 373 h.head = nh.head 374 h.dbExists = nh.dbExists 375 h.dbIndex = nh.dbIndex 376 h.Unlock() 377 return ret, nil 378 } 379 } 380 381 // checks is needed because to cover the case where the number of bits is not a multiple of blockLen 382 func (h *Handle) validateOrdinal(ordinal uint64) error { 383 h.Lock() 384 defer h.Unlock() 385 if ordinal >= h.bits { 386 return errors.New("bit does not belong to the sequence") 387 } 388 return nil 389 } 390 391 // Destroy removes from the datastore the data belonging to this handle 392 func (h *Handle) Destroy() error { 393 for { 394 if err := h.deleteFromStore(); err != nil { 395 if _, ok := err.(types.RetryError); !ok { 396 return fmt.Errorf("internal failure while destroying the sequence: %v", err) 397 } 398 // Fetch latest 399 if err := h.store.GetObject(datastore.Key(h.Key()...), h); err != nil { 400 if err == datastore.ErrKeyNotFound { // already removed 401 return nil 402 } 403 return fmt.Errorf("failed to fetch from store when destroying the sequence: %v", err) 404 } 405 continue 406 } 407 return nil 408 } 409 } 410 411 // ToByteArray converts this handle's data into a byte array 412 func (h *Handle) ToByteArray() ([]byte, error) { 413 414 h.Lock() 415 defer h.Unlock() 416 ba := make([]byte, 16) 417 binary.BigEndian.PutUint64(ba[0:], h.bits) 418 binary.BigEndian.PutUint64(ba[8:], h.unselected) 419 bm, err := h.head.toByteArray() 420 if err != nil { 421 return nil, fmt.Errorf("failed to serialize head: %s", err.Error()) 422 } 423 ba = append(ba, bm...) 424 425 return ba, nil 426 } 427 428 // FromByteArray reads his handle's data from a byte array 429 func (h *Handle) FromByteArray(ba []byte) error { 430 if ba == nil { 431 return errors.New("nil byte array") 432 } 433 434 nh := &sequence{} 435 err := nh.fromByteArray(ba[16:]) 436 if err != nil { 437 return fmt.Errorf("failed to deserialize head: %s", err.Error()) 438 } 439 440 h.Lock() 441 h.head = nh 442 h.bits = binary.BigEndian.Uint64(ba[0:8]) 443 h.unselected = binary.BigEndian.Uint64(ba[8:16]) 444 h.Unlock() 445 446 return nil 447 } 448 449 // Bits returns the length of the bit sequence 450 func (h *Handle) Bits() uint64 { 451 return h.bits 452 } 453 454 // Unselected returns the number of bits which are not selected 455 func (h *Handle) Unselected() uint64 { 456 h.Lock() 457 defer h.Unlock() 458 return h.unselected 459 } 460 461 func (h *Handle) String() string { 462 h.Lock() 463 defer h.Unlock() 464 return fmt.Sprintf("App: %s, ID: %s, DBIndex: 0x%x, Bits: %d, Unselected: %d, Sequence: %s Curr:%d", 465 h.app, h.id, h.dbIndex, h.bits, h.unselected, h.head.toString(), h.curr) 466 } 467 468 // MarshalJSON encodes Handle into json message 469 func (h *Handle) MarshalJSON() ([]byte, error) { 470 m := map[string]interface{}{ 471 "id": h.id, 472 } 473 474 b, err := h.ToByteArray() 475 if err != nil { 476 return nil, err 477 } 478 m["sequence"] = b 479 return json.Marshal(m) 480 } 481 482 // UnmarshalJSON decodes json message into Handle 483 func (h *Handle) UnmarshalJSON(data []byte) error { 484 var ( 485 m map[string]interface{} 486 b []byte 487 err error 488 ) 489 if err = json.Unmarshal(data, &m); err != nil { 490 return err 491 } 492 h.id = m["id"].(string) 493 bi, _ := json.Marshal(m["sequence"]) 494 if err := json.Unmarshal(bi, &b); err != nil { 495 return err 496 } 497 return h.FromByteArray(b) 498 } 499 500 // getFirstAvailable looks for the first unset bit in passed mask starting from start 501 func getFirstAvailable(head *sequence, start uint64) (uint64, uint64, error) { 502 // Find sequence which contains the start bit 503 byteStart, bitStart := ordinalToPos(start) 504 current, _, precBlocks, inBlockBytePos := findSequence(head, byteStart) 505 // Derive the this sequence offsets 506 byteOffset := byteStart - inBlockBytePos 507 bitOffset := inBlockBytePos*8 + bitStart 508 for current != nil { 509 if current.block != blockMAX { 510 // If the current block is not full, check if there is any bit 511 // from the current bit in the current block. If not, before proceeding to the 512 // next block node, make sure we check for available bit in the next 513 // instance of the same block. Due to RLE same block signature will be 514 // compressed. 515 retry: 516 bytePos, bitPos, err := current.getAvailableBit(bitOffset) 517 if err != nil && precBlocks == current.count-1 { 518 // This is the last instance in the same block node, 519 // so move to the next block. 520 goto next 521 } 522 if err != nil { 523 // There are some more instances of the same block, so add the offset 524 // and be optimistic that you will find the available bit in the next 525 // instance of the same block. 526 bitOffset = 0 527 byteOffset += blockBytes 528 precBlocks++ 529 goto retry 530 } 531 return byteOffset + bytePos, bitPos, err 532 } 533 // Moving to next block: Reset bit offset. 534 next: 535 bitOffset = 0 536 byteOffset += (current.count * blockBytes) - (precBlocks * blockBytes) 537 precBlocks = 0 538 current = current.next 539 } 540 return invalidPos, invalidPos, ErrNoBitAvailable 541 } 542 543 // getAvailableFromCurrent will look for available ordinal from the current ordinal. 544 // If none found then it will loop back to the start to check of the available bit. 545 // This can be further optimized to check from start till curr in case of a rollover 546 func getAvailableFromCurrent(head *sequence, start, curr, end uint64) (uint64, uint64, error) { 547 var bytePos, bitPos uint64 548 var err error 549 if curr != 0 && curr > start { 550 bytePos, bitPos, err = getFirstAvailable(head, curr) 551 ret := posToOrdinal(bytePos, bitPos) 552 if end < ret || err != nil { 553 goto begin 554 } 555 return bytePos, bitPos, nil 556 } 557 558 begin: 559 bytePos, bitPos, err = getFirstAvailable(head, start) 560 ret := posToOrdinal(bytePos, bitPos) 561 if end < ret || err != nil { 562 return invalidPos, invalidPos, ErrNoBitAvailable 563 } 564 return bytePos, bitPos, nil 565 } 566 567 // checkIfAvailable checks if the bit correspondent to the specified ordinal is unset 568 // If the ordinal is beyond the sequence limits, a negative response is returned 569 func checkIfAvailable(head *sequence, ordinal uint64) (uint64, uint64, error) { 570 bytePos, bitPos := ordinalToPos(ordinal) 571 572 // Find the sequence containing this byte 573 current, _, _, inBlockBytePos := findSequence(head, bytePos) 574 if current != nil { 575 // Check whether the bit corresponding to the ordinal address is unset 576 bitSel := blockFirstBit >> (inBlockBytePos*8 + bitPos) 577 if current.block&bitSel == 0 { 578 return bytePos, bitPos, nil 579 } 580 } 581 582 return invalidPos, invalidPos, ErrBitAllocated 583 } 584 585 // Given the byte position and the sequences list head, return the pointer to the 586 // sequence containing the byte (current), the pointer to the previous sequence, 587 // the number of blocks preceding the block containing the byte inside the current sequence. 588 // If bytePos is outside of the list, function will return (nil, nil, 0, invalidPos) 589 func findSequence(head *sequence, bytePos uint64) (*sequence, *sequence, uint64, uint64) { 590 // Find the sequence containing this byte 591 previous := head 592 current := head 593 n := bytePos 594 for current.next != nil && n >= (current.count*blockBytes) { // Nil check for less than 32 addresses masks 595 n -= (current.count * blockBytes) 596 previous = current 597 current = current.next 598 } 599 600 // If byte is outside of the list, let caller know 601 if n >= (current.count * blockBytes) { 602 return nil, nil, 0, invalidPos 603 } 604 605 // Find the byte position inside the block and the number of blocks 606 // preceding the block containing the byte inside this sequence 607 precBlocks := n / blockBytes 608 inBlockBytePos := bytePos % blockBytes 609 610 return current, previous, precBlocks, inBlockBytePos 611 } 612 613 // PushReservation pushes the bit reservation inside the bitmask. 614 // Given byte and bit positions, identify the sequence (current) which holds the block containing the affected bit. 615 // Create a new block with the modified bit according to the operation (allocate/release). 616 // Create a new sequence containing the new block and insert it in the proper position. 617 // Remove current sequence if empty. 618 // Check if new sequence can be merged with neighbour (previous/next) sequences. 619 // 620 // 621 // Identify "current" sequence containing block: 622 // [prev seq] [current seq] [next seq] 623 // 624 // Based on block position, resulting list of sequences can be any of three forms: 625 // 626 // block position Resulting list of sequences 627 // A) block is first in current: [prev seq] [new] [modified current seq] [next seq] 628 // B) block is last in current: [prev seq] [modified current seq] [new] [next seq] 629 // C) block is in the middle of current: [prev seq] [curr pre] [new] [curr post] [next seq] 630 func pushReservation(bytePos, bitPos uint64, head *sequence, release bool) *sequence { 631 // Store list's head 632 newHead := head 633 634 // Find the sequence containing this byte 635 current, previous, precBlocks, inBlockBytePos := findSequence(head, bytePos) 636 if current == nil { 637 return newHead 638 } 639 640 // Construct updated block 641 bitSel := blockFirstBit >> (inBlockBytePos*8 + bitPos) 642 newBlock := current.block 643 if release { 644 newBlock &^= bitSel 645 } else { 646 newBlock |= bitSel 647 } 648 649 // Quit if it was a redundant request 650 if current.block == newBlock { 651 return newHead 652 } 653 654 // Current sequence inevitably looses one block, upadate count 655 current.count-- 656 657 // Create new sequence 658 newSequence := &sequence{block: newBlock, count: 1} 659 660 // Insert the new sequence in the list based on block position 661 if precBlocks == 0 { // First in sequence (A) 662 newSequence.next = current 663 if current == head { 664 newHead = newSequence 665 previous = newHead 666 } else { 667 previous.next = newSequence 668 } 669 removeCurrentIfEmpty(&newHead, newSequence, current) 670 mergeSequences(previous) 671 } else if precBlocks == current.count { // Last in sequence (B) 672 newSequence.next = current.next 673 current.next = newSequence 674 mergeSequences(current) 675 } else { // In between the sequence (C) 676 currPre := &sequence{block: current.block, count: precBlocks, next: newSequence} 677 currPost := current 678 currPost.count -= precBlocks 679 newSequence.next = currPost 680 if currPost == head { 681 newHead = currPre 682 } else { 683 previous.next = currPre 684 } 685 // No merging or empty current possible here 686 } 687 688 return newHead 689 } 690 691 // Removes the current sequence from the list if empty, adjusting the head pointer if needed 692 func removeCurrentIfEmpty(head **sequence, previous, current *sequence) { 693 if current.count == 0 { 694 if current == *head { 695 *head = current.next 696 } else { 697 previous.next = current.next 698 } 699 } 700 } 701 702 // Given a pointer to a sequence, it checks if it can be merged with any following sequences 703 // It stops when no more merging is possible. 704 // TODO: Optimization: only attempt merge from start to end sequence, no need to scan till the end of the list 705 func mergeSequences(seq *sequence) { 706 if seq != nil { 707 // Merge all what possible from seq 708 for seq.next != nil && seq.block == seq.next.block { 709 seq.count += seq.next.count 710 seq.next = seq.next.next 711 } 712 // Move to next 713 mergeSequences(seq.next) 714 } 715 } 716 717 func getNumBlocks(numBits uint64) uint64 { 718 numBlocks := numBits / uint64(blockLen) 719 if numBits%uint64(blockLen) != 0 { 720 numBlocks++ 721 } 722 return numBlocks 723 } 724 725 func ordinalToPos(ordinal uint64) (uint64, uint64) { 726 return ordinal / 8, ordinal % 8 727 } 728 729 func posToOrdinal(bytePos, bitPos uint64) uint64 { 730 return bytePos*8 + bitPos 731 }