exonware-xwnode 0.0.1.12__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.
Files changed (132) hide show
  1. exonware/__init__.py +14 -0
  2. exonware/xwnode/__init__.py +127 -0
  3. exonware/xwnode/base.py +676 -0
  4. exonware/xwnode/config.py +178 -0
  5. exonware/xwnode/contracts.py +730 -0
  6. exonware/xwnode/errors.py +503 -0
  7. exonware/xwnode/facade.py +460 -0
  8. exonware/xwnode/strategies/__init__.py +158 -0
  9. exonware/xwnode/strategies/advisor.py +463 -0
  10. exonware/xwnode/strategies/edges/__init__.py +32 -0
  11. exonware/xwnode/strategies/edges/adj_list.py +227 -0
  12. exonware/xwnode/strategies/edges/adj_matrix.py +391 -0
  13. exonware/xwnode/strategies/edges/base.py +169 -0
  14. exonware/xwnode/strategies/flyweight.py +328 -0
  15. exonware/xwnode/strategies/impls/__init__.py +13 -0
  16. exonware/xwnode/strategies/impls/_base_edge.py +403 -0
  17. exonware/xwnode/strategies/impls/_base_node.py +307 -0
  18. exonware/xwnode/strategies/impls/edge_adj_list.py +353 -0
  19. exonware/xwnode/strategies/impls/edge_adj_matrix.py +445 -0
  20. exonware/xwnode/strategies/impls/edge_bidir_wrapper.py +455 -0
  21. exonware/xwnode/strategies/impls/edge_block_adj_matrix.py +539 -0
  22. exonware/xwnode/strategies/impls/edge_coo.py +533 -0
  23. exonware/xwnode/strategies/impls/edge_csc.py +447 -0
  24. exonware/xwnode/strategies/impls/edge_csr.py +492 -0
  25. exonware/xwnode/strategies/impls/edge_dynamic_adj_list.py +503 -0
  26. exonware/xwnode/strategies/impls/edge_flow_network.py +555 -0
  27. exonware/xwnode/strategies/impls/edge_hyperedge_set.py +516 -0
  28. exonware/xwnode/strategies/impls/edge_neural_graph.py +650 -0
  29. exonware/xwnode/strategies/impls/edge_octree.py +574 -0
  30. exonware/xwnode/strategies/impls/edge_property_store.py +655 -0
  31. exonware/xwnode/strategies/impls/edge_quadtree.py +519 -0
  32. exonware/xwnode/strategies/impls/edge_rtree.py +820 -0
  33. exonware/xwnode/strategies/impls/edge_temporal_edgeset.py +558 -0
  34. exonware/xwnode/strategies/impls/edge_tree_graph_basic.py +271 -0
  35. exonware/xwnode/strategies/impls/edge_weighted_graph.py +411 -0
  36. exonware/xwnode/strategies/manager.py +775 -0
  37. exonware/xwnode/strategies/metrics.py +538 -0
  38. exonware/xwnode/strategies/migration.py +432 -0
  39. exonware/xwnode/strategies/nodes/__init__.py +50 -0
  40. exonware/xwnode/strategies/nodes/_base_node.py +307 -0
  41. exonware/xwnode/strategies/nodes/adjacency_list.py +267 -0
  42. exonware/xwnode/strategies/nodes/aho_corasick.py +345 -0
  43. exonware/xwnode/strategies/nodes/array_list.py +209 -0
  44. exonware/xwnode/strategies/nodes/base.py +247 -0
  45. exonware/xwnode/strategies/nodes/deque.py +200 -0
  46. exonware/xwnode/strategies/nodes/hash_map.py +135 -0
  47. exonware/xwnode/strategies/nodes/heap.py +307 -0
  48. exonware/xwnode/strategies/nodes/linked_list.py +232 -0
  49. exonware/xwnode/strategies/nodes/node_aho_corasick.py +520 -0
  50. exonware/xwnode/strategies/nodes/node_array_list.py +175 -0
  51. exonware/xwnode/strategies/nodes/node_avl_tree.py +371 -0
  52. exonware/xwnode/strategies/nodes/node_b_plus_tree.py +542 -0
  53. exonware/xwnode/strategies/nodes/node_bitmap.py +420 -0
  54. exonware/xwnode/strategies/nodes/node_bitset_dynamic.py +513 -0
  55. exonware/xwnode/strategies/nodes/node_bloom_filter.py +347 -0
  56. exonware/xwnode/strategies/nodes/node_btree.py +357 -0
  57. exonware/xwnode/strategies/nodes/node_count_min_sketch.py +470 -0
  58. exonware/xwnode/strategies/nodes/node_cow_tree.py +473 -0
  59. exonware/xwnode/strategies/nodes/node_cuckoo_hash.py +392 -0
  60. exonware/xwnode/strategies/nodes/node_fenwick_tree.py +301 -0
  61. exonware/xwnode/strategies/nodes/node_hash_map.py +269 -0
  62. exonware/xwnode/strategies/nodes/node_heap.py +191 -0
  63. exonware/xwnode/strategies/nodes/node_hyperloglog.py +407 -0
  64. exonware/xwnode/strategies/nodes/node_linked_list.py +409 -0
  65. exonware/xwnode/strategies/nodes/node_lsm_tree.py +400 -0
  66. exonware/xwnode/strategies/nodes/node_ordered_map.py +390 -0
  67. exonware/xwnode/strategies/nodes/node_ordered_map_balanced.py +565 -0
  68. exonware/xwnode/strategies/nodes/node_patricia.py +512 -0
  69. exonware/xwnode/strategies/nodes/node_persistent_tree.py +378 -0
  70. exonware/xwnode/strategies/nodes/node_radix_trie.py +452 -0
  71. exonware/xwnode/strategies/nodes/node_red_black_tree.py +497 -0
  72. exonware/xwnode/strategies/nodes/node_roaring_bitmap.py +570 -0
  73. exonware/xwnode/strategies/nodes/node_segment_tree.py +289 -0
  74. exonware/xwnode/strategies/nodes/node_set_hash.py +354 -0
  75. exonware/xwnode/strategies/nodes/node_set_tree.py +480 -0
  76. exonware/xwnode/strategies/nodes/node_skip_list.py +316 -0
  77. exonware/xwnode/strategies/nodes/node_splay_tree.py +393 -0
  78. exonware/xwnode/strategies/nodes/node_suffix_array.py +487 -0
  79. exonware/xwnode/strategies/nodes/node_treap.py +387 -0
  80. exonware/xwnode/strategies/nodes/node_tree_graph_hybrid.py +1434 -0
  81. exonware/xwnode/strategies/nodes/node_trie.py +252 -0
  82. exonware/xwnode/strategies/nodes/node_union_find.py +187 -0
  83. exonware/xwnode/strategies/nodes/node_xdata_optimized.py +369 -0
  84. exonware/xwnode/strategies/nodes/priority_queue.py +209 -0
  85. exonware/xwnode/strategies/nodes/queue.py +161 -0
  86. exonware/xwnode/strategies/nodes/sparse_matrix.py +206 -0
  87. exonware/xwnode/strategies/nodes/stack.py +152 -0
  88. exonware/xwnode/strategies/nodes/trie.py +274 -0
  89. exonware/xwnode/strategies/nodes/union_find.py +283 -0
  90. exonware/xwnode/strategies/pattern_detector.py +603 -0
  91. exonware/xwnode/strategies/performance_monitor.py +487 -0
  92. exonware/xwnode/strategies/queries/__init__.py +24 -0
  93. exonware/xwnode/strategies/queries/base.py +236 -0
  94. exonware/xwnode/strategies/queries/cql.py +201 -0
  95. exonware/xwnode/strategies/queries/cypher.py +181 -0
  96. exonware/xwnode/strategies/queries/datalog.py +70 -0
  97. exonware/xwnode/strategies/queries/elastic_dsl.py +70 -0
  98. exonware/xwnode/strategies/queries/eql.py +70 -0
  99. exonware/xwnode/strategies/queries/flux.py +70 -0
  100. exonware/xwnode/strategies/queries/gql.py +70 -0
  101. exonware/xwnode/strategies/queries/graphql.py +240 -0
  102. exonware/xwnode/strategies/queries/gremlin.py +181 -0
  103. exonware/xwnode/strategies/queries/hiveql.py +214 -0
  104. exonware/xwnode/strategies/queries/hql.py +70 -0
  105. exonware/xwnode/strategies/queries/jmespath.py +219 -0
  106. exonware/xwnode/strategies/queries/jq.py +66 -0
  107. exonware/xwnode/strategies/queries/json_query.py +66 -0
  108. exonware/xwnode/strategies/queries/jsoniq.py +248 -0
  109. exonware/xwnode/strategies/queries/kql.py +70 -0
  110. exonware/xwnode/strategies/queries/linq.py +238 -0
  111. exonware/xwnode/strategies/queries/logql.py +70 -0
  112. exonware/xwnode/strategies/queries/mql.py +68 -0
  113. exonware/xwnode/strategies/queries/n1ql.py +210 -0
  114. exonware/xwnode/strategies/queries/partiql.py +70 -0
  115. exonware/xwnode/strategies/queries/pig.py +215 -0
  116. exonware/xwnode/strategies/queries/promql.py +70 -0
  117. exonware/xwnode/strategies/queries/sparql.py +220 -0
  118. exonware/xwnode/strategies/queries/sql.py +275 -0
  119. exonware/xwnode/strategies/queries/xml_query.py +66 -0
  120. exonware/xwnode/strategies/queries/xpath.py +223 -0
  121. exonware/xwnode/strategies/queries/xquery.py +258 -0
  122. exonware/xwnode/strategies/queries/xwnode_executor.py +332 -0
  123. exonware/xwnode/strategies/queries/xwquery_strategy.py +424 -0
  124. exonware/xwnode/strategies/registry.py +604 -0
  125. exonware/xwnode/strategies/simple.py +273 -0
  126. exonware/xwnode/strategies/utils.py +532 -0
  127. exonware/xwnode/types.py +912 -0
  128. exonware/xwnode/version.py +78 -0
  129. exonware_xwnode-0.0.1.12.dist-info/METADATA +169 -0
  130. exonware_xwnode-0.0.1.12.dist-info/RECORD +132 -0
  131. exonware_xwnode-0.0.1.12.dist-info/WHEEL +4 -0
  132. exonware_xwnode-0.0.1.12.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,400 @@
1
+ """
2
+ LSM Tree Node Strategy Implementation
3
+
4
+ This module implements the LSM_TREE strategy for write-heavy workloads
5
+ with eventual consistency and compaction.
6
+ """
7
+
8
+ from typing import Any, Iterator, Dict, List, Optional, Tuple
9
+ import time
10
+ import threading
11
+ from collections import defaultdict
12
+ from .base import ANodeTreeStrategy
13
+ from ...types import NodeMode, NodeTrait
14
+
15
+
16
+ class MemTable:
17
+ """In-memory table for LSM tree."""
18
+
19
+ def __init__(self, max_size: int = 1000):
20
+ self.data: Dict[str, Tuple[Any, float]] = {} # key -> (value, timestamp)
21
+ self.max_size = max_size
22
+ self.size = 0
23
+
24
+ def put(self, key: str, value: Any) -> bool:
25
+ """Put value, returns True if table is now full."""
26
+ self.data[key] = (value, time.time())
27
+ if key not in self.data:
28
+ self.size += 1
29
+ return self.size >= self.max_size
30
+
31
+ def get(self, key: str) -> Optional[Tuple[Any, float]]:
32
+ """Get value and timestamp."""
33
+ return self.data.get(key)
34
+
35
+ def has(self, key: str) -> bool:
36
+ """Check if key exists."""
37
+ return key in self.data
38
+
39
+ def remove(self, key: str) -> bool:
40
+ """Remove key (tombstone)."""
41
+ if key in self.data:
42
+ self.data[key] = (None, time.time()) # Tombstone
43
+ return True
44
+ return False
45
+
46
+ def items(self) -> Iterator[Tuple[str, Tuple[Any, float]]]:
47
+ """Get all items."""
48
+ return iter(self.data.items())
49
+
50
+ def clear(self) -> None:
51
+ """Clear all data."""
52
+ self.data.clear()
53
+ self.size = 0
54
+
55
+
56
+ class SSTable:
57
+ """Sorted String Table for LSM tree."""
58
+
59
+ def __init__(self, level: int, data: Dict[str, Tuple[Any, float]]):
60
+ self.level = level
61
+ self.data = dict(sorted(data.items())) # Keep sorted
62
+ self.creation_time = time.time()
63
+ self.size = len(data)
64
+
65
+ def get(self, key: str) -> Optional[Tuple[Any, float]]:
66
+ """Get value and timestamp."""
67
+ return self.data.get(key)
68
+
69
+ def has(self, key: str) -> bool:
70
+ """Check if key exists."""
71
+ return key in self.data
72
+
73
+ def items(self) -> Iterator[Tuple[str, Tuple[Any, float]]]:
74
+ """Get all items in sorted order."""
75
+ return iter(self.data.items())
76
+
77
+ def keys(self) -> Iterator[str]:
78
+ """Get all keys in sorted order."""
79
+ return iter(self.data.keys())
80
+
81
+ def range_query(self, start_key: str, end_key: str) -> List[Tuple[str, Any, float]]:
82
+ """Query range [start_key, end_key]."""
83
+ result = []
84
+ for key, (value, timestamp) in self.data.items():
85
+ if start_key <= key <= end_key and value is not None: # Skip tombstones
86
+ result.append((key, value, timestamp))
87
+ return result
88
+
89
+
90
+ class LSMTreeStrategy(ANodeTreeStrategy):
91
+ """
92
+ LSM Tree node strategy for write-heavy workloads.
93
+
94
+ Provides excellent write performance with eventual read consistency
95
+ through in-memory memtables and sorted disk-based SSTables.
96
+ """
97
+
98
+ def __init__(self, traits: NodeTrait = NodeTrait.NONE, **options):
99
+ """Initialize the LSM Tree strategy."""
100
+ super().__init__(NodeMode.LSM_TREE, traits, **options)
101
+
102
+ self.memtable_size = options.get('memtable_size', 1000)
103
+ self.max_levels = options.get('max_levels', 7)
104
+ self.level_multiplier = options.get('level_multiplier', 10)
105
+
106
+ # Storage components
107
+ self.memtable = MemTable(self.memtable_size)
108
+ self.immutable_memtables: List[MemTable] = []
109
+ self.sstables: Dict[int, List[SSTable]] = defaultdict(list)
110
+ self._values: Dict[str, Any] = {} # Direct key-value cache for fast access
111
+
112
+ # Compaction control
113
+ self._compaction_lock = threading.RLock()
114
+ self._background_compaction = options.get('background_compaction', False)
115
+ self._last_compaction = time.time()
116
+
117
+ self._size = 0
118
+
119
+ def get_supported_traits(self) -> NodeTrait:
120
+ """Get the traits supported by the LSM tree strategy."""
121
+ return (NodeTrait.ORDERED | NodeTrait.STREAMING | NodeTrait.PERSISTENT)
122
+
123
+ # ============================================================================
124
+ # CORE OPERATIONS (Key-based interface for compatibility)
125
+ # ============================================================================
126
+
127
+ def put(self, key: Any, value: Any = None) -> None:
128
+ """Store a value (optimized for writes)."""
129
+ key_str = str(key)
130
+
131
+ # Always write to active memtable first
132
+ was_new_key = key_str not in self._values
133
+
134
+ if self.memtable.put(key_str, value):
135
+ # Memtable is full, flush to L0
136
+ self._flush_memtable()
137
+
138
+ # Update our direct storage too for consistency
139
+ self._values[key_str] = value
140
+
141
+ if was_new_key:
142
+ self._size += 1
143
+
144
+ def get(self, key: Any, default: Any = None) -> Any:
145
+ """Retrieve a value (may involve multiple lookups)."""
146
+ key_str = str(key)
147
+
148
+ # 1. Check active memtable first
149
+ result = self.memtable.get(key_str)
150
+ if result is not None:
151
+ value, timestamp = result
152
+ return value if value is not None else default
153
+
154
+ # 2. Check immutable memtables (newest first)
155
+ for memtable in reversed(self.immutable_memtables):
156
+ result = memtable.get(key_str)
157
+ if result is not None:
158
+ value, timestamp = result
159
+ return value if value is not None else default
160
+
161
+ # 3. Check SSTables from L0 down (newest first within each level)
162
+ for level in range(self.max_levels):
163
+ for sstable in reversed(self.sstables[level]):
164
+ result = sstable.get(key_str)
165
+ if result is not None:
166
+ value, timestamp = result
167
+ return value if value is not None else default
168
+
169
+ return default
170
+
171
+ def has(self, key: Any) -> bool:
172
+ """Check if key exists (may involve multiple lookups)."""
173
+ return str(key) in self._values
174
+
175
+ def remove(self, key: Any) -> bool:
176
+ """Remove value by key (writes tombstone)."""
177
+ key_str = str(key)
178
+
179
+ if not self.has(key_str):
180
+ return False
181
+
182
+ # Write tombstone to memtable
183
+ if self.memtable.put(key_str, None): # None = tombstone
184
+ self._flush_memtable()
185
+
186
+ # Remove from direct cache
187
+ del self._values[key_str]
188
+ self._size -= 1
189
+ return True
190
+
191
+ def delete(self, key: Any) -> bool:
192
+ """Remove value by key (alias for remove)."""
193
+ return self.remove(key)
194
+
195
+ def clear(self) -> None:
196
+ """Clear all data."""
197
+ with self._compaction_lock:
198
+ self.memtable.clear()
199
+ self.immutable_memtables.clear()
200
+ self.sstables.clear()
201
+ self._values.clear()
202
+ self._size = 0
203
+
204
+ def keys(self) -> Iterator[str]:
205
+ """Get all keys (merged from all levels)."""
206
+ seen_keys = set()
207
+
208
+ # Active memtable
209
+ for key, (value, _) in self.memtable.items():
210
+ if value is not None and key not in seen_keys:
211
+ seen_keys.add(key)
212
+ yield key
213
+
214
+ # Immutable memtables
215
+ for memtable in reversed(self.immutable_memtables):
216
+ for key, (value, _) in memtable.items():
217
+ if value is not None and key not in seen_keys:
218
+ seen_keys.add(key)
219
+ yield key
220
+
221
+ # SSTables
222
+ for level in range(self.max_levels):
223
+ for sstable in reversed(self.sstables[level]):
224
+ for key in sstable.keys():
225
+ if key not in seen_keys:
226
+ value, _ = sstable.get(key)
227
+ if value is not None:
228
+ seen_keys.add(key)
229
+ yield key
230
+
231
+ def values(self) -> Iterator[Any]:
232
+ """Get all values."""
233
+ for key in self.keys():
234
+ yield self.get(key)
235
+
236
+ def items(self) -> Iterator[tuple[str, Any]]:
237
+ """Get all key-value pairs."""
238
+ for key in self.keys():
239
+ yield (key, self.get(key))
240
+
241
+ def __len__(self) -> int:
242
+ """Get the number of items."""
243
+ return self._size
244
+
245
+ def to_native(self) -> Dict[str, Any]:
246
+ """Convert to native Python dict."""
247
+ return dict(self.items())
248
+
249
+ @property
250
+ def is_list(self) -> bool:
251
+ """This is not primarily a list strategy."""
252
+ return False
253
+
254
+ @property
255
+ def is_dict(self) -> bool:
256
+ """This is a dict-like strategy."""
257
+ return True
258
+
259
+ # ============================================================================
260
+ # LSM TREE SPECIFIC OPERATIONS
261
+ # ============================================================================
262
+
263
+ def _flush_memtable(self) -> None:
264
+ """Flush active memtable to L0."""
265
+ if self.memtable.size == 0:
266
+ return
267
+
268
+ with self._compaction_lock:
269
+ # Move active memtable to immutable
270
+ self.immutable_memtables.append(self.memtable)
271
+ self.memtable = MemTable(self.memtable_size)
272
+
273
+ # Create L0 SSTable from oldest immutable memtable
274
+ if self.immutable_memtables:
275
+ old_memtable = self.immutable_memtables.pop(0)
276
+ sstable = SSTable(0, old_memtable.data)
277
+ self.sstables[0].append(sstable)
278
+
279
+ # Trigger compaction if needed
280
+ self._maybe_compact()
281
+
282
+ def _maybe_compact(self) -> None:
283
+ """Check if compaction is needed and trigger it."""
284
+ # Simple compaction strategy: compact when level has too many SSTables
285
+ for level in range(self.max_levels - 1):
286
+ max_sstables = self.level_multiplier ** level
287
+ if len(self.sstables[level]) > max_sstables:
288
+ self._compact_level(level)
289
+ break
290
+
291
+ def _compact_level(self, level: int) -> None:
292
+ """Compact SSTables from level to level+1."""
293
+ if level >= self.max_levels - 1:
294
+ return
295
+
296
+ # Simple compaction: merge all SSTables in level
297
+ merged_data = {}
298
+
299
+ for sstable in self.sstables[level]:
300
+ for key, (value, timestamp) in sstable.items():
301
+ if key not in merged_data or timestamp > merged_data[key][1]:
302
+ merged_data[key] = (value, timestamp)
303
+
304
+ # Remove tombstones and create new SSTable
305
+ clean_data = {k: v for k, v in merged_data.items() if v[0] is not None}
306
+
307
+ if clean_data:
308
+ new_sstable = SSTable(level + 1, clean_data)
309
+ self.sstables[level + 1].append(new_sstable)
310
+
311
+ # Clear the compacted level
312
+ self.sstables[level].clear()
313
+
314
+ self._last_compaction = time.time()
315
+
316
+ def force_compaction(self) -> None:
317
+ """Force full compaction of all levels."""
318
+ with self._compaction_lock:
319
+ # Flush any pending memtables first
320
+ if self.memtable.size > 0:
321
+ self._flush_memtable()
322
+
323
+ # Compact each level
324
+ for level in range(self.max_levels - 1):
325
+ if self.sstables[level]:
326
+ self._compact_level(level)
327
+
328
+ def range_query(self, start_key: str, end_key: str) -> List[Tuple[str, Any]]:
329
+ """Efficient range query across all levels."""
330
+ result_map = {}
331
+
332
+ # Query all levels and merge results (newest wins)
333
+ for level in range(self.max_levels):
334
+ for sstable in self.sstables[level]:
335
+ for key, value, timestamp in sstable.range_query(start_key, end_key):
336
+ if key not in result_map or timestamp > result_map[key][1]:
337
+ result_map[key] = (value, timestamp)
338
+
339
+ # Return sorted results (excluding tombstones)
340
+ return [(k, v) for k, (v, _) in sorted(result_map.items()) if v is not None]
341
+
342
+ def get_level_stats(self) -> Dict[int, Dict[str, Any]]:
343
+ """Get statistics for each level."""
344
+ stats = {}
345
+ for level in range(self.max_levels):
346
+ sstables = self.sstables[level]
347
+ stats[level] = {
348
+ 'sstable_count': len(sstables),
349
+ 'total_keys': sum(sstable.size for sstable in sstables),
350
+ 'oldest_sstable': min((ss.creation_time for ss in sstables), default=0),
351
+ 'newest_sstable': max((ss.creation_time for ss in sstables), default=0)
352
+ }
353
+ return stats
354
+
355
+ def compact_if_needed(self) -> bool:
356
+ """Check and perform compaction if needed."""
357
+ # Compaction heuristics
358
+ total_sstables = sum(len(tables) for tables in self.sstables.values())
359
+ time_since_last = time.time() - self._last_compaction
360
+
361
+ if total_sstables > 50 or time_since_last > 300: # 5 minutes
362
+ self.force_compaction()
363
+ return True
364
+ return False
365
+
366
+ # ============================================================================
367
+ # PERFORMANCE CHARACTERISTICS
368
+ # ============================================================================
369
+
370
+ @property
371
+ def backend_info(self) -> Dict[str, Any]:
372
+ """Get backend implementation info."""
373
+ return {
374
+ 'strategy': 'LSM_TREE',
375
+ 'backend': 'Memtables + SSTables',
376
+ 'memtable_size': self.memtable_size,
377
+ 'max_levels': self.max_levels,
378
+ 'complexity': {
379
+ 'write': 'O(1) amortized',
380
+ 'read': 'O(log n) worst case',
381
+ 'range_query': 'O(log n + k)',
382
+ 'compaction': 'O(n)'
383
+ }
384
+ }
385
+
386
+ @property
387
+ def metrics(self) -> Dict[str, Any]:
388
+ """Get performance metrics."""
389
+ total_sstables = sum(len(tables) for tables in self.sstables.values())
390
+ memtable_utilization = self.memtable.size / self.memtable_size * 100
391
+
392
+ return {
393
+ 'size': self._size,
394
+ 'active_memtable_size': self.memtable.size,
395
+ 'immutable_memtables': len(self.immutable_memtables),
396
+ 'total_sstables': total_sstables,
397
+ 'memtable_utilization': f"{memtable_utilization:.1f}%",
398
+ 'last_compaction': self._last_compaction,
399
+ 'memory_usage': f"{(self.memtable.size + total_sstables * 500) * 24} bytes (estimated)"
400
+ }