Semaphore¶
-
class
Semaphore
(context, group_id, service_name, proxy_name, object_name)¶ Bases:
hazelcast.proxy.cp.BaseCPProxy
A linearizable, distributed semaphore.
Semaphores are often used to restrict the number of callers that can access some physical or logical resource.
Semaphore is a cluster-wide counting semaphore. Conceptually, it maintains a set of permits. Each
acquire()
blocks if necessary until a permit is available, and then takes it. Dually, eachrelease()
adds a permit, potentially releasing a blocking acquirer. However, no actual permit objects are used; the semaphore just keeps a count of the number available and acts accordingly.Hazelcast’s distributed semaphore implementation guarantees that callers invoking any of the
acquire()
methods are selected to obtain permits in the order of their invocations (first-in-first-out; FIFO). Note that FIFO ordering implies the order which the primary replica of an Semaphore receives these acquire requests. Therefore, it is possible for one member to invokeacquire()
before another member, but its request hits the primary replica after the other member.This class also provides convenient ways to work with multiple permits at once. Beware of the increased risk of indefinite postponement when using the multiple-permit acquire. If permits are released one by one, a caller waiting for one permit will acquire it before a caller waiting for multiple permits regardless of the call order.
Correct usage of a semaphore is established by programming convention in the application.
It works on top of the Raft consensus algorithm. It offers linearizability during crash failures and network partitions. It is CP with respect to the CAP principle. If a network partition occurs, it remains available on at most one side of the partition.
It has 2 variations:
The default implementation accessed via
cp_subsystem
is session-aware. In this one, when a caller makes its very firstacquire()
call, it starts a new CP session with the underlying CP group. Then, liveliness of the caller is tracked via this CP session. When the caller fails, permits acquired by this caller are automatically and safely released. However, the session-aware version comes with a limitation, that is, a client cannot release permits before acquiring them first. In other words, a client can release only the permits it has acquired earlier. It means, you can acquire a permit from one thread and release it from another thread using the same Hazelcast client, but not different instances of Hazelcast client. You can use the session-aware CP Semaphore implementation by disabling JDK compatibility viajdk-compatible
server-side setting. Although the session-aware implementation has a minor difference to the JDK Semaphore, we think it is a better fit for distributed environments because of its safe auto-cleanup mechanism for acquired permits.The second implementation offered by
cp_subsystem
is sessionless. This implementation does not perform auto-cleanup of acquired permits on failures. Acquired permits are not bound to threads and permits can be released without acquiring first. However, you need to handle failed permit owners on your own. If a Hazelcast server or a client fails while holding some permits, they will not be automatically released. You can use the sessionless CP Semaphore implementation by enabling JDK compatibility viajdk-compatible
server-side setting.
There is a subtle difference between the lock and semaphore abstractions. A lock can be assigned to at most one endpoint at a time, so we have a total order among its holders. However, permits of a semaphore can be assigned to multiple endpoints at a time, which implies that we may not have a total order among permit holders. In fact, permit holders are partially ordered. For this reason, the fencing token approach, which is explained in
FencedLock
, does not work for the semaphore abstraction. Moreover, each permit is an independent entity. Multiple permit acquires and reentrant lock acquires of a single endpoint are not equivalent. The only case where a semaphore behaves like a lock is the binary case, where the semaphore has only 1 permit. In this case, the semaphore works like a non-reentrant lock.All of the API methods in the new CP Semaphore implementation offer the exactly-once execution semantics for the session-aware version. For instance, even if a
release()
call is internally retried because of a crashed Hazelcast member, the permit is released only once. However, this guarantee is not given for the sessionless, a.k.a, JDK-compatible CP Semaphore.-
init
(permits)¶ Tries to initialize this Semaphore instance with the given permit count.
- Parameters
permits (int) – The given permit count.
- Returns
True
if the initialization succeeds,False
if already initialized.
- Return type
hazelcast.future.Future[bool]
- Raises
AssertionError – If the
permits
is negative.
-
acquire
(permits=1)¶ Acquires the given number of permits if they are available, and returns immediately, reducing the number of available permits by the given amount.
If insufficient permits are available then the result of the returned future is not set until one of the following things happens:
Some other caller invokes one of the
release
methods for this semaphore, the current caller is next to be assigned permits and the number of available permits satisfies this request,This Semaphore instance is destroyed
- Parameters
permits (int) – Optional number of permits to acquire; defaults to
1
when not specified- Returns
- Return type
hazelcast.future.Future[None]
- Raises
AssertionError – If the
permits
is not positive.
-
available_permits
()¶ Returns the current number of permits currently available in this semaphore.
This method is typically used for debugging and testing purposes.
- Returns
The number of permits available in this semaphore.
- Return type
-
drain_permits
()¶ Acquires and returns all permits that are available at invocation time.
- Returns
The number of permits drained.
- Return type
-
reduce_permits
(reduction)¶ Reduces the number of available permits by the indicated amount.
This method differs from
acquire
as it does not block until permits become available. Similarly, if the caller has acquired some permits, they are not released with this call.- Parameters
reduction (int) – The number of permits to reduce.
- Returns
- Return type
hazelcast.future.Future[None]
- Raises
AssertionError – If the
reduction
is negative.
-
increase_permits
(increase)¶ Increases the number of available permits by the indicated amount.
If there are some callers waiting for permits to become available, they will be notified. Moreover, if the caller has acquired some permits, they are not released with this call.
- Parameters
increase (int) – The number of permits to increase.
- Returns
- Return type
hazelcast.future.Future[None]
- Raises
AssertionError – If
increase
is negative.
-
release
(permits=1)¶ Releases the given number of permits and increases the number of available permits by that amount.
If some callers in the cluster are blocked for acquiring permits, they will be notified.
If the underlying Semaphore implementation is non-JDK-compatible (configured via
jdk-compatible
server-side setting), then a client can only release a permit which it has acquired before. In other words, a client cannot release a permit without acquiring it first.Otherwise, which means the underlying implementation is JDK compatible (configured via
jdk-compatible
server-side setting), there is no requirement that a client that releases a permit must have acquired that permit by calling one of theacquire()
methods. A client can freely release a permit without acquiring it first. In this case, correct usage of a semaphore is established by programming convention in the application.- Parameters
permits (int) – Optional number of permits to release; defaults to
1
when not specified.- Returns
- Return type
hazelcast.future.Future[None]
- Raises
AssertionError – If the
permits
is not positive.IllegalStateError – if the Semaphore is non-JDK-compatible and the caller does not have a permit
-
try_acquire
(permits=1, timeout=0)¶ Acquires the given number of permits and returns
True
, if they become available during the given waiting time.If permits are acquired, the number of available permits in the Semaphore instance is also reduced by the given amount.
If no sufficient permits are available, then the result of the returned future is not set until one of the following things happens:
Permits are released by other callers, the current caller is next to be assigned permits and the number of available permits satisfies this request
The specified waiting time elapses
- Parameters
permits (int) – The number of permits to acquire; defaults to
1
when not specified.timeout (int) – Optional timeout in seconds to wait for the permits; when it’s not specified the operation will return immediately after the acquire attempt
- Returns
True
if all permits were acquired,false
if the waiting time elapsed before all permits could be acquired
- Return type
hazelcast.future.Future[bool]
- Raises
AssertionError – If the
permits
is not positive.