qlat_utils.cache — Hierarchical In-Memory Cache¶
Source: qlat-utils/qlat_utils/cache.py
Note: Update this document when updating the source file.
Outline¶
Overview¶
The qlat_utils.cache module provides a hierarchical, dict-based caching
system built on the Cache class (a dict subclass). Each Cache node
carries a cache_keys attribute recording its path from the root, enabling
introspection and targeted cleanup.
A module-level root cache object serves as the top of the hierarchy.
Sub-caches are created and retrieved with mk_cache. Values can be cleaned
recursively without destroying structure, and the entire Python + C++ cache
stack can be cleared with clear_all_caches.
Cache Class¶
class Cache(dict)¶
A dict subclass that records a hierarchical key path.
Attribute |
Type |
Description |
|---|---|---|
|
|
Chain of keys from the root cache to this node |
Cache behaves exactly like a regular dict for item access (__getitem__,
__setitem__, pop, items, etc.). The cache_keys tuple is purely
informational and used by management functions for logging.
Global Cache & Management Functions¶
cache¶
The module-level root Cache() instance. All sub-caches are descendants of
this object.
mk_cache(*keys, ca=cache)¶
Create a nested chain of Cache nodes under ca for each key in keys.
If a sub-cache already exists at any level, it is reused (not recreated).
Returns the innermost Cache node.
Parameter |
Type |
Default |
Description |
|---|---|---|---|
|
|
— |
Hierarchical key path |
|
|
|
Parent cache to search/create under |
clean_cache(ca=cache)¶
Recursively remove all leaf values (non-Cache entries) from ca and its
sub-caches, preserving the Cache structure itself. Timed with @timer.
rm_cache(*keys, ca=cache)¶
Remove the sub-cache identified by keys from ca if it exists. Timed with
@timer.
list_cache(ca=cache)¶
Return a nested dict mirroring the cache hierarchy. Leaf values are omitted;
only Cache sub-nodes are included. Timed with @timer.
show_cache_keys(keys)¶
Return a human-readable string representation of a cache_keys tuple, e.g.
"['fields_io']['gauge_field']".
clear_all_caches()¶
Clean the Python-level cache (clean_cache + cache.clear()) and then clear
the C+±level cache via c.clear_all_caches(). Timed with @timer.
Examples¶
Creating and Using a Sub-Cache¶
import qlat_utils as q
# Create a sub-cache for field I/O handles
cache_fields_io = q.mk_cache("fields_io")
# Store a value keyed by object id
my_obj = object()
cache_fields_io[id(my_obj)] = ("fsel_data", "sbs_data")
# Retrieve
assert id(my_obj) in cache_fields_io
c_fsel, c_sbs = cache_fields_io[id(my_obj)]
assert c_fsel == "fsel_data"
assert c_sbs == "sbs_data"
# Remove
cache_fields_io.pop(id(my_obj), None)
assert id(my_obj) not in cache_fields_io
Hierarchical Sub-Caches¶
import qlat_utils as q
cache_gauge = q.mk_cache("fields_io", "gauge_field")
# Equivalent to:
# cache["fields_io"]["gauge_field"]
# created step by step, reusing existing nodes.
# Store and retrieve a value
cache_gauge["config_100"] = {"beta": 6.0, "L": 8}
assert cache_gauge["config_100"]["beta"] == 6.0
# mk_cache reuses existing nodes (does not overwrite)
cache_gauge2 = q.mk_cache("fields_io", "gauge_field")
assert cache_gauge is cache_gauge2
Removing a Sub-Cache¶
import qlat_utils as q
# Set up a nested cache
q.mk_cache("fields_io", "gauge_field")
q.mk_cache("fields_io", "prop_field")
# Remove one sub-cache (keeps sibling)
q.rm_cache("fields_io", "gauge_field")
# Verify it is gone
assert "gauge_field" not in q.cache.get("fields_io", {})
# Sibling still exists
assert "prop_field" in q.cache["fields_io"]
Cleaning Values (Preserving Structure)¶
import qlat_utils as q
# Set up cache with values
cache_io = q.mk_cache("fields_io")
cache_io["key_a"] = "value_a"
cache_io["key_b"] = "value_b"
# clean_cache removes leaf values but keeps Cache sub-nodes
q.clean_cache()
assert len(cache_io) == 0
# The Cache node itself still exists in the hierarchy
assert "fields_io" in q.cache
Clearing All Caches¶
import qlat_utils as q
# Set up some caches with values
cache_io = q.mk_cache("fields_io")
cache_io["key"] = "value"
# clear_all_caches clears both Python-level and C++-level caches
q.clear_all_caches()
# Python cache is empty after clearing
assert len(q.cache) == 0
Inspecting the Cache¶
import qlat_utils as q
# Create some nested caches
q.mk_cache("fields_io", "gauge_field")
q.mk_cache("fields_io", "prop_field")
structure = q.list_cache()
# Returns a nested dict with Cache sub-nodes only (no leaf values)
assert "fields_io" in structure
assert "gauge_field" in structure["fields_io"]
assert "prop_field" in structure["fields_io"]
Multiple Independent Cache Trees¶
import qlat_utils as q
# You can create independent cache trees under different roots
root_a = q.Cache()
root_b = q.Cache()
ca = q.mk_cache("group", "sub", ca=root_a)
cb = q.mk_cache("group", "sub", ca=root_b)
ca["from_a"] = 1
cb["from_b"] = 2
assert ca["from_a"] == 1
assert cb["from_b"] == 2
# They are independent
assert "from_b" not in ca
assert "from_a" not in cb
Cache Keys Introspection¶
import qlat_utils as q
cache_gauge = q.mk_cache("fields_io", "gauge_field")
# cache_keys records the path from the root
assert cache_gauge.cache_keys == ("fields_io", "gauge_field")
# show_cache_keys produces a human-readable string
print(q.show_cache_keys(cache_gauge.cache_keys))
# Output: ['fields_io']['gauge_field']