Allocator Module

This module provides resource allocation mechanisms using Redis as the backend.

RedisAllocator

class redis_allocator.allocator.RedisAllocator[source]

A Redis-based distributed allocation system.

Manages a pool of resource identifiers (keys) using Redis, allowing distributed clients to allocate, free, and manage these resources. It leverages Redis’s atomic operations via Lua scripts for safe concurrent access.

The allocator maintains a doubly-linked list in a Redis hash to track available (free) resources. Allocated resources are tracked using standard Redis keys that act as locks.

Key Concepts: - Allocation Pool: A set of resource identifiers (keys) managed by the allocator.

Stored in a Redis hash (<prefix>|<suffix>|pool) representing a doubly-linked list. Head/Tail pointers are stored in separate keys (<prefix>|<suffix>|pool|head, <prefix>|<suffix>|pool|tail).

  • Free List: The subset of keys within the pool that are currently available. Represented by the linked list structure within the pool hash.

  • Allocated State: A key is considered allocated if a corresponding lock key exists (<prefix>|<suffix>:<key>).

  • Shared Mode: If shared=True, allocating a key moves it to the tail of the free list but does not create a lock key. This allows multiple clients to “allocate” the same key concurrently, effectively using the list as a rotating pool. If shared=False (default), allocation creates a lock key, granting exclusive access.

  • Soft Binding: Allows associating a logical name with an allocated key. If an object provides a name, the allocator tries to reuse the previously bound key for that name. Stored in Redis keys like <prefix>|<suffix>-cache:bind:<name>.

  • Garbage Collection (GC): Periodically scans the pool to reconcile the free list with the lock states. Removes expired/locked items from the free list and returns items whose locks have expired back to the free list.

  • Policies: Uses RedisAllocatorPolicy (e.g., DefaultRedisAllocatorPolicy) to customize allocation behavior, GC triggering, and pool updates.

Generic type U should implement RedisAllocatableClass.

__init__(redis, prefix, suffix='allocator', eps=1e-06, shared=False, policy=None)[source]

Initializes the RedisAllocator.

Parameters:
  • redis (Redis) – StrictRedis client instance (must decode responses).

  • prefix (str) – Prefix for all Redis keys used by this allocator instance.

  • suffix – Suffix to uniquely identify this allocator instance’s keys.

  • eps – Small float tolerance for comparisons (used by underlying lock).

  • shared – If True, operates in shared mode (keys are rotated, not locked). If False (default), keys are locked upon allocation.

  • policy (RedisAllocatorPolicy[U] | None) – Optional allocation policy. Defaults to DefaultRedisAllocatorPolicy.

object_key(key, obj)[source]

Get the key for an object.

Parameters:
  • key (str)

  • obj (U)

clear()[source]

Empty the pool.

extend(keys=None, timeout=-1)[source]

Add new resources to the allocation pool.

Parameters:
  • keys (Sequence[str] | None) – Sequence of resource identifiers to add to the pool

  • timeout (int) – Optional timeout in seconds for the pool items (-1 means no timeout)

shrink(keys=None)[source]

Remove resources from the allocation pool.

Parameters:

keys (Sequence[str] | None) – Sequence of resource identifiers to remove from the pool

assign(keys=None, timeout=-1)[source]

Completely replace the resources in the allocation pool.

Parameters:
  • keys (Sequence[str] | None) – Sequence of resource identifiers to assign to the pool, replacing any existing resources

  • timeout (int) – Optional timeout in seconds for the pool items (-1 means no timeout)

keys()[source]

Get all resource identifiers in the allocation pool.

Returns:

Iterable of resource identifiers in the pool

Return type:

Iterable[str]

__contains__(key)[source]

Check if a resource identifier is in the allocation pool.

Parameters:

key – Resource identifier to check

Returns:

True if the resource is in the pool, False otherwise

update_soft_bind(name, key, timeout=3600)[source]

Update a soft binding between a name and a resource.

Soft bindings create a persistent mapping between named objects and allocated keys, allowing the same key to be consistently allocated to the same named object. This is useful for maintaining affinity between objects and their resources.

Parameters:
  • name (str) – Name to bind

  • key (str) – Resource identifier to bind to the name

  • timeout (float | timedelta | None)

unbind_soft_bind(name)[source]

Remove a soft binding.

This removes the persistent mapping between a named object and its allocated key, allowing the key to be freely allocated to any requestor.

Parameters:

name (str) – Name of the soft binding to remove

get_soft_bind(name)[source]

Get the resource identifier bound to a name.

Parameters:

name (str) – Name of the soft binding

Return type:

str | None

malloc_key(timeout=120, name=None, cache_timeout=3600)[source]

Allocate a resource key from the pool.

The behavior depends on the allocator’s shared mode: - In non-shared mode (default): Locks the allocated key for exclusive access - In shared mode: Simply removes the key from the free list without locking it

Parameters:
  • timeout (float | timedelta | None) – How long the allocation lock should be valid (in seconds).

  • name (str | None) – Optional name to use for soft binding.

  • cache_timeout (float | timedelta | None) – Timeout for the soft binding cache entry (seconds). Defaults to 3600. If <= 0, cache entry persists indefinitely.

Returns:

Resource identifier if allocation was successful, None otherwise

Return type:

str | None

malloc(timeout=120, obj=None, params=None, cache_timeout=3600)[source]

Allocate a resource from the pool and wrap it in a RedisAllocatorObject.

If a policy is configured, it will be used to control the allocation behavior. Otherwise, the basic allocation mechanism will be used.

Parameters:
  • timeout (float | timedelta | None) – How long the allocation lock should be valid (in seconds)

  • obj (U | None) – The object to wrap in the RedisAllocatorObject. If it has a .name, soft binding will be attempted.

  • params (dict | None) – Additional parameters to associate with the allocated object.

  • cache_timeout (float | timedelta | None) – Timeout for the soft binding cache entry (seconds). Defaults to 3600. Passed to the policy or malloc_key.

Returns:

RedisAllocatorObject wrapping the allocated resource if successful, None otherwise

Return type:

RedisAllocatorObject[U] | None

free_keys(*keys, timeout=-1)[source]

Free allocated resources.

Parameters:
  • *keys (str) – Resource identifiers to free

  • timeout (int) – Optional timeout in seconds for the pool items (-1 means no timeout)

free(obj, timeout=-1)[source]

Free an allocated object.

Parameters:
  • obj (RedisAllocatorObject[U]) – The allocated object to free

  • timeout (int) – Optional timeout in seconds for the pool item (-1 means no timeout)

__iter__()

Iterate over the keys in the pool.

__len__()

Get the number of keys in the pool.

deleq(key, value)

Deletes a key when the comparison value is equal to the current value.

Parameters:
delge(key, value)

Deletes a key when the comparison value is greater than or equal to the current value.

Parameters:
delgt(key, value)

Deletes a key when the comparison value is greater than the current value.

Parameters:
delle(key, value)

Deletes a key when the comparison value is less than or equal to the current value.

Parameters:
dellt(key, value)

Deletes a key when the comparison value is less than the current value.

Parameters:
delne(key, value)

Deletes a key when the comparison value is not equal to the current value.

Parameters:
get_free_list()[source]
health_check()

Check the health status of the keys in the pool.

Returns:

A tuple of (locked_count, free_count)

Return type:

Tuple[int, int]

is_locked(key)

Check if a key is locked.

Parameters:

key (str) – The key to check.

Returns:

True if the key is locked, False otherwise.

Return type:

bool

items_locked_status()

Get (key, lock_status) pairs for all keys in the pool.

Return type:

Iterable[Tuple[str, bool]]

key_status(key, timeout=120)

Get the status of a key.

Parameters:
  • key (str) – The key to check the status of.

  • timeout (int) – The lock timeout in seconds.

Returns:

The current status of the key.

Return type:

LockStatus

lock(key, value='1', timeout=120)

Try to lock a key for a specified duration.

Parameters:
  • key (str) – The key to lock.

  • value (str) – The value to set for the key.

  • timeout (float | timedelta | None) – The lock timeout in seconds.

Returns:

True if the ownership of the key is successfully acquired, False otherwise.

Return type:

bool

lock_value(key)

Get the value of a locked key.

Parameters:

key (str) – The key to get the value of.

Returns:

The value of the key if the key is locked, None otherwise.

Return type:

str | None

rlock(key, value='1', timeout=120)

Try to lock a key for a specified duration.

When the value is the same as the current value, the function will return True.

Parameters:
  • key (str) – The key to lock.

  • value (str) – The value to set for the key.

  • timeout – The lock timeout in seconds.

Returns:

True if the ownership of the key is successfully acquired, False otherwise.

Return type:

bool

seteq(key, value, set_value=None, ex=None)

Sets a new value when the comparison value is equal to the current value.

Parameters:
Return type:

bool

setge(key, value, set_value=None, ex=None)

Sets a new value when the comparison value is greater than or equal to the current value.

Parameters:
Return type:

bool

setgt(key, value, set_value=None, ex=None)

Sets a new value when the comparison value is greater than the current value.

Parameters:
Return type:

bool

setle(key, value, set_value=None, ex=None)

Sets a new value when the comparison value is less than or equal to the current value.

Parameters:
Return type:

bool

setlt(key, value, set_value=None, ex=None)

Sets a new value when the comparison value is less than the current value.

Parameters:
Return type:

bool

setne(key, value, set_value=None, ex=None)

Sets a new value when the comparison value is not equal to the current value.

Parameters:
Return type:

bool

unlock(key)

Forcefully release a key without checking if the key is locked.

Parameters:

key (str) – The key to release.

Returns:

True if the key is successfully released, False if the key is not locked.

Return type:

bool

update(key, value='1', timeout=120)

Lock a key for a specified duration without checking if the key is already locked.

Parameters:
  • key (str) – The key to lock.

  • value – The value to set for the key.

  • timeout (float | timedelta | None) – The lock timeout in seconds.

values_lock_status()

Get the lock status of all keys in the pool.

Return type:

Iterable[bool]

redis: Redis
prefix: str
suffix: str
eps: float
gc(count=10)[source]

Perform garbage collection on the allocation pool.

This method scans through the pool and ensures consistency between the allocation metadata and the actual locks.

Parameters:

count (int) – Number of items to check in this garbage collection pass

RedisAllocatorObject

RedisAllocatableClass

class redis_allocator.allocator.RedisAllocatableClass[source]

A class that can be allocated through RedisAllocator.

You should inherit from this class and implement the set_config method.

abstract set_config(key, params)[source]

Set the configuration for the object.

Parameters:
  • key (str) – The key to set the configuration for.

  • params (dict) – The parameters to set the configuration for.

open()[source]

Open the object.

close()[source]

close the object.

is_healthy()[source]
property name: str | None

Get the cache name of the object, if is none no soft binding will be used.

property unique_id: str

Get the unique ID of the object.

RedisThreadHealthCheckPool

class redis_allocator.allocator.RedisThreadHealthCheckPool[source]

A class that provides a simple interface for managing the health status of a thread.

This class enables tracking the health status of threads in a distributed environment using Redis locks.

__init__(redis, identity, timeout)[source]

Initialize a RedisThreadHealthCheckPool instance.

Parameters:
  • redis (Redis) – The Redis client used for interacting with Redis.

  • identity (str) – The identity prefix for the health checker.

  • timeout (int) – The timeout for health checks in seconds.

  • tasks – A list of thread identifiers to track.

property current_thread_id: str

Get the current thread ID.

Returns:

The current thread ID as a string.

initialize()[source]

Initialize the health status.

update()[source]

Update the health status.

finalize()[source]

Finalize the health status.

Allocator

Redis-based distributed memory allocation system.

This module provides the core functionality of the RedisAllocator system, allowing for distributed memory allocation with support for garbage collection, thread health checking, and priority-based allocation mechanisms.

Key features: 1. Shared vs non-shared allocation modes:

  • In shared mode, allocating an item simply removes it from the free list and puts it back to the tail

  • In non-shared mode, allocation locks the item to prevent others from accessing it

  1. Garbage collection for stale/unhealthy items: - Items that are locked (unhealthy) but in the free list are removed - Items that are not in the free list but haven’t been updated within their timeout are freed

  2. Soft binding mechanism: - Maps object names to allocated keys for consistent allocation - Prioritizes previously allocated keys when the same named object requests allocation

  3. Support for an updater to refresh the pool’s keys periodically

  4. Policy-based control of allocation behavior through RedisAllocatorPolicy

class redis_allocator.allocator.RedisThreadHealthCheckPool[source]

Bases: RedisLockPool

A class that provides a simple interface for managing the health status of a thread.

This class enables tracking the health status of threads in a distributed environment using Redis locks.

__init__(redis, identity, timeout)[source]

Initialize a RedisThreadHealthCheckPool instance.

Parameters:
  • redis (Redis) – The Redis client used for interacting with Redis.

  • identity (str) – The identity prefix for the health checker.

  • timeout (int) – The timeout for health checks in seconds.

  • tasks – A list of thread identifiers to track.

property current_thread_id: str

Get the current thread ID.

Returns:

The current thread ID as a string.

initialize()[source]

Initialize the health status.

update()[source]

Update the health status.

finalize()[source]

Finalize the health status.

class redis_allocator.allocator.RedisAllocatableClass[source]

Bases: ABC

A class that can be allocated through RedisAllocator.

You should inherit from this class and implement the set_config method.

abstract set_config(key, params)[source]

Set the configuration for the object.

Parameters:
  • key (str) – The key to set the configuration for.

  • params (dict) – The parameters to set the configuration for.

open()[source]

Open the object.

close()[source]

close the object.

is_healthy()[source]
property name: str | None

Get the cache name of the object, if is none no soft binding will be used.

property unique_id: str

Get the unique ID of the object.

class redis_allocator.allocator.RedisAllocatorObject[source]

Bases: Generic[U]

Represents an object allocated through RedisAllocator.

This class provides an interface for working with allocated objects including locking and unlocking mechanisms for thread-safe operations.

__init__(allocator, key, obj=None, params=None)[source]

Initialize a RedisAllocatorObject instance.

Parameters:
  • allocator (RedisAllocator) – The RedisAllocator that created this object

  • key (str) – The Redis key for this allocated object

  • obj (U | None) – The actual object being allocated

  • params (dict | None) – Additional parameters passed by local program

allocator: RedisAllocator
key: str
obj: U | None
params: dict | None
update(timeout=120)[source]

Lock this object for exclusive access.

Parameters:

timeout (float | timedelta | None) – How long the lock should be valid (in seconds)

open()[source]

Open the object.

close()[source]

Kill the object.

is_healthy()[source]

Check if the object is healthy.

Return type:

bool

set_healthy(duration=3600)[source]

Set the object as healthy.

Parameters:

duration (float | timedelta | None)

set_unhealthy(duration=3600)[source]

Set the object as unhealthy.

Parameters:

duration (float | timedelta | None)

refresh(timeout=120, cache_timeout=3600)[source]

Refresh the object.

Parameters:
refresh_until_healthy(timeout=120, max_attempts=10, lock_duration=3600, cache_timeout=3600)[source]

Refresh the object until it is healthy.

Parameters:
property unique_id: str

Get the unique ID of the object.

property name: str | None

Get the name of the object.

class redis_allocator.allocator.RedisAllocatorUpdater[source]

Bases: object

A class that updates the allocator keys.

__init__(params)[source]

Initialize the allocator updater.

Parameters:

params (Sequence[Any])

abstract fetch(param)[source]

Fetch the keys from params.

Parameters:

param (Any)

Return type:

Sequence[str]

__call__()[source]

Update the allocator key.

__len__()[source]

Get the length of the allocator updater.

class redis_allocator.allocator.RedisAllocatorPolicy[source]

Bases: ABC, Generic[U]

Abstract base class for Redis allocator policies.

This class defines the interface for allocation policies that can be used with RedisAllocator to control allocation behavior.

initialize(allocator)[source]

Initialize the policy with an allocator instance.

Parameters:

allocator (RedisAllocator[U]) – The RedisAllocator instance to use with this policy

abstract malloc(allocator, timeout=120, obj=None, params=None, cache_timeout=3600)[source]

Allocate a resource according to the policy.

Parameters:
  • allocator (RedisAllocator[U]) – The RedisAllocator instance

  • timeout (float | timedelta | None) – How long the allocation should be valid (in seconds)

  • obj (U | None) – The object to associate with the allocation

  • params (dict | None) – Additional parameters for the allocation

  • cache_timeout (float | timedelta | None) – Timeout for the soft binding cache entry (seconds). Defaults to 3600.

Returns:

RedisAllocatorObject if allocation was successful, None otherwise

Return type:

RedisAllocatorObject[U] | None

abstract refresh_pool(allocator)[source]

Refresh the allocation pool.

This method is called periodically to update the pool with new resources.

Parameters:

allocator (RedisAllocator[U]) – The RedisAllocator instance

abstract refresh_pool_all(allocator)[source]

Refresh the allocation pool.

Parameters:

allocator (RedisAllocator[U])

check_health_once(r_obj, duration=3600)[source]

Check the health of the object.

Parameters:
Return type:

bool

check_health(allocator, lock_duration=3600, max_threads=8, obj_fn=None, params_fn=None)[source]

Check the health of the allocator.

Parameters:
Returns:

A tuple containing the number of healthy and unhealthy items in the allocator

Return type:

tuple[int, int]

class redis_allocator.allocator.DefaultRedisAllocatorPolicy[source]

Bases: RedisAllocatorPolicy[U]

Default implementation of RedisAllocatorPolicy.

This policy provides the following features: 1. Garbage collection before allocation: Automatically performs garbage collection

operations before allocating resources to ensure stale resources are reclaimed.

  1. Soft binding prioritization: Prioritizes allocation of previously bound keys for named objects, creating a consistent mapping between object names and keys. If a soft binding exists but the bound key is no longer in the pool, the binding is ignored and a new key is allocated.

  2. Periodic pool updates: Uses an optional updater to refresh the pool’s keys at configurable intervals. Only one process/thread (the one that acquires the update lock) will perform the update.

  3. Configurable expiry times: Allows setting default expiry durations for pool items, ensuring automatic cleanup of stale resources even without explicit garbage collection.

The policy controls when garbage collection happens, when the pool is refreshed with new keys, and how allocation prioritizes resources.

__init__(gc_count=5, update_interval=300, expiry_duration=-1, updater=None, auto_close=False)[source]

Initialize the default allocation policy.

Parameters:
  • gc_count (int) – Number of GC operations to perform before allocation

  • update_interval (int) – Interval in seconds between pool updates

  • expiry_duration (int) – Default timeout for pool items (-1 means no timeout)

  • updater (RedisAllocatorUpdater | None) – Optional updater for refreshing the pool’s keys

  • auto_close (bool) – If True, the allocator will automatically close the object when it is not unique

initialize(allocator)[source]

Initialize the policy with an allocator instance.

Parameters:

allocator (RedisAllocator[U]) – The RedisAllocator instance to use with this policy

refresh_pool_all(allocator)[source]

Refresh the allocation pool.

Parameters:

allocator (RedisAllocator[U])

malloc(allocator, timeout=120, obj=None, params=None, cache_timeout=3600)[source]

Allocate a resource according to the policy.

This implementation: 1. Performs GC operations before allocation 2. Checks for soft binding based on object name 3. Falls back to regular allocation if no soft binding exists

Parameters:
  • allocator (RedisAllocator[U]) – The RedisAllocator instance

  • timeout (float | timedelta | None) – How long the allocation should be valid (in seconds)

  • obj (U | None) – The object to associate with the allocation

  • params (dict | None) – Additional parameters for the allocation

  • cache_timeout (float | timedelta | None) – Timeout for the soft binding cache entry (seconds). Defaults to 3600.

Returns:

RedisAllocatorObject if allocation was successful, None otherwise

Return type:

RedisAllocatorObject[U] | None

refresh_pool(allocator, shuffle=True, n=1)[source]

Refresh the allocation pool using the updater.

Parameters:

allocator (RedisAllocator[U]) – The RedisAllocator instance

finalize(allocator)[source]

Finalize the policy.

Parameters:

allocator (RedisAllocator[U])

class redis_allocator.allocator.RedisAllocator[source]

Bases: RedisLockPool, Generic[U]

A Redis-based distributed allocation system.

Manages a pool of resource identifiers (keys) using Redis, allowing distributed clients to allocate, free, and manage these resources. It leverages Redis’s atomic operations via Lua scripts for safe concurrent access.

The allocator maintains a doubly-linked list in a Redis hash to track available (free) resources. Allocated resources are tracked using standard Redis keys that act as locks.

Key Concepts: - Allocation Pool: A set of resource identifiers (keys) managed by the allocator.

Stored in a Redis hash (<prefix>|<suffix>|pool) representing a doubly-linked list. Head/Tail pointers are stored in separate keys (<prefix>|<suffix>|pool|head, <prefix>|<suffix>|pool|tail).

  • Free List: The subset of keys within the pool that are currently available. Represented by the linked list structure within the pool hash.

  • Allocated State: A key is considered allocated if a corresponding lock key exists (<prefix>|<suffix>:<key>).

  • Shared Mode: If shared=True, allocating a key moves it to the tail of the free list but does not create a lock key. This allows multiple clients to “allocate” the same key concurrently, effectively using the list as a rotating pool. If shared=False (default), allocation creates a lock key, granting exclusive access.

  • Soft Binding: Allows associating a logical name with an allocated key. If an object provides a name, the allocator tries to reuse the previously bound key for that name. Stored in Redis keys like <prefix>|<suffix>-cache:bind:<name>.

  • Garbage Collection (GC): Periodically scans the pool to reconcile the free list with the lock states. Removes expired/locked items from the free list and returns items whose locks have expired back to the free list.

  • Policies: Uses RedisAllocatorPolicy (e.g., DefaultRedisAllocatorPolicy) to customize allocation behavior, GC triggering, and pool updates.

Generic type U should implement RedisAllocatableClass.

__init__(redis, prefix, suffix='allocator', eps=1e-06, shared=False, policy=None)[source]

Initializes the RedisAllocator.

Parameters:
  • redis (Redis) – StrictRedis client instance (must decode responses).

  • prefix (str) – Prefix for all Redis keys used by this allocator instance.

  • suffix – Suffix to uniquely identify this allocator instance’s keys.

  • eps – Small float tolerance for comparisons (used by underlying lock).

  • shared – If True, operates in shared mode (keys are rotated, not locked). If False (default), keys are locked upon allocation.

  • policy (RedisAllocatorPolicy[U] | None) – Optional allocation policy. Defaults to DefaultRedisAllocatorPolicy.

object_key(key, obj)[source]

Get the key for an object.

Parameters:
  • key (str)

  • obj (U)

clear()[source]

Empty the pool.

extend(keys=None, timeout=-1)[source]

Add new resources to the allocation pool.

Parameters:
  • keys (Sequence[str] | None) – Sequence of resource identifiers to add to the pool

  • timeout (int) – Optional timeout in seconds for the pool items (-1 means no timeout)

shrink(keys=None)[source]

Remove resources from the allocation pool.

Parameters:

keys (Sequence[str] | None) – Sequence of resource identifiers to remove from the pool

assign(keys=None, timeout=-1)[source]

Completely replace the resources in the allocation pool.

Parameters:
  • keys (Sequence[str] | None) – Sequence of resource identifiers to assign to the pool, replacing any existing resources

  • timeout (int) – Optional timeout in seconds for the pool items (-1 means no timeout)

keys()[source]

Get all resource identifiers in the allocation pool.

Returns:

Iterable of resource identifiers in the pool

Return type:

Iterable[str]

__contains__(key)[source]

Check if a resource identifier is in the allocation pool.

Parameters:

key – Resource identifier to check

Returns:

True if the resource is in the pool, False otherwise

update_soft_bind(name, key, timeout=3600)[source]

Update a soft binding between a name and a resource.

Soft bindings create a persistent mapping between named objects and allocated keys, allowing the same key to be consistently allocated to the same named object. This is useful for maintaining affinity between objects and their resources.

Parameters:
  • name (str) – Name to bind

  • key (str) – Resource identifier to bind to the name

  • timeout (float | timedelta | None)

unbind_soft_bind(name)[source]

Remove a soft binding.

This removes the persistent mapping between a named object and its allocated key, allowing the key to be freely allocated to any requestor.

Parameters:

name (str) – Name of the soft binding to remove

get_soft_bind(name)[source]

Get the resource identifier bound to a name.

Parameters:

name (str) – Name of the soft binding

Return type:

str | None

malloc_key(timeout=120, name=None, cache_timeout=3600)[source]

Allocate a resource key from the pool.

The behavior depends on the allocator’s shared mode: - In non-shared mode (default): Locks the allocated key for exclusive access - In shared mode: Simply removes the key from the free list without locking it

Parameters:
  • timeout (float | timedelta | None) – How long the allocation lock should be valid (in seconds).

  • name (str | None) – Optional name to use for soft binding.

  • cache_timeout (float | timedelta | None) – Timeout for the soft binding cache entry (seconds). Defaults to 3600. If <= 0, cache entry persists indefinitely.

Returns:

Resource identifier if allocation was successful, None otherwise

Return type:

str | None

malloc(timeout=120, obj=None, params=None, cache_timeout=3600)[source]

Allocate a resource from the pool and wrap it in a RedisAllocatorObject.

If a policy is configured, it will be used to control the allocation behavior. Otherwise, the basic allocation mechanism will be used.

Parameters:
  • timeout (float | timedelta | None) – How long the allocation lock should be valid (in seconds)

  • obj (U | None) – The object to wrap in the RedisAllocatorObject. If it has a .name, soft binding will be attempted.

  • params (dict | None) – Additional parameters to associate with the allocated object.

  • cache_timeout (float | timedelta | None) – Timeout for the soft binding cache entry (seconds). Defaults to 3600. Passed to the policy or malloc_key.

Returns:

RedisAllocatorObject wrapping the allocated resource if successful, None otherwise

Return type:

RedisAllocatorObject[U] | None

free_keys(*keys, timeout=-1)[source]

Free allocated resources.

Parameters:
  • *keys (str) – Resource identifiers to free

  • timeout (int) – Optional timeout in seconds for the pool items (-1 means no timeout)

free(obj, timeout=-1)[source]

Free an allocated object.

Parameters:
  • obj (RedisAllocatorObject[U]) – The allocated object to free

  • timeout (int) – Optional timeout in seconds for the pool item (-1 means no timeout)

get_free_list()[source]
redis: Redis
prefix: str
suffix: str
eps: float
gc(count=10)[source]

Perform garbage collection on the allocation pool.

This method scans through the pool and ensures consistency between the allocation metadata and the actual locks.

Parameters:

count (int) – Number of items to check in this garbage collection pass

Core Concepts & Visualization

Allocator Pool Structure (Conceptual)

The allocator manages a pool of resources using several Redis keys:

  • Pool Hash (`<prefix>|<suffix>|pool`): Stores the resource keys currently in the pool. The value for each key represents its position in a doubly-linked list used for the free list (e.g., prev_key||next_key||expiry_timestamp). A special value (#ALLOCATED) indicates the key is part of the pool but not currently free.

  • Head Pointer (`…|pool|head`): A simple key holding the resource key currently at the head of the free list.

  • Tail Pointer (`…|pool|tail`): A simple key holding the resource key currently at the tail of the free list.

  • Lock Keys (`<prefix>|<suffix>:<key>`): Standard Redis keys used as locks in non-shared mode. Their existence indicates a resource is allocated.

  • Soft Bind Cache Keys (`<prefix>|<suffix>-cache:bind:<name>`): Store the mapping between a logical name and an allocated resource key for soft binding.

        graph TD
    subgraph Redis Keys
        HKey["<prefix>|<suffix>|pool|head"] --> Key1["Key1: ""||Key2||Expiry"]
        TKey["<prefix>|<suffix>|pool|tail"] --> KeyN["KeyN: KeyN-1||""||Expiry"]
        PoolHash["<prefix>|<suffix>|pool (Hash)"]
    end

    subgraph "PoolHash Contents (Doubly-Linked Free List)"
        Key1 --> Key2["Key2: Key1||Key3||Expiry"]
        Key2 --> Key3["Key3: Key2||...||Expiry"]
        Key3 --> ...
        KeyN_1[...] --> KeyN
    end

    subgraph "Allocated Keys (Non-Shared Mode)"
        LKey1["<prefix>|<suffix>:AllocatedKey1"]
        LKeyX["<prefix>|<suffix>:AllocatedKeyX"]
    end

    subgraph "Soft Bind Cache"
        CacheKey1["<prefix>|<suffix>-cache:bind:name1"] --> LKey1
    end
    

Simplified Allocation Flow (Non-Shared Mode)

When malloc or malloc_key is called in non-shared mode:

  1. It checks if a name was provided for soft binding.

  2. If yes, it looks up the name in the soft bind cache.

  3. If a cached key is found and the corresponding lock key does not exist, the cached key is reused.

  4. Otherwise (no name, no valid cached key), it attempts to pop a key from the head of the free list (using the Pool Hash and Head Pointer).

  5. If a key is popped, a lock key is created for it with the specified timeout.

  6. If a name was provided, the soft bind cache is updated.

  7. The allocated key (or None) is returned.

        flowchart TD
    Start --> CheckSoftBind{Soft Bind Name Provided?}
    CheckSoftBind -- Yes --> GetBind{GET bind cache key}
    GetBind --> IsBoundKeyValid{"Cached Key Found and Unlocked?"}
    IsBoundKeyValid -- Yes --> ReturnCached[Return Cached Key]
    IsBoundKeyValid -- No --> PopHead{Pop Head from Free List (Lua pop_from_head)}
    CheckSoftBind -- No --> PopHead
    PopHead --> IsKeyFound{Key Found?}
    IsKeyFound -- Yes --> LockKey[SET Lock Key w/ Timeout]
    LockKey --> UpdateCache{"Update Bind Cache (if name provided)"}
    UpdateCache --> ReturnNewKey[Return New Key]
    IsKeyFound -- No --> ReturnNone[Return None]
    ReturnCached --> End
    ReturnNewKey --> End
    ReturnNone --> End
    

Simplified Free Flow (Non-Shared Mode)

When free or free_keys is called in non-shared mode:

  1. It attempts to delete the lock key (<prefix>|<suffix>:<key>).

  2. If the lock key existed and was deleted (DEL returns 1), the resource key is added back to the tail of the free list within the Pool Hash.

        flowchart TD
    Start --> DeleteLock{DEL Lock Key}
    DeleteLock --> Deleted{"Key Existed? (DEL > 0)"}
    Deleted -- Yes --> PushTail[Push Key to Free List Tail (Lua push_to_tail)]
    PushTail --> End
    Deleted -- No --> End
    

Shared Mode

In shared mode (shared=True), the flow is simpler:

  • Allocation: Pops a key from the head, but immediately pushes it back to the tail without creating a lock key. Soft binding still applies.

  • Free: Effectively a no-op, as no lock key was created during allocation.