cacheado 1.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
storages/in_memory.py ADDED
@@ -0,0 +1,109 @@
1
+ import logging
2
+ import threading
3
+ from collections import defaultdict
4
+ from typing import DefaultDict, Dict, List, Optional
5
+
6
+ from cache_types import _CacheKey, _CacheValue
7
+ from protocols.storage_provider import IStorageProvider
8
+
9
+
10
+ class InMemory(IStorageProvider):
11
+ """
12
+ Thread-safe, in-memory implementation of the IStorageProvider.
13
+
14
+ Uses key-based locks for high-concurrency atomic operations.
15
+ Optimized with __slots__ for memory efficiency.
16
+ """
17
+
18
+ __slots__ = ("_cache", "_key_locks", "_instance_lock")
19
+
20
+ def __init__(self):
21
+ """Initializes the in-memory storage."""
22
+ self._cache: Dict[_CacheKey, _CacheValue] = {}
23
+ self._key_locks: DefaultDict[_CacheKey, threading.Lock] = defaultdict(threading.Lock)
24
+ self._instance_lock = threading.Lock()
25
+ logging.info("InMemoryStorageProvider initialized.")
26
+
27
+ def get(self, key: _CacheKey) -> Optional[_CacheValue]:
28
+ """
29
+ Atomically gets a value tuple (value, expiry) from memory.
30
+
31
+ Args:
32
+ key (_CacheKey): The internal key to get.
33
+
34
+ Returns:
35
+ Optional[_CacheValue]: The stored tuple, or None.
36
+ """
37
+ try:
38
+ with self._key_locks[key]:
39
+ return self._cache.get(key)
40
+ except Exception as e:
41
+ logging.error(f"Error getting key {key}: {e}")
42
+ return None
43
+
44
+ def get_value_no_lock(self, key: _CacheKey) -> Optional[_CacheValue]:
45
+ """
46
+ Performs a non-locking ("dirty") read for the cleanup loop.
47
+
48
+ Args:
49
+ key (_CacheKey): The internal key to look up.
50
+
51
+ Returns:
52
+ Optional[_CacheValue]: The stored tuple (value, expiry) or None.
53
+ """
54
+ return self._cache.get(key)
55
+
56
+ def set(self, key: _CacheKey, value: _CacheValue) -> None:
57
+ """
58
+ Atomically sets a value tuple (value, expiry) in memory.
59
+
60
+ Args:
61
+ key (_CacheKey): The internal key to set.
62
+ value (_CacheValue): The (value, expiry) tuple to store.
63
+ """
64
+ try:
65
+ with self._key_locks[key]:
66
+ self._cache[key] = value
67
+ except Exception as e:
68
+ logging.error(f"Error setting key {key}: {e}")
69
+ raise
70
+
71
+ def evict(self, key: _CacheKey) -> None:
72
+ """
73
+ Atomically evicts a key from memory and cleans up its lock.
74
+
75
+ Args:
76
+ key (_CacheKey): The internal key to evict.
77
+ """
78
+ try:
79
+ with self._key_locks[key]:
80
+ if key in self._cache:
81
+ del self._cache[key]
82
+
83
+ if key in self._key_locks:
84
+ del self._key_locks[key]
85
+ except Exception as e:
86
+ logging.error(f"Error evicting key {key}: {e}")
87
+
88
+ def get_all_keys(self) -> List[_CacheKey]:
89
+ """
90
+ Atomically gets a copy of all keys in memory.
91
+
92
+ Returns:
93
+ List[_CacheKey]: A list of all cache keys.
94
+ """
95
+ try:
96
+ with self._instance_lock:
97
+ return list(self._cache.keys())
98
+ except Exception as e:
99
+ logging.error(f"Error getting all keys: {e}")
100
+ return []
101
+
102
+ def clear(self) -> None:
103
+ """Atomically clears the entire in-memory storage."""
104
+ try:
105
+ with self._instance_lock:
106
+ self._cache.clear()
107
+ self._key_locks.clear()
108
+ except Exception as e:
109
+ logging.error(f"Error clearing storage: {e}")