Skip to content

Commit 881f37b

Browse files
Cache effective object roots in TreeStore lookups
Agent-Logs-Url: https://github.com/Blosc/python-blosc2/sessions/973a79eb-d0c3-43ac-8008-54a9bd392be0 Co-authored-by: FrancescAlted <314521+FrancescAlted@users.noreply.github.com>
1 parent 14b0a72 commit 881f37b

1 file changed

Lines changed: 35 additions & 9 deletions

File tree

src/blosc2/tree_store.py

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,8 @@ def __init__(self, *args, _from_parent_store=None, **kwargs):
190190

191191
self.subtree_path = "" # Empty string means full tree
192192
self._inline_handles: list = [] # inline object handles opened from this store
193+
self._known_object_roots_cache: set[str] | None = None
194+
self._effective_object_roots_cache: tuple[str, set[str]] | None = None
193195

194196
# ------------------------------------------------------------------
195197
# Object registry helpers
@@ -203,12 +205,18 @@ def _objects_registry(self) -> dict:
203205
except Exception:
204206
return {}
205207

208+
def _invalidate_object_roots_cache(self) -> None:
209+
"""Invalidate cached object-root views."""
210+
self._known_object_roots_cache = None
211+
self._effective_object_roots_cache = None
212+
206213
def _register_object(self, full_key: str, *, kind: str, version: int, layout: str) -> None:
207214
"""Register *full_key* as an object root in the persistent registry."""
208215
try:
209216
reg = self._objects_registry()
210217
reg[full_key] = {"kind": kind, "version": version, "layout": layout}
211218
self._estore._store.vlmeta["_object_registry"] = reg
219+
self._invalidate_object_roots_cache()
212220
except Exception:
213221
pass # best-effort
214222

@@ -218,6 +226,7 @@ def _unregister_object(self, full_key: str) -> None:
218226
reg = self._objects_registry()
219227
reg.pop(full_key, None)
220228
self._estore._store.vlmeta["_object_registry"] = reg
229+
self._invalidate_object_roots_cache()
221230
except Exception:
222231
pass
223232

@@ -247,23 +256,40 @@ def _probed_object_roots(self) -> set:
247256

248257
def _known_object_roots(self) -> set:
249258
"""Return registered plus physically probed object-root full keys."""
250-
return self._object_roots() | self._probed_object_roots()
259+
if self._known_object_roots_cache is not None:
260+
return set(self._known_object_roots_cache)
261+
262+
registered = self._object_roots()
263+
# Fast path: when registry exists, avoid costly full-store probing.
264+
roots = registered if registered else self._probed_object_roots()
265+
self._known_object_roots_cache = roots
266+
return set(roots)
251267

252268
def _effective_object_roots(self) -> set:
253269
"""Object root keys relative to the current view (subtree or root)."""
270+
current_subtree_path = self.subtree_path or ""
271+
if (
272+
self._effective_object_roots_cache is not None
273+
and self._effective_object_roots_cache[0] == current_subtree_path
274+
):
275+
return set(self._effective_object_roots_cache[1])
276+
254277
all_roots = self._known_object_roots()
255278
if not self.subtree_path:
256-
return all_roots
279+
self._effective_object_roots_cache = (current_subtree_path, all_roots)
280+
return set(all_roots)
257281
result = set()
258282
for full_key in all_roots:
259283
relative = self._translate_key_from_full(full_key)
260284
if relative is not None:
261285
result.add(relative)
262-
return result
286+
self._effective_object_roots_cache = (current_subtree_path, result)
287+
return set(result)
263288

264-
def _is_object_internal_key(self, key: str) -> bool:
289+
def _is_object_internal_key(self, key: str, object_roots: set[str] | None = None) -> bool:
265290
"""Return ``True`` when *key* (subtree-relative) is inside an object root."""
266-
return any(key != root and key.startswith(root + "/") for root in self._effective_object_roots())
291+
roots = self._effective_object_roots() if object_roots is None else object_roots
292+
return any(key != root and key.startswith(root + "/") for root in roots)
267293

268294
def _probe_object_info(self, full_key: str) -> dict | None:
269295
"""Probe the physical store for a CTable manifest at *full_key*/_meta.
@@ -647,7 +673,8 @@ def __contains__(self, key: str) -> bool:
647673
key = self._validate_key(key)
648674
if self._is_vlmeta_key(key):
649675
return False
650-
if self._is_object_internal_key(key):
676+
object_roots = self._effective_object_roots()
677+
if self._is_object_internal_key(key, object_roots):
651678
return False
652679
full_key = self._translate_key_to_full(key)
653680
return (
@@ -692,11 +719,10 @@ def keys(self):
692719
all_keys = {key for key in all_keys if not self._is_vlmeta_key(key)}
693720

694721
# Filter out object-internal keys
695-
all_keys = {key for key in all_keys if not self._is_object_internal_key(key)}
696-
697-
# Add object roots (they are not stored as DictStore keys themselves)
698722
object_roots = self._effective_object_roots()
723+
all_keys = {key for key in all_keys if not self._is_object_internal_key(key, object_roots)}
699724

725+
# Add object roots (they are not stored as DictStore keys themselves)
700726
# Build structural paths from both data leaves and object root keys
701727
all_with_roots = all_keys | object_roots
702728
structural_keys = set()

0 commit comments

Comments
 (0)