github.com/adityamillind98/moby@v23.0.0-rc.4+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 h.Lock() 414 defer h.Unlock() 415 ba := make([]byte, 16) 416 binary.BigEndian.PutUint64(ba[0:], h.bits) 417 binary.BigEndian.PutUint64(ba[8:], h.unselected) 418 bm, err := h.head.toByteArray() 419 if err != nil { 420 return nil, fmt.Errorf("failed to serialize head: %s", err.Error()) 421 } 422 ba = append(ba, bm...) 423 424 return ba, nil 425 } 426 427 // FromByteArray reads his handle's data from a byte array 428 func (h *Handle) FromByteArray(ba []byte) error { 429 if ba == nil { 430 return errors.New("nil byte array") 431 } 432 433 nh := &sequence{} 434 err := nh.fromByteArray(ba[16:]) 435 if err != nil { 436 return fmt.Errorf("failed to deserialize head: %s", err.Error()) 437 } 438 439 h.Lock() 440 h.head = nh 441 h.bits = binary.BigEndian.Uint64(ba[0:8]) 442 h.unselected = binary.BigEndian.Uint64(ba[8:16]) 443 h.Unlock() 444 445 return nil 446 } 447 448 // Bits returns the length of the bit sequence 449 func (h *Handle) Bits() uint64 { 450 return h.bits 451 } 452 453 // Unselected returns the number of bits which are not selected 454 func (h *Handle) Unselected() uint64 { 455 h.Lock() 456 defer h.Unlock() 457 return h.unselected 458 } 459 460 func (h *Handle) String() string { 461 h.Lock() 462 defer h.Unlock() 463 return fmt.Sprintf("App: %s, ID: %s, DBIndex: 0x%x, Bits: %d, Unselected: %d, Sequence: %s Curr:%d", 464 h.app, h.id, h.dbIndex, h.bits, h.unselected, h.head.toString(), h.curr) 465 } 466 467 // MarshalJSON encodes Handle into json message 468 func (h *Handle) MarshalJSON() ([]byte, error) { 469 m := map[string]interface{}{ 470 "id": h.id, 471 } 472 473 b, err := h.ToByteArray() 474 if err != nil { 475 return nil, err 476 } 477 m["sequence"] = b 478 return json.Marshal(m) 479 } 480 481 // UnmarshalJSON decodes json message into Handle 482 func (h *Handle) UnmarshalJSON(data []byte) error { 483 var ( 484 m map[string]interface{} 485 b []byte 486 err error 487 ) 488 if err = json.Unmarshal(data, &m); err != nil { 489 return err 490 } 491 h.id = m["id"].(string) 492 bi, _ := json.Marshal(m["sequence"]) 493 if err := json.Unmarshal(bi, &b); err != nil { 494 return err 495 } 496 return h.FromByteArray(b) 497 } 498 499 // getFirstAvailable looks for the first unset bit in passed mask starting from start 500 func getFirstAvailable(head *sequence, start uint64) (uint64, uint64, error) { 501 // Find sequence which contains the start bit 502 byteStart, bitStart := ordinalToPos(start) 503 current, _, precBlocks, inBlockBytePos := findSequence(head, byteStart) 504 // Derive the this sequence offsets 505 byteOffset := byteStart - inBlockBytePos 506 bitOffset := inBlockBytePos*8 + bitStart 507 for current != nil { 508 if current.block != blockMAX { 509 // If the current block is not full, check if there is any bit 510 // from the current bit in the current block. If not, before proceeding to the 511 // next block node, make sure we check for available bit in the next 512 // instance of the same block. Due to RLE same block signature will be 513 // compressed. 514 retry: 515 bytePos, bitPos, err := current.getAvailableBit(bitOffset) 516 if err != nil && precBlocks == current.count-1 { 517 // This is the last instance in the same block node, 518 // so move to the next block. 519 goto next 520 } 521 if err != nil { 522 // There are some more instances of the same block, so add the offset 523 // and be optimistic that you will find the available bit in the next 524 // instance of the same block. 525 bitOffset = 0 526 byteOffset += blockBytes 527 precBlocks++ 528 goto retry 529 } 530 return byteOffset + bytePos, bitPos, err 531 } 532 // Moving to next block: Reset bit offset. 533 next: 534 bitOffset = 0 535 byteOffset += (current.count * blockBytes) - (precBlocks * blockBytes) 536 precBlocks = 0 537 current = current.next 538 } 539 return invalidPos, invalidPos, ErrNoBitAvailable 540 } 541 542 // getAvailableFromCurrent will look for available ordinal from the current ordinal. 543 // If none found then it will loop back to the start to check of the available bit. 544 // This can be further optimized to check from start till curr in case of a rollover 545 func getAvailableFromCurrent(head *sequence, start, curr, end uint64) (uint64, uint64, error) { 546 var bytePos, bitPos uint64 547 var err error 548 if curr != 0 && curr > start { 549 bytePos, bitPos, err = getFirstAvailable(head, curr) 550 ret := posToOrdinal(bytePos, bitPos) 551 if end < ret || err != nil { 552 goto begin 553 } 554 return bytePos, bitPos, nil 555 } 556 557 begin: 558 bytePos, bitPos, err = getFirstAvailable(head, start) 559 ret := posToOrdinal(bytePos, bitPos) 560 if end < ret || err != nil { 561 return invalidPos, invalidPos, ErrNoBitAvailable 562 } 563 return bytePos, bitPos, nil 564 } 565 566 // checkIfAvailable checks if the bit correspondent to the specified ordinal is unset 567 // If the ordinal is beyond the sequence limits, a negative response is returned 568 func checkIfAvailable(head *sequence, ordinal uint64) (uint64, uint64, error) { 569 bytePos, bitPos := ordinalToPos(ordinal) 570 571 // Find the sequence containing this byte 572 current, _, _, inBlockBytePos := findSequence(head, bytePos) 573 if current != nil { 574 // Check whether the bit corresponding to the ordinal address is unset 575 bitSel := blockFirstBit >> (inBlockBytePos*8 + bitPos) 576 if current.block&bitSel == 0 { 577 return bytePos, bitPos, nil 578 } 579 } 580 581 return invalidPos, invalidPos, ErrBitAllocated 582 } 583 584 // Given the byte position and the sequences list head, return the pointer to the 585 // sequence containing the byte (current), the pointer to the previous sequence, 586 // the number of blocks preceding the block containing the byte inside the current sequence. 587 // If bytePos is outside of the list, function will return (nil, nil, 0, invalidPos) 588 func findSequence(head *sequence, bytePos uint64) (*sequence, *sequence, uint64, uint64) { 589 // Find the sequence containing this byte 590 previous := head 591 current := head 592 n := bytePos 593 for current.next != nil && n >= (current.count*blockBytes) { // Nil check for less than 32 addresses masks 594 n -= (current.count * blockBytes) 595 previous = current 596 current = current.next 597 } 598 599 // If byte is outside of the list, let caller know 600 if n >= (current.count * blockBytes) { 601 return nil, nil, 0, invalidPos 602 } 603 604 // Find the byte position inside the block and the number of blocks 605 // preceding the block containing the byte inside this sequence 606 precBlocks := n / blockBytes 607 inBlockBytePos := bytePos % blockBytes 608 609 return current, previous, precBlocks, inBlockBytePos 610 } 611 612 // PushReservation pushes the bit reservation inside the bitmask. 613 // Given byte and bit positions, identify the sequence (current) which holds the block containing the affected bit. 614 // Create a new block with the modified bit according to the operation (allocate/release). 615 // Create a new sequence containing the new block and insert it in the proper position. 616 // Remove current sequence if empty. 617 // Check if new sequence can be merged with neighbour (previous/next) sequences. 618 // 619 // Identify "current" sequence containing block: 620 // 621 // [prev seq] [current seq] [next seq] 622 // 623 // Based on block position, resulting list of sequences can be any of three forms: 624 // 625 // block position Resulting list of sequences 626 // 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 }