DictCache

DictCache and TwoLevelCache

class DIRAC.Core.Utilities.DictCache.DictCache(deleteFunction=False, threadLocal=False)

Bases: object

DictCache is a generic cache implementation. The user can decide whether this cache should be shared among the threads or not, but it is always thread safe Note that when shared, the access to the cache is protected by a lock, but not necessarily the object you are retrieving from it.

__init__(deleteFunction=False, threadLocal=False)

Initialize the dict cache.

Parameters:
  • deleteFunction – if not False, invoked when deleting a cached object

  • threadLocal – if False, the cache will be shared among all the threads, otherwise, each thread gets its own cache.

add(cKey, validSeconds, value=None)

Add a record to the cache

Parameters:
  • cKey – identification key of the record

  • validSeconds (int) – valid seconds of this record

  • value – value of the record

delete(cKey)

Delete a key from the cache

Parameters:

cKey – identification key of the record

exists(cKey, validSeconds=0)

Returns True/False if the key exists for the given number of seconds

Parameters:
  • cKey – identification key of the record

  • validSeconds (int) – The amount of seconds the key has to be valid for

Returns:

bool

get(cKey, validSeconds=0)

Get a record from the cache

Parameters:
  • cKey – identification key of the record

  • validSeconds (int) – The amount of seconds the key has to be valid for

Returns:

None or value of key

getKeys(validSeconds=0)

Get keys for all contents

Parameters:

validSeconds (int) – valid time in seconds

Returns:

list

property lock

Return the lock. In practice, if the cache is shared among threads, it is a LockRing. Otherwise, it is just a mock object.

purgeAll(useLock=True)

Purge all entries CAUTION: useLock parameter should ALWAYS be True

Parameters:

useLock (bool) – use lock

purgeExpired(expiredInSeconds=0)

Purge all entries that are expired or will be expired in <expiredInSeconds>

Parameters:

expiredInSeconds (int) – expired time in a seconds

showContentsInString()

Return a human readable string to represent the contents

Returns:

str

class DIRAC.Core.Utilities.DictCache.MockLockRing

Bases: object

This mock class is just used to expose the acquire and release method

acquire(*args, **kwargs)

Really does nothing !

doNothing(*args, **kwargs)

Really does nothing !

release(*args, **kwargs)

Really does nothing !

class DIRAC.Core.Utilities.DictCache.ThreadLocalDict

Bases: _local

This class is just useful to have a mutable object (in this case, a dict) as a thread local Read the _threading_local docstring for more details.

Its purpose is to have a different cache per thread

__init__()

c’tor

class DIRAC.Core.Utilities.DictCache.TwoLevelCache(soft_ttl: int, hard_ttl: int, *, max_workers: int = 10, max_items: int = 1000000)

Bases: object

A two-level caching system with soft and hard time-to-live (TTL) expiration.

This cache implements a two-tier caching mechanism to allow for background refresh of cached values. It uses a soft TTL for quick access and a hard TTL as a fallback, which helps in reducing latency and maintaining data freshness.

soft_cache

A cache with a shorter TTL for quick access.

Type:

TTLCache

hard_cache

A cache with a longer TTL as a fallback.

Type:

TTLCache

locks

Thread-safe locks for each cache key.

Type:

defaultdict

futures

Stores ongoing asynchronous population tasks.

Type:

dict

pool

Thread pool for executing cache population tasks.

Type:

ThreadPoolExecutor

Parameters:
  • soft_ttl (int) – Time-to-live in seconds for the soft cache.

  • hard_ttl (int) – Time-to-live in seconds for the hard cache.

  • max_workers (int) – Maximum number of workers in the thread pool.

  • max_items (int) – Maximum number of items in the cache.

Example

>>> cache = TwoLevelCache(soft_ttl=60, hard_ttl=300)
>>> def populate_func():
...     return "cached_value"
>>> value = cache.get("key", populate_func)

Note

The cache uses a ThreadPoolExecutor with a maximum of 10 workers to handle concurrent cache population requests.

__init__(soft_ttl: int, hard_ttl: int, *, max_workers: int = 10, max_items: int = 1000000)

Initialize the TwoLevelCache with specified TTLs.

get(key: str, populate_func: Callable[[], Any]) dict

Retrieve a value from the cache, populating it if necessary.

This method first checks the soft cache for the key. If not found, it checks the hard cache while initiating a background refresh. If the key is not in either cache, it waits for the populate_func to complete and stores the result in both caches.

Locks are used to ensure there is never more than one concurrent population task for a given key.

Parameters:
  • key (str) – The cache key to retrieve or populate.

  • populate_func (Callable[[], Any]) – A function to call to populate the cache if the key is not found.

Returns:

The cached value associated with the key.

Return type:

Any

Note

This method is thread-safe and handles concurrent requests for the same key.