-
Notifications
You must be signed in to change notification settings - Fork 421
/
Copy pathcache.py
215 lines (177 loc) · 5.92 KB
/
cache.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
from __future__ import annotations
from collections import deque
from typing import Any
class KeyBufferCache:
"""
A cache implementation for a single key with size tracking and eviction support.
This class manages a buffer for a specific key, keeping track of the current size
and providing methods to add, remove, and manage cached items. It supports automatic
eviction tracking and size management.
Attributes
----------
cache : deque
A double-ended queue storing the cached items.
current_size : int
The total size of all items currently in the cache.
has_evicted : bool
A flag indicating whether any items have been evicted from the cache.
"""
def __init__(self):
"""
Initialize a buffer cache for a specific key.
"""
self.cache: deque = deque()
self.current_size: int = 0
self.has_evicted: bool = False
def add(self, item: Any) -> None:
"""
Add an item to the cache.
Parameters
----------
item : Any
The item to be stored in the cache.
"""
item_size = len(str(item))
self.cache.append(item)
self.current_size += item_size
def remove_oldest(self) -> Any:
"""
Remove and return the oldest item from the cache.
Returns
-------
Any
The removed item.
"""
removed_item = self.cache.popleft()
self.current_size -= len(str(removed_item))
self.has_evicted = True
return removed_item
def get(self) -> list:
"""
Retrieve items for this key.
Returns
-------
list
List of items in the cache.
"""
return list(self.cache)
def clear(self) -> None:
"""
Clear the cache for this key.
"""
self.cache.clear()
self.current_size = 0
self.has_evicted = False
class LoggerBufferCache:
"""
A multi-key buffer cache with size-based eviction and management.
This class provides a flexible caching mechanism that manages multiple keys,
with each key having its own buffer cache. The total size of each key's cache
is limited, and older items are automatically evicted when the size limit is reached.
Key Features:
- Multiple key support
- Size-based eviction
- Tracking of evicted items
- Configurable maximum buffer size
Example
--------
>>> buffer_cache = LoggerBufferCache(max_size_bytes=1000)
>>> buffer_cache.add("logs", "First log message")
>>> buffer_cache.add("debug", "Debug information")
>>> buffer_cache.get("logs")
['First log message']
>>> buffer_cache.get_current_size("logs")
16
"""
def __init__(self, max_size_bytes: int):
"""
Initialize the LoggerBufferCache.
Parameters
----------
max_size_bytes : int
Maximum size of the cache in bytes for each key.
"""
self.max_size_bytes: int = max_size_bytes
self.cache: dict[str, KeyBufferCache] = {}
def add(self, key: str, item: Any) -> None:
"""
Add an item to the cache for a specific key.
Parameters
----------
key : str
The key to store the item under.
item : Any
The item to be stored in the cache.
Returns
-------
bool
True if item was added, False otherwise.
"""
# Check if item is larger than entire buffer
item_size = len(str(item))
if item_size > self.max_size_bytes:
raise BufferError("Cannot add item to the buffer")
# Create the key's cache if it doesn't exist
if key not in self.cache:
self.cache[key] = KeyBufferCache()
# Calculate the size after adding the new item
new_total_size = self.cache[key].current_size + item_size
# If adding the item would exceed max size, remove oldest items
while new_total_size > self.max_size_bytes and self.cache[key].cache:
self.cache[key].remove_oldest()
new_total_size = self.cache[key].current_size + item_size
self.cache[key].add(item)
def get(self, key: str) -> list:
"""
Retrieve items for a specific key.
Parameters
----------
key : str
The key to retrieve items for.
Returns
-------
list
List of items for the given key, or an empty list if the key doesn't exist.
"""
return [] if key not in self.cache else self.cache[key].get()
def clear(self, key: str | None = None) -> None:
"""
Clear the cache, either for a specific key or entirely.
Parameters
----------
key : Optional[str], optional
The key to clear. If None, clears the entire cache.
"""
if key:
if key in self.cache:
self.cache[key].clear()
del self.cache[key]
else:
self.cache.clear()
def has_items_evicted(self, key: str) -> bool:
"""
Check if a specific key's cache has evicted items.
Parameters
----------
key : str
The key to check for evicted items.
Returns
-------
bool
True if items have been evicted, False otherwise.
"""
return False if key not in self.cache else self.cache[key].has_evicted
def get_current_size(self, key: str) -> int | None:
"""
Get the current size of the buffer for a specific key.
Parameters
----------
key : str
The key to get the current size for.
Returns
-------
int
The current size of the buffer for the key.
Returns 0 if the key does not exist.
"""
return None if key not in self.cache else self.cache[key].current_size