MCPcopy Index your code
hub / github.com/aws/aws-cli / SlidingWindowSemaphore

Class SlidingWindowSemaphore

awscli/s3transfer/utils.py:654–749  ·  view source on GitHub ↗

A semaphore used to coordinate sequential resource access. This class is similar to the stdlib BoundedSemaphore: * It's initialized with a count. * Each call to ``acquire()`` decrements the counter. * If the count is at zero, then ``acquire()`` will either block until the cou

Source from the content-addressed store, hash-verified

652
653
654class SlidingWindowSemaphore(TaskSemaphore):
655 """A semaphore used to coordinate sequential resource access.
656
657 This class is similar to the stdlib BoundedSemaphore:
658
659 * It's initialized with a count.
660 * Each call to ``acquire()`` decrements the counter.
661 * If the count is at zero, then ``acquire()`` will either block until the
662 count increases, or if ``blocking=False``, then it will raise
663 a NoResourcesAvailable exception indicating that it failed to acquire the
664 semaphore.
665
666 The main difference is that this semaphore is used to limit
667 access to a resource that requires sequential access. For example,
668 if I want to access resource R that has 20 subresources R_0 - R_19,
669 this semaphore can also enforce that you only have a max range of
670 10 at any given point in time. You must also specify a tag name
671 when you acquire the semaphore. The sliding window semantics apply
672 on a per tag basis. The internal count will only be incremented
673 when the minimum sequence number for a tag is released.
674
675 """
676
677 def __init__(self, count):
678 self._count = count
679 # Dict[tag, next_sequence_number].
680 self._tag_sequences = defaultdict(int)
681 self._lowest_sequence = {}
682 self._lock = threading.Lock()
683 self._condition = threading.Condition(self._lock)
684 # Dict[tag, List[sequence_number]]
685 self._pending_release = {}
686
687 def current_count(self):
688 with self._lock:
689 return self._count
690
691 def acquire(self, tag, blocking=True):
692 logger.debug("Acquiring %s", tag)
693 self._condition.acquire()
694 try:
695 if self._count == 0:
696 if not blocking:
697 raise NoResourcesAvailable(f"Cannot acquire tag '{tag}'")
698 else:
699 while self._count == 0:
700 self._condition.wait()
701 # self._count is no longer zero.
702 # First, check if this is the first time we're seeing this tag.
703 sequence_number = self._tag_sequences[tag]
704 if sequence_number == 0:
705 # First time seeing the tag, so record we're at 0.
706 self._lowest_sequence[tag] = sequence_number
707 self._tag_sequences[tag] += 1
708 self._count -= 1
709 return sequence_number
710 finally:
711 self._condition.release()

Calls

no outgoing calls