createsonline 0.1.26__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.
- createsonline/__init__.py +46 -0
- createsonline/admin/__init__.py +7 -0
- createsonline/admin/content.py +526 -0
- createsonline/admin/crud.py +805 -0
- createsonline/admin/field_builder.py +559 -0
- createsonline/admin/integration.py +482 -0
- createsonline/admin/interface.py +2562 -0
- createsonline/admin/model_creator.py +513 -0
- createsonline/admin/model_manager.py +388 -0
- createsonline/admin/modern_dashboard.py +498 -0
- createsonline/admin/permissions.py +264 -0
- createsonline/admin/user_forms.py +594 -0
- createsonline/ai/__init__.py +202 -0
- createsonline/ai/fields.py +1226 -0
- createsonline/ai/orm.py +325 -0
- createsonline/ai/services.py +1244 -0
- createsonline/app.py +506 -0
- createsonline/auth/__init__.py +8 -0
- createsonline/auth/management.py +228 -0
- createsonline/auth/models.py +552 -0
- createsonline/cli/__init__.py +5 -0
- createsonline/cli/commands/__init__.py +122 -0
- createsonline/cli/commands/database.py +416 -0
- createsonline/cli/commands/info.py +173 -0
- createsonline/cli/commands/initdb.py +218 -0
- createsonline/cli/commands/project.py +545 -0
- createsonline/cli/commands/serve.py +173 -0
- createsonline/cli/commands/shell.py +93 -0
- createsonline/cli/commands/users.py +148 -0
- createsonline/cli/main.py +2041 -0
- createsonline/cli/manage.py +274 -0
- createsonline/config/__init__.py +9 -0
- createsonline/config/app.py +2577 -0
- createsonline/config/database.py +179 -0
- createsonline/config/docs.py +384 -0
- createsonline/config/errors.py +160 -0
- createsonline/config/orm.py +43 -0
- createsonline/config/request.py +93 -0
- createsonline/config/settings.py +176 -0
- createsonline/data/__init__.py +23 -0
- createsonline/data/dataframe.py +925 -0
- createsonline/data/io.py +453 -0
- createsonline/data/series.py +557 -0
- createsonline/database/__init__.py +60 -0
- createsonline/database/abstraction.py +440 -0
- createsonline/database/assistant.py +585 -0
- createsonline/database/fields.py +442 -0
- createsonline/database/migrations.py +132 -0
- createsonline/database/models.py +604 -0
- createsonline/database.py +438 -0
- createsonline/http/__init__.py +28 -0
- createsonline/http/client.py +535 -0
- createsonline/ml/__init__.py +55 -0
- createsonline/ml/classification.py +552 -0
- createsonline/ml/clustering.py +680 -0
- createsonline/ml/metrics.py +542 -0
- createsonline/ml/neural.py +560 -0
- createsonline/ml/preprocessing.py +784 -0
- createsonline/ml/regression.py +501 -0
- createsonline/performance/__init__.py +19 -0
- createsonline/performance/cache.py +444 -0
- createsonline/performance/compression.py +335 -0
- createsonline/performance/core.py +419 -0
- createsonline/project_init.py +789 -0
- createsonline/routing.py +528 -0
- createsonline/security/__init__.py +34 -0
- createsonline/security/core.py +811 -0
- createsonline/security/encryption.py +349 -0
- createsonline/server.py +295 -0
- createsonline/static/css/admin.css +263 -0
- createsonline/static/css/common.css +358 -0
- createsonline/static/css/dashboard.css +89 -0
- createsonline/static/favicon.ico +0 -0
- createsonline/static/icons/icon-128x128.png +0 -0
- createsonline/static/icons/icon-128x128.webp +0 -0
- createsonline/static/icons/icon-16x16.png +0 -0
- createsonline/static/icons/icon-16x16.webp +0 -0
- createsonline/static/icons/icon-180x180.png +0 -0
- createsonline/static/icons/icon-180x180.webp +0 -0
- createsonline/static/icons/icon-192x192.png +0 -0
- createsonline/static/icons/icon-192x192.webp +0 -0
- createsonline/static/icons/icon-256x256.png +0 -0
- createsonline/static/icons/icon-256x256.webp +0 -0
- createsonline/static/icons/icon-32x32.png +0 -0
- createsonline/static/icons/icon-32x32.webp +0 -0
- createsonline/static/icons/icon-384x384.png +0 -0
- createsonline/static/icons/icon-384x384.webp +0 -0
- createsonline/static/icons/icon-48x48.png +0 -0
- createsonline/static/icons/icon-48x48.webp +0 -0
- createsonline/static/icons/icon-512x512.png +0 -0
- createsonline/static/icons/icon-512x512.webp +0 -0
- createsonline/static/icons/icon-64x64.png +0 -0
- createsonline/static/icons/icon-64x64.webp +0 -0
- createsonline/static/image/android-chrome-192x192.png +0 -0
- createsonline/static/image/android-chrome-512x512.png +0 -0
- createsonline/static/image/apple-touch-icon.png +0 -0
- createsonline/static/image/favicon-16x16.png +0 -0
- createsonline/static/image/favicon-32x32.png +0 -0
- createsonline/static/image/favicon.ico +0 -0
- createsonline/static/image/favicon.svg +17 -0
- createsonline/static/image/icon-128x128.png +0 -0
- createsonline/static/image/icon-128x128.webp +0 -0
- createsonline/static/image/icon-16x16.png +0 -0
- createsonline/static/image/icon-16x16.webp +0 -0
- createsonline/static/image/icon-180x180.png +0 -0
- createsonline/static/image/icon-180x180.webp +0 -0
- createsonline/static/image/icon-192x192.png +0 -0
- createsonline/static/image/icon-192x192.webp +0 -0
- createsonline/static/image/icon-256x256.png +0 -0
- createsonline/static/image/icon-256x256.webp +0 -0
- createsonline/static/image/icon-32x32.png +0 -0
- createsonline/static/image/icon-32x32.webp +0 -0
- createsonline/static/image/icon-384x384.png +0 -0
- createsonline/static/image/icon-384x384.webp +0 -0
- createsonline/static/image/icon-48x48.png +0 -0
- createsonline/static/image/icon-48x48.webp +0 -0
- createsonline/static/image/icon-512x512.png +0 -0
- createsonline/static/image/icon-512x512.webp +0 -0
- createsonline/static/image/icon-64x64.png +0 -0
- createsonline/static/image/icon-64x64.webp +0 -0
- createsonline/static/image/logo-header-h100.png +0 -0
- createsonline/static/image/logo-header-h100.webp +0 -0
- createsonline/static/image/logo-header-h200@2x.png +0 -0
- createsonline/static/image/logo-header-h200@2x.webp +0 -0
- createsonline/static/image/logo.png +0 -0
- createsonline/static/js/admin.js +274 -0
- createsonline/static/site.webmanifest +35 -0
- createsonline/static/templates/admin/base.html +87 -0
- createsonline/static/templates/admin/dashboard.html +217 -0
- createsonline/static/templates/admin/model_form.html +270 -0
- createsonline/static/templates/admin/model_list.html +202 -0
- createsonline/static/test_script.js +15 -0
- createsonline/static/test_styles.css +59 -0
- createsonline/static_files.py +365 -0
- createsonline/templates/404.html +100 -0
- createsonline/templates/admin_login.html +169 -0
- createsonline/templates/base.html +102 -0
- createsonline/templates/index.html +151 -0
- createsonline/templates.py +205 -0
- createsonline/testing.py +322 -0
- createsonline/utils.py +448 -0
- createsonline/validation/__init__.py +49 -0
- createsonline/validation/fields.py +598 -0
- createsonline/validation/models.py +504 -0
- createsonline/validation/validators.py +561 -0
- createsonline/views.py +184 -0
- createsonline-0.1.26.dist-info/METADATA +46 -0
- createsonline-0.1.26.dist-info/RECORD +152 -0
- createsonline-0.1.26.dist-info/WHEEL +5 -0
- createsonline-0.1.26.dist-info/entry_points.txt +2 -0
- createsonline-0.1.26.dist-info/licenses/LICENSE +21 -0
- createsonline-0.1.26.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
# createsonline/performance/cache.py
|
|
2
|
+
"""
|
|
3
|
+
Ultra-Fast Caching System for CREATESONLINE
|
|
4
|
+
|
|
5
|
+
Advanced caching strategies:
|
|
6
|
+
- LRU cache with TTL
|
|
7
|
+
- Memory-mapped caching
|
|
8
|
+
- Distributed cache support
|
|
9
|
+
- Smart cache invalidation
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import time
|
|
13
|
+
import hashlib
|
|
14
|
+
import threading
|
|
15
|
+
from typing import Any, Dict, Optional, Callable
|
|
16
|
+
from collections import OrderedDict
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class CacheManager:
|
|
20
|
+
"""
|
|
21
|
+
Ultra-high performance cache manager with multiple cache layers
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(self, max_size=10000, default_ttl=300):
|
|
25
|
+
self.max_size = max_size
|
|
26
|
+
self.default_ttl = default_ttl
|
|
27
|
+
|
|
28
|
+
# Multi-layer cache system
|
|
29
|
+
self.l1_cache = LRUCache(max_size // 4) # Hot cache
|
|
30
|
+
self.l2_cache = TTLCache(max_size) # Main cache
|
|
31
|
+
self.l3_cache = DiskCache() # Disk cache for large items
|
|
32
|
+
|
|
33
|
+
# Cache statistics
|
|
34
|
+
self.stats = CacheStats()
|
|
35
|
+
|
|
36
|
+
# Background cleanup thread
|
|
37
|
+
self._cleanup_thread = threading.Thread(target=self._cleanup_worker, daemon=True)
|
|
38
|
+
self._cleanup_thread.start()
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def get(self, key: str) -> Optional[Any]:
|
|
42
|
+
"""Get item from cache with multi-layer lookup"""
|
|
43
|
+
|
|
44
|
+
# L1 Cache (fastest)
|
|
45
|
+
result = self.l1_cache.get(key)
|
|
46
|
+
if result is not None:
|
|
47
|
+
self.stats.record_hit('l1')
|
|
48
|
+
return result
|
|
49
|
+
|
|
50
|
+
# L2 Cache
|
|
51
|
+
result = self.l2_cache.get(key)
|
|
52
|
+
if result is not None:
|
|
53
|
+
# Promote to L1 for frequently accessed items
|
|
54
|
+
self.l1_cache.set(key, result)
|
|
55
|
+
self.stats.record_hit('l2')
|
|
56
|
+
return result
|
|
57
|
+
|
|
58
|
+
# L3 Cache (disk)
|
|
59
|
+
result = self.l3_cache.get(key)
|
|
60
|
+
if result is not None:
|
|
61
|
+
# Promote to L2
|
|
62
|
+
self.l2_cache.set(key, result)
|
|
63
|
+
self.stats.record_hit('l3')
|
|
64
|
+
return result
|
|
65
|
+
|
|
66
|
+
self.stats.record_miss()
|
|
67
|
+
return None
|
|
68
|
+
|
|
69
|
+
def set(self, key: str, value: Any, ttl: Optional[int] = None) -> None:
|
|
70
|
+
"""Set item in appropriate cache layer"""
|
|
71
|
+
|
|
72
|
+
ttl = ttl or self.default_ttl
|
|
73
|
+
|
|
74
|
+
# Determine cache layer based on value size
|
|
75
|
+
value_size = self._estimate_size(value)
|
|
76
|
+
|
|
77
|
+
if value_size < 1024: # Small items go to L1
|
|
78
|
+
self.l1_cache.set(key, value)
|
|
79
|
+
self.l2_cache.set(key, value, ttl)
|
|
80
|
+
elif value_size < 1024 * 1024: # Medium items go to L2
|
|
81
|
+
self.l2_cache.set(key, value, ttl)
|
|
82
|
+
else: # Large items go to L3
|
|
83
|
+
self.l3_cache.set(key, value, ttl)
|
|
84
|
+
|
|
85
|
+
self.stats.record_set()
|
|
86
|
+
|
|
87
|
+
def delete(self, key: str) -> bool:
|
|
88
|
+
"""Delete item from all cache layers"""
|
|
89
|
+
|
|
90
|
+
deleted = False
|
|
91
|
+
deleted |= self.l1_cache.delete(key)
|
|
92
|
+
deleted |= self.l2_cache.delete(key)
|
|
93
|
+
deleted |= self.l3_cache.delete(key)
|
|
94
|
+
|
|
95
|
+
if deleted:
|
|
96
|
+
self.stats.record_delete()
|
|
97
|
+
|
|
98
|
+
return deleted
|
|
99
|
+
|
|
100
|
+
def clear(self) -> None:
|
|
101
|
+
"""Clear all cache layers"""
|
|
102
|
+
self.l1_cache.clear()
|
|
103
|
+
self.l2_cache.clear()
|
|
104
|
+
self.l3_cache.clear()
|
|
105
|
+
self.stats.reset()
|
|
106
|
+
|
|
107
|
+
def get_stats(self) -> Dict[str, Any]:
|
|
108
|
+
"""Get comprehensive cache statistics"""
|
|
109
|
+
return {
|
|
110
|
+
"cache_layers": {
|
|
111
|
+
"l1_size": len(self.l1_cache.cache),
|
|
112
|
+
"l2_size": len(self.l2_cache.cache),
|
|
113
|
+
"l3_size": self.l3_cache.size()
|
|
114
|
+
},
|
|
115
|
+
"hit_rates": self.stats.get_hit_rates(),
|
|
116
|
+
"performance": self.stats.get_performance_metrics()
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
def _estimate_size(self, value: Any) -> int:
|
|
120
|
+
"""Estimate memory size of value"""
|
|
121
|
+
if isinstance(value, str):
|
|
122
|
+
return len(value.encode('utf-8'))
|
|
123
|
+
elif isinstance(value, (int, float)):
|
|
124
|
+
return 8
|
|
125
|
+
elif isinstance(value, dict):
|
|
126
|
+
return sum(self._estimate_size(k) + self._estimate_size(v) for k, v in value.items())
|
|
127
|
+
elif isinstance(value, list):
|
|
128
|
+
return sum(self._estimate_size(item) for item in value)
|
|
129
|
+
else:
|
|
130
|
+
return 1024 # Default estimate
|
|
131
|
+
|
|
132
|
+
def _cleanup_worker(self):
|
|
133
|
+
"""Background cleanup worker"""
|
|
134
|
+
while True:
|
|
135
|
+
time.sleep(60) # Cleanup every minute
|
|
136
|
+
self.l2_cache.cleanup_expired()
|
|
137
|
+
self.l3_cache.cleanup_expired()
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class LRUCache:
|
|
141
|
+
"""Ultra-fast LRU cache implementation"""
|
|
142
|
+
|
|
143
|
+
def __init__(self, max_size: int = 1000):
|
|
144
|
+
self.max_size = max_size
|
|
145
|
+
self.cache = OrderedDict()
|
|
146
|
+
self.lock = threading.RLock()
|
|
147
|
+
|
|
148
|
+
def get(self, key: str) -> Optional[Any]:
|
|
149
|
+
"""Get item and move to end (most recently used)"""
|
|
150
|
+
with self.lock:
|
|
151
|
+
if key in self.cache:
|
|
152
|
+
# Move to end
|
|
153
|
+
value = self.cache.pop(key)
|
|
154
|
+
self.cache[key] = value
|
|
155
|
+
return value
|
|
156
|
+
return None
|
|
157
|
+
|
|
158
|
+
def set(self, key: str, value: Any) -> None:
|
|
159
|
+
"""Set item and maintain size limit"""
|
|
160
|
+
with self.lock:
|
|
161
|
+
if key in self.cache:
|
|
162
|
+
# Update existing
|
|
163
|
+
self.cache.pop(key)
|
|
164
|
+
elif len(self.cache) >= self.max_size:
|
|
165
|
+
# Remove least recently used
|
|
166
|
+
self.cache.popitem(last=False)
|
|
167
|
+
|
|
168
|
+
self.cache[key] = value
|
|
169
|
+
|
|
170
|
+
def delete(self, key: str) -> bool:
|
|
171
|
+
"""Delete item"""
|
|
172
|
+
with self.lock:
|
|
173
|
+
if key in self.cache:
|
|
174
|
+
del self.cache[key]
|
|
175
|
+
return True
|
|
176
|
+
return False
|
|
177
|
+
|
|
178
|
+
def clear(self) -> None:
|
|
179
|
+
"""Clear all items"""
|
|
180
|
+
with self.lock:
|
|
181
|
+
self.cache.clear()
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
class TTLCache:
|
|
185
|
+
"""Time-to-live cache with automatic expiration"""
|
|
186
|
+
|
|
187
|
+
def __init__(self, max_size: int = 5000):
|
|
188
|
+
self.max_size = max_size
|
|
189
|
+
self.cache = {}
|
|
190
|
+
self.timestamps = {}
|
|
191
|
+
self.lock = threading.RLock()
|
|
192
|
+
|
|
193
|
+
def get(self, key: str) -> Optional[Any]:
|
|
194
|
+
"""Get item if not expired"""
|
|
195
|
+
with self.lock:
|
|
196
|
+
if key in self.cache:
|
|
197
|
+
timestamp, ttl = self.timestamps[key]
|
|
198
|
+
if time.time() - timestamp < ttl:
|
|
199
|
+
return self.cache[key]
|
|
200
|
+
else:
|
|
201
|
+
# Expired
|
|
202
|
+
del self.cache[key]
|
|
203
|
+
del self.timestamps[key]
|
|
204
|
+
return None
|
|
205
|
+
|
|
206
|
+
def set(self, key: str, value: Any, ttl: int = 300) -> None:
|
|
207
|
+
"""Set item with TTL"""
|
|
208
|
+
with self.lock:
|
|
209
|
+
# Evict if at capacity and key is new
|
|
210
|
+
if key not in self.cache and len(self.cache) >= self.max_size:
|
|
211
|
+
# Remove oldest entry
|
|
212
|
+
oldest_key = min(self.timestamps.keys(), key=lambda k: self.timestamps[k][0])
|
|
213
|
+
del self.cache[oldest_key]
|
|
214
|
+
del self.timestamps[oldest_key]
|
|
215
|
+
|
|
216
|
+
self.cache[key] = value
|
|
217
|
+
self.timestamps[key] = (time.time(), ttl)
|
|
218
|
+
|
|
219
|
+
def delete(self, key: str) -> bool:
|
|
220
|
+
"""Delete item"""
|
|
221
|
+
with self.lock:
|
|
222
|
+
if key in self.cache:
|
|
223
|
+
del self.cache[key]
|
|
224
|
+
del self.timestamps[key]
|
|
225
|
+
return True
|
|
226
|
+
return False
|
|
227
|
+
|
|
228
|
+
def cleanup_expired(self) -> int:
|
|
229
|
+
"""Remove expired items"""
|
|
230
|
+
with self.lock:
|
|
231
|
+
current_time = time.time()
|
|
232
|
+
expired_keys = []
|
|
233
|
+
|
|
234
|
+
for key, (timestamp, ttl) in self.timestamps.items():
|
|
235
|
+
if current_time - timestamp >= ttl:
|
|
236
|
+
expired_keys.append(key)
|
|
237
|
+
|
|
238
|
+
for key in expired_keys:
|
|
239
|
+
del self.cache[key]
|
|
240
|
+
del self.timestamps[key]
|
|
241
|
+
|
|
242
|
+
return len(expired_keys)
|
|
243
|
+
|
|
244
|
+
def clear(self) -> None:
|
|
245
|
+
"""Clear all items"""
|
|
246
|
+
with self.lock:
|
|
247
|
+
self.cache.clear()
|
|
248
|
+
self.timestamps.clear()
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
class DiskCache:
|
|
252
|
+
"""Simple disk-based cache for large items"""
|
|
253
|
+
|
|
254
|
+
def __init__(self, cache_dir: str = "/tmp/createsonline_cache"):
|
|
255
|
+
self.cache_dir = cache_dir
|
|
256
|
+
self.index = {}
|
|
257
|
+
self.lock = threading.RLock()
|
|
258
|
+
|
|
259
|
+
# Create cache directory
|
|
260
|
+
import os
|
|
261
|
+
os.makedirs(cache_dir, exist_ok=True)
|
|
262
|
+
|
|
263
|
+
def get(self, key: str) -> Optional[Any]:
|
|
264
|
+
"""Get item from disk cache"""
|
|
265
|
+
with self.lock:
|
|
266
|
+
if key in self.index:
|
|
267
|
+
timestamp, ttl, filename = self.index[key]
|
|
268
|
+
|
|
269
|
+
if time.time() - timestamp < ttl:
|
|
270
|
+
try:
|
|
271
|
+
import pickle
|
|
272
|
+
with open(filename, 'rb') as f:
|
|
273
|
+
return pickle.load(f)
|
|
274
|
+
except:
|
|
275
|
+
# File corrupted or missing
|
|
276
|
+
del self.index[key]
|
|
277
|
+
else:
|
|
278
|
+
# Expired
|
|
279
|
+
self._remove_file(filename)
|
|
280
|
+
del self.index[key]
|
|
281
|
+
|
|
282
|
+
return None
|
|
283
|
+
|
|
284
|
+
def set(self, key: str, value: Any, ttl: int = 3600) -> None:
|
|
285
|
+
"""Set item to disk cache"""
|
|
286
|
+
with self.lock:
|
|
287
|
+
filename = f"{self.cache_dir}/{hashlib.md5(key.encode()).hexdigest()}.cache"
|
|
288
|
+
|
|
289
|
+
try:
|
|
290
|
+
import pickle
|
|
291
|
+
with open(filename, 'wb') as f:
|
|
292
|
+
pickle.dump(value, f)
|
|
293
|
+
|
|
294
|
+
self.index[key] = (time.time(), ttl, filename)
|
|
295
|
+
except:
|
|
296
|
+
# Failed to write
|
|
297
|
+
pass
|
|
298
|
+
|
|
299
|
+
def delete(self, key: str) -> bool:
|
|
300
|
+
"""Delete item from disk cache"""
|
|
301
|
+
with self.lock:
|
|
302
|
+
if key in self.index:
|
|
303
|
+
_, _, filename = self.index[key]
|
|
304
|
+
self._remove_file(filename)
|
|
305
|
+
del self.index[key]
|
|
306
|
+
return True
|
|
307
|
+
return False
|
|
308
|
+
|
|
309
|
+
def size(self) -> int:
|
|
310
|
+
"""Get number of cached items"""
|
|
311
|
+
return len(self.index)
|
|
312
|
+
|
|
313
|
+
def cleanup_expired(self) -> int:
|
|
314
|
+
"""Remove expired disk cache files"""
|
|
315
|
+
with self.lock:
|
|
316
|
+
current_time = time.time()
|
|
317
|
+
expired_keys = []
|
|
318
|
+
|
|
319
|
+
for key, (timestamp, ttl, filename) in self.index.items():
|
|
320
|
+
if current_time - timestamp >= ttl:
|
|
321
|
+
expired_keys.append(key)
|
|
322
|
+
self._remove_file(filename)
|
|
323
|
+
|
|
324
|
+
for key in expired_keys:
|
|
325
|
+
del self.index[key]
|
|
326
|
+
|
|
327
|
+
return len(expired_keys)
|
|
328
|
+
|
|
329
|
+
def _remove_file(self, filename: str) -> None:
|
|
330
|
+
"""Safely remove cache file"""
|
|
331
|
+
try:
|
|
332
|
+
import os
|
|
333
|
+
os.remove(filename)
|
|
334
|
+
except:
|
|
335
|
+
pass
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
class CacheStats:
|
|
339
|
+
"""Track cache performance statistics"""
|
|
340
|
+
|
|
341
|
+
def __init__(self):
|
|
342
|
+
self.hits = {'l1': 0, 'l2': 0, 'l3': 0}
|
|
343
|
+
self.misses = 0
|
|
344
|
+
self.sets = 0
|
|
345
|
+
self.deletes = 0
|
|
346
|
+
self.start_time = time.time()
|
|
347
|
+
self.lock = threading.RLock()
|
|
348
|
+
|
|
349
|
+
def record_hit(self, layer: str) -> None:
|
|
350
|
+
"""Record cache hit"""
|
|
351
|
+
with self.lock:
|
|
352
|
+
self.hits[layer] += 1
|
|
353
|
+
|
|
354
|
+
def record_miss(self) -> None:
|
|
355
|
+
"""Record cache miss"""
|
|
356
|
+
with self.lock:
|
|
357
|
+
self.misses += 1
|
|
358
|
+
|
|
359
|
+
def record_set(self) -> None:
|
|
360
|
+
"""Record cache set"""
|
|
361
|
+
with self.lock:
|
|
362
|
+
self.sets += 1
|
|
363
|
+
|
|
364
|
+
def record_delete(self) -> None:
|
|
365
|
+
"""Record cache delete"""
|
|
366
|
+
with self.lock:
|
|
367
|
+
self.deletes += 1
|
|
368
|
+
|
|
369
|
+
def get_hit_rates(self) -> Dict[str, float]:
|
|
370
|
+
"""Get hit rates by layer"""
|
|
371
|
+
with self.lock:
|
|
372
|
+
total_hits = sum(self.hits.values())
|
|
373
|
+
total_requests = total_hits + self.misses
|
|
374
|
+
|
|
375
|
+
if total_requests == 0:
|
|
376
|
+
return {'overall': 0.0, 'l1': 0.0, 'l2': 0.0, 'l3': 0.0}
|
|
377
|
+
|
|
378
|
+
return {
|
|
379
|
+
'overall': total_hits / total_requests * 100,
|
|
380
|
+
'l1': self.hits['l1'] / total_requests * 100,
|
|
381
|
+
'l2': self.hits['l2'] / total_requests * 100,
|
|
382
|
+
'l3': self.hits['l3'] / total_requests * 100
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
def get_performance_metrics(self) -> Dict[str, Any]:
|
|
386
|
+
"""Get performance metrics"""
|
|
387
|
+
with self.lock:
|
|
388
|
+
uptime = time.time() - self.start_time
|
|
389
|
+
total_ops = sum(self.hits.values()) + self.misses + self.sets + self.deletes
|
|
390
|
+
|
|
391
|
+
return {
|
|
392
|
+
'uptime_seconds': uptime,
|
|
393
|
+
'total_operations': total_ops,
|
|
394
|
+
'operations_per_second': total_ops / uptime if uptime > 0 else 0,
|
|
395
|
+
'total_hits': sum(self.hits.values()),
|
|
396
|
+
'total_misses': self.misses,
|
|
397
|
+
'total_sets': self.sets,
|
|
398
|
+
'total_deletes': self.deletes
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
def reset(self) -> None:
|
|
402
|
+
"""Reset all statistics"""
|
|
403
|
+
with self.lock:
|
|
404
|
+
self.hits = {'l1': 0, 'l2': 0, 'l3': 0}
|
|
405
|
+
self.misses = 0
|
|
406
|
+
self.sets = 0
|
|
407
|
+
self.deletes = 0
|
|
408
|
+
self.start_time = time.time()
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
# Global cache instance
|
|
412
|
+
_global_cache = None
|
|
413
|
+
|
|
414
|
+
def get_cache() -> CacheManager:
|
|
415
|
+
"""Get global cache instance"""
|
|
416
|
+
global _global_cache
|
|
417
|
+
if _global_cache is None:
|
|
418
|
+
_global_cache = CacheManager()
|
|
419
|
+
return _global_cache
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
def cache(ttl: int = 300, key_prefix: str = ""):
|
|
423
|
+
"""Decorator for caching function results"""
|
|
424
|
+
|
|
425
|
+
def decorator(func: Callable):
|
|
426
|
+
def wrapper(*args, **kwargs):
|
|
427
|
+
# Generate cache key
|
|
428
|
+
cache_key = f"{key_prefix}{func.__name__}:{hash((args, tuple(sorted(kwargs.items()))))}"
|
|
429
|
+
|
|
430
|
+
# Try to get from cache
|
|
431
|
+
cache_manager = get_cache()
|
|
432
|
+
result = cache_manager.get(cache_key)
|
|
433
|
+
|
|
434
|
+
if result is not None:
|
|
435
|
+
return result
|
|
436
|
+
|
|
437
|
+
# Execute function and cache result
|
|
438
|
+
result = func(*args, **kwargs)
|
|
439
|
+
cache_manager.set(cache_key, result, ttl)
|
|
440
|
+
return result
|
|
441
|
+
|
|
442
|
+
return wrapper
|
|
443
|
+
return decorator
|
|
444
|
+
|