lqft-python-engine 0.1.9__tar.gz → 0.3.0__tar.gz
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.
- {lqft_python_engine-0.1.9 → lqft_python_engine-0.3.0}/PKG-INFO +2 -2
- {lqft_python_engine-0.1.9 → lqft_python_engine-0.3.0}/lqft_engine.c +129 -38
- {lqft_python_engine-0.1.9 → lqft_python_engine-0.3.0}/lqft_engine.py +68 -30
- {lqft_python_engine-0.1.9 → lqft_python_engine-0.3.0}/lqft_python_engine.egg-info/PKG-INFO +2 -2
- {lqft_python_engine-0.1.9 → lqft_python_engine-0.3.0}/setup.py +2 -2
- {lqft_python_engine-0.1.9 → lqft_python_engine-0.3.0}/LICENSE.md +0 -0
- {lqft_python_engine-0.1.9 → lqft_python_engine-0.3.0}/lqft_python_engine.egg-info/SOURCES.txt +0 -0
- {lqft_python_engine-0.1.9 → lqft_python_engine-0.3.0}/lqft_python_engine.egg-info/dependency_links.txt +0 -0
- {lqft_python_engine-0.1.9 → lqft_python_engine-0.3.0}/lqft_python_engine.egg-info/requires.txt +0 -0
- {lqft_python_engine-0.1.9 → lqft_python_engine-0.3.0}/lqft_python_engine.egg-info/top_level.txt +0 -0
- {lqft_python_engine-0.1.9 → lqft_python_engine-0.3.0}/pure_python_ds.py +0 -0
- {lqft_python_engine-0.1.9 → lqft_python_engine-0.3.0}/pyproject.toml +0 -0
- {lqft_python_engine-0.1.9 → lqft_python_engine-0.3.0}/setup.cfg +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lqft-python-engine
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary: LQFT Engine:
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: LQFT Engine: Memory Circuit Breaker & Strict Type Safety (v5.0 Stable)
|
|
5
5
|
Home-page: https://github.com/ParjadM/Log-Quantum-Fractal-Tree-LQFT-
|
|
6
6
|
Author: Parjad Minooei
|
|
7
7
|
License: MIT
|
|
@@ -11,24 +11,28 @@
|
|
|
11
11
|
#include <stdint.h>
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
* LQFT C-Engine -
|
|
14
|
+
* LQFT C-Engine - V5.0 (Active ARC Deletion & Full CRUD)
|
|
15
15
|
* Architect: Parjad Minooei
|
|
16
16
|
* * CHANGE LOG:
|
|
17
|
-
* -
|
|
18
|
-
* -
|
|
19
|
-
* -
|
|
17
|
+
* - Implemented Automatic Reference Counting (ARC).
|
|
18
|
+
* - Added cascading `decref` for immediate RAM reclamation on deletion.
|
|
19
|
+
* - Added Open-Addressing Tombstones to the Global Registry.
|
|
20
|
+
* - Resolved all GCC -Wsign-compare warnings for production-grade builds.
|
|
20
21
|
*/
|
|
21
22
|
|
|
22
23
|
#define BIT_PARTITION 5
|
|
23
24
|
#define MAX_BITS 64
|
|
24
25
|
#define MASK 0x1F
|
|
25
26
|
#define REGISTRY_SIZE 8000009
|
|
27
|
+
#define TOMBSTONE ((LQFTNode*)1) // Special pointer for freed registry slots
|
|
26
28
|
|
|
27
29
|
typedef struct LQFTNode {
|
|
28
30
|
void* value;
|
|
29
31
|
uint64_t key_hash;
|
|
30
32
|
struct LQFTNode* children[32];
|
|
31
33
|
char struct_hash[17];
|
|
34
|
+
uint64_t full_hash_val; // Cached for O(1) registry removal
|
|
35
|
+
int ref_count; // Tracks active branch dependencies
|
|
32
36
|
} LQFTNode;
|
|
33
37
|
|
|
34
38
|
static LQFTNode** registry = NULL;
|
|
@@ -38,6 +42,9 @@ static LQFTNode* global_root = NULL;
|
|
|
38
42
|
const uint64_t FNV_OFFSET_BASIS = 14695981039346656037ULL;
|
|
39
43
|
const uint64_t FNV_PRIME = 1099511628211ULL;
|
|
40
44
|
|
|
45
|
+
// -------------------------------------------------------------------
|
|
46
|
+
// Core Hashing & Memory Utilities
|
|
47
|
+
// -------------------------------------------------------------------
|
|
41
48
|
uint64_t fnv1a_update(uint64_t hash, const void* data, size_t len) {
|
|
42
49
|
const uint8_t* p = (const uint8_t*)data;
|
|
43
50
|
for (size_t i = 0; i < len; i++) {
|
|
@@ -69,10 +76,52 @@ LQFTNode* create_node(void* value, uint64_t key_hash) {
|
|
|
69
76
|
if (!node) return NULL;
|
|
70
77
|
node->value = value;
|
|
71
78
|
node->key_hash = key_hash;
|
|
79
|
+
node->full_hash_val = 0;
|
|
80
|
+
node->ref_count = 0; // Starts at 0 until adopted by a parent
|
|
72
81
|
for (int i = 0; i < 32; i++) node->children[i] = NULL;
|
|
73
82
|
return node;
|
|
74
83
|
}
|
|
75
84
|
|
|
85
|
+
// -------------------------------------------------------------------
|
|
86
|
+
// Active ARC Deletion Logic
|
|
87
|
+
// -------------------------------------------------------------------
|
|
88
|
+
void decref(LQFTNode* node) {
|
|
89
|
+
if (!node) return;
|
|
90
|
+
|
|
91
|
+
node->ref_count--;
|
|
92
|
+
|
|
93
|
+
// If no branches point to this node anymore, obliterate it.
|
|
94
|
+
if (node->ref_count <= 0) {
|
|
95
|
+
// 1. Cascade destruction to children
|
|
96
|
+
for (int i = 0; i < 32; i++) {
|
|
97
|
+
if (node->children[i]) {
|
|
98
|
+
decref(node->children[i]);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// 2. Remove from global registry (Replace with Tombstone)
|
|
103
|
+
uint32_t idx = node->full_hash_val % REGISTRY_SIZE;
|
|
104
|
+
uint32_t start_idx = idx;
|
|
105
|
+
|
|
106
|
+
while (registry[idx] != NULL) {
|
|
107
|
+
if (registry[idx] == node) {
|
|
108
|
+
registry[idx] = TOMBSTONE;
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
idx = (idx + 1) % REGISTRY_SIZE;
|
|
112
|
+
if (idx == start_idx) break;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// 3. Physically free memory back to the OS
|
|
116
|
+
if (node->value) free(node->value);
|
|
117
|
+
free(node);
|
|
118
|
+
physical_node_count--;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// -------------------------------------------------------------------
|
|
123
|
+
// Merkle-DAG Deduplication
|
|
124
|
+
// -------------------------------------------------------------------
|
|
76
125
|
LQFTNode* get_canonical(void* value, uint64_t key_hash, LQFTNode** children) {
|
|
77
126
|
if (!init_registry()) return NULL;
|
|
78
127
|
|
|
@@ -97,27 +146,47 @@ LQFTNode* get_canonical(void* value, uint64_t key_hash, LQFTNode** children) {
|
|
|
97
146
|
sprintf(lookup_hash, "%016llx", (unsigned long long)full_hash);
|
|
98
147
|
uint32_t idx = full_hash % REGISTRY_SIZE;
|
|
99
148
|
uint32_t start_idx = idx;
|
|
149
|
+
int first_tombstone = -1;
|
|
100
150
|
|
|
151
|
+
// Search registry (Skipping Tomestones)
|
|
101
152
|
while (registry[idx] != NULL) {
|
|
102
|
-
if (
|
|
103
|
-
if (
|
|
153
|
+
if (registry[idx] == TOMBSTONE) {
|
|
154
|
+
if (first_tombstone == -1) first_tombstone = (int)idx;
|
|
155
|
+
} else if (registry[idx]->full_hash_val == full_hash && strcmp(registry[idx]->struct_hash, lookup_hash) == 0) {
|
|
156
|
+
if (value) free(value); // Free duplicate string payload
|
|
104
157
|
return registry[idx];
|
|
105
158
|
}
|
|
106
159
|
idx = (idx + 1) % REGISTRY_SIZE;
|
|
107
160
|
if (idx == start_idx) break;
|
|
108
161
|
}
|
|
109
162
|
|
|
163
|
+
// Create a physical new node if identity doesn't exist
|
|
110
164
|
LQFTNode* new_node = create_node(value, key_hash);
|
|
111
165
|
if (!new_node) return NULL;
|
|
166
|
+
|
|
112
167
|
if (children) {
|
|
113
|
-
for (int i = 0; i < 32; i++)
|
|
168
|
+
for (int i = 0; i < 32; i++) {
|
|
169
|
+
new_node->children[i] = children[i];
|
|
170
|
+
// Anchor the child to this new parent
|
|
171
|
+
if (children[i]) children[i]->ref_count++;
|
|
172
|
+
}
|
|
114
173
|
}
|
|
174
|
+
|
|
115
175
|
strcpy(new_node->struct_hash, lookup_hash);
|
|
116
|
-
|
|
176
|
+
new_node->full_hash_val = full_hash;
|
|
177
|
+
|
|
178
|
+
// Insert into registry (Reusing tombstones if possible)
|
|
179
|
+
// SYSTEM FIX: Explicitly cast first_tombstone to uint32_t to match idx
|
|
180
|
+
uint32_t insert_idx = (first_tombstone != -1) ? (uint32_t)first_tombstone : idx;
|
|
181
|
+
registry[insert_idx] = new_node;
|
|
117
182
|
physical_node_count++;
|
|
183
|
+
|
|
118
184
|
return new_node;
|
|
119
185
|
}
|
|
120
186
|
|
|
187
|
+
// -------------------------------------------------------------------
|
|
188
|
+
// Python Wrapper API
|
|
189
|
+
// -------------------------------------------------------------------
|
|
121
190
|
static PyObject* method_delete(PyObject* self, PyObject* args) {
|
|
122
191
|
unsigned long long h;
|
|
123
192
|
if (!PyArg_ParseTuple(args, "K", &h)) return NULL;
|
|
@@ -129,7 +198,6 @@ static PyObject* method_delete(PyObject* self, PyObject* args) {
|
|
|
129
198
|
LQFTNode* curr = global_root;
|
|
130
199
|
int bit_depth = 0;
|
|
131
200
|
|
|
132
|
-
// Trace path to target
|
|
133
201
|
while (curr != NULL && curr->value == NULL) {
|
|
134
202
|
uint32_t segment = (h >> bit_depth) & MASK;
|
|
135
203
|
path_nodes[path_len] = curr;
|
|
@@ -139,10 +207,10 @@ static PyObject* method_delete(PyObject* self, PyObject* args) {
|
|
|
139
207
|
bit_depth += BIT_PARTITION;
|
|
140
208
|
}
|
|
141
209
|
|
|
142
|
-
//
|
|
210
|
+
// Key not found, abort
|
|
143
211
|
if (curr == NULL || curr->key_hash != h) Py_RETURN_NONE;
|
|
144
212
|
|
|
145
|
-
|
|
213
|
+
LQFTNode* old_root = global_root;
|
|
146
214
|
LQFTNode* new_sub_node = NULL;
|
|
147
215
|
|
|
148
216
|
for (int i = path_len - 1; i >= 0; i--) {
|
|
@@ -151,7 +219,8 @@ static PyObject* method_delete(PyObject* self, PyObject* args) {
|
|
|
151
219
|
LQFTNode* new_children[32];
|
|
152
220
|
int has_other_children = 0;
|
|
153
221
|
|
|
154
|
-
|
|
222
|
+
// SYSTEM FIX: Use uint32_t for j to safely compare with segment
|
|
223
|
+
for (uint32_t j = 0; j < 32; j++) {
|
|
155
224
|
if (j == segment) new_children[j] = new_sub_node;
|
|
156
225
|
else {
|
|
157
226
|
new_children[j] = p_node->children[j];
|
|
@@ -159,31 +228,15 @@ static PyObject* method_delete(PyObject* self, PyObject* args) {
|
|
|
159
228
|
}
|
|
160
229
|
}
|
|
161
230
|
|
|
162
|
-
if (!has_other_children && i > 0)
|
|
163
|
-
|
|
164
|
-
} else {
|
|
165
|
-
new_sub_node = get_canonical(NULL, 0, new_children);
|
|
166
|
-
}
|
|
231
|
+
if (!has_other_children && i > 0) new_sub_node = NULL;
|
|
232
|
+
else new_sub_node = get_canonical(NULL, 0, new_children);
|
|
167
233
|
}
|
|
168
234
|
|
|
235
|
+
// Anchor new root and release the old one
|
|
169
236
|
global_root = (new_sub_node) ? new_sub_node : get_canonical(NULL, 0, NULL);
|
|
170
|
-
|
|
171
|
-
|
|
237
|
+
if (global_root) global_root->ref_count++;
|
|
238
|
+
if (old_root) decref(old_root); // Trigger Active Deletion Cascade
|
|
172
239
|
|
|
173
|
-
static PyObject* method_free_all(PyObject* self, PyObject* args) {
|
|
174
|
-
if (registry != NULL) {
|
|
175
|
-
for (int i = 0; i < REGISTRY_SIZE; i++) {
|
|
176
|
-
if (registry[i] != NULL) {
|
|
177
|
-
if (registry[i]->value) free(registry[i]->value);
|
|
178
|
-
free(registry[i]);
|
|
179
|
-
registry[i] = NULL;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
free(registry);
|
|
183
|
-
registry = NULL;
|
|
184
|
-
}
|
|
185
|
-
physical_node_count = 0;
|
|
186
|
-
global_root = NULL;
|
|
187
240
|
Py_RETURN_NONE;
|
|
188
241
|
}
|
|
189
242
|
|
|
@@ -191,15 +244,20 @@ static PyObject* method_insert(PyObject* self, PyObject* args) {
|
|
|
191
244
|
unsigned long long h;
|
|
192
245
|
char* val_str;
|
|
193
246
|
if (!PyArg_ParseTuple(args, "Ks", &h, &val_str)) return NULL;
|
|
247
|
+
|
|
194
248
|
if (!global_root) {
|
|
195
249
|
if (!init_registry()) return PyErr_NoMemory();
|
|
196
250
|
global_root = get_canonical(NULL, 0, NULL);
|
|
251
|
+
global_root->ref_count++;
|
|
197
252
|
}
|
|
253
|
+
|
|
254
|
+
LQFTNode* old_root = global_root;
|
|
198
255
|
LQFTNode* path_nodes[20];
|
|
199
256
|
uint32_t path_segs[20];
|
|
200
257
|
int path_len = 0;
|
|
201
258
|
LQFTNode* curr = global_root;
|
|
202
259
|
int bit_depth = 0;
|
|
260
|
+
|
|
203
261
|
while (curr != NULL && curr->value == NULL) {
|
|
204
262
|
uint32_t segment = (h >> bit_depth) & MASK;
|
|
205
263
|
path_nodes[path_len] = curr;
|
|
@@ -209,10 +267,13 @@ static PyObject* method_insert(PyObject* self, PyObject* args) {
|
|
|
209
267
|
curr = curr->children[segment];
|
|
210
268
|
bit_depth += BIT_PARTITION;
|
|
211
269
|
}
|
|
270
|
+
|
|
212
271
|
LQFTNode* new_sub_node = NULL;
|
|
213
|
-
if (curr == NULL) {
|
|
214
|
-
|
|
215
|
-
else {
|
|
272
|
+
if (curr == NULL) {
|
|
273
|
+
new_sub_node = get_canonical(portable_strdup(val_str), h, NULL);
|
|
274
|
+
} else if (curr->key_hash == h) {
|
|
275
|
+
new_sub_node = get_canonical(portable_strdup(val_str), h, curr->children);
|
|
276
|
+
} else {
|
|
216
277
|
unsigned long long old_h = curr->key_hash;
|
|
217
278
|
char* old_val = portable_strdup((char*)curr->value);
|
|
218
279
|
int temp_depth = bit_depth;
|
|
@@ -227,10 +288,16 @@ static PyObject* method_insert(PyObject* self, PyObject* args) {
|
|
|
227
288
|
new_children[s_new] = c_new;
|
|
228
289
|
new_sub_node = get_canonical(NULL, 0, new_children);
|
|
229
290
|
break;
|
|
230
|
-
} else {
|
|
291
|
+
} else {
|
|
292
|
+
path_nodes[path_len] = NULL;
|
|
293
|
+
path_segs[path_len] = s_old;
|
|
294
|
+
path_len++;
|
|
295
|
+
temp_depth += BIT_PARTITION;
|
|
296
|
+
}
|
|
231
297
|
}
|
|
232
298
|
if (new_sub_node == NULL) new_sub_node = get_canonical(portable_strdup(val_str), h, curr->children);
|
|
233
299
|
}
|
|
300
|
+
|
|
234
301
|
for (int i = path_len - 1; i >= 0; i--) {
|
|
235
302
|
if (path_nodes[i] == NULL) {
|
|
236
303
|
LQFTNode* new_children[32] = {NULL};
|
|
@@ -245,7 +312,12 @@ static PyObject* method_insert(PyObject* self, PyObject* args) {
|
|
|
245
312
|
new_sub_node = get_canonical(p_node->value, p_node->key_hash, new_children);
|
|
246
313
|
}
|
|
247
314
|
}
|
|
315
|
+
|
|
316
|
+
// Anchor new root and release the old one
|
|
248
317
|
global_root = new_sub_node;
|
|
318
|
+
global_root->ref_count++;
|
|
319
|
+
if (old_root) decref(old_root); // Trigger Active Deletion Cascade
|
|
320
|
+
|
|
249
321
|
Py_RETURN_NONE;
|
|
250
322
|
}
|
|
251
323
|
|
|
@@ -253,6 +325,7 @@ static PyObject* method_search(PyObject* self, PyObject* args) {
|
|
|
253
325
|
unsigned long long h;
|
|
254
326
|
if (!PyArg_ParseTuple(args, "K", &h)) return NULL;
|
|
255
327
|
if (!global_root) Py_RETURN_NONE;
|
|
328
|
+
|
|
256
329
|
LQFTNode* curr = global_root;
|
|
257
330
|
int bit_depth = 0;
|
|
258
331
|
while (curr != NULL && curr->value == NULL) {
|
|
@@ -260,17 +333,35 @@ static PyObject* method_search(PyObject* self, PyObject* args) {
|
|
|
260
333
|
curr = curr->children[segment];
|
|
261
334
|
bit_depth += BIT_PARTITION;
|
|
262
335
|
}
|
|
336
|
+
|
|
263
337
|
if (curr != NULL && curr->key_hash == h) return PyUnicode_FromString((char*)curr->value);
|
|
264
338
|
Py_RETURN_NONE;
|
|
265
339
|
}
|
|
266
340
|
|
|
341
|
+
static PyObject* method_free_all(PyObject* self, PyObject* args) {
|
|
342
|
+
if (registry != NULL) {
|
|
343
|
+
for (int i = 0; i < REGISTRY_SIZE; i++) {
|
|
344
|
+
if (registry[i] != NULL && registry[i] != TOMBSTONE) {
|
|
345
|
+
if (registry[i]->value) free(registry[i]->value);
|
|
346
|
+
free(registry[i]);
|
|
347
|
+
}
|
|
348
|
+
registry[i] = NULL;
|
|
349
|
+
}
|
|
350
|
+
free(registry);
|
|
351
|
+
registry = NULL;
|
|
352
|
+
}
|
|
353
|
+
physical_node_count = 0;
|
|
354
|
+
global_root = NULL;
|
|
355
|
+
Py_RETURN_NONE;
|
|
356
|
+
}
|
|
357
|
+
|
|
267
358
|
static PyObject* method_get_metrics(PyObject* self, PyObject* args) {
|
|
268
359
|
return Py_BuildValue("{s:i}", "physical_nodes", physical_node_count);
|
|
269
360
|
}
|
|
270
361
|
|
|
271
362
|
static PyMethodDef LQFTMethods[] = {
|
|
272
363
|
{"insert", method_insert, METH_VARARGS, "Insert key-value"},
|
|
273
|
-
{"delete", method_delete, METH_VARARGS, "Delete key"},
|
|
364
|
+
{"delete", method_delete, METH_VARARGS, "Active ARC Delete key"},
|
|
274
365
|
{"search", method_search, METH_VARARGS, "Search key"},
|
|
275
366
|
{"get_metrics", method_get_metrics, METH_VARARGS, "Get engine stats"},
|
|
276
367
|
{"free_all", method_free_all, METH_VARARGS, "Total memory wipe"},
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import hashlib
|
|
2
2
|
import weakref
|
|
3
|
+
import psutil
|
|
4
|
+
import os
|
|
3
5
|
|
|
4
6
|
# ---------------------------------------------------------
|
|
5
7
|
# LEGACY PURE PYTHON LQFT (For reference/fallback)
|
|
@@ -39,7 +41,6 @@ class LQFTNode:
|
|
|
39
41
|
return cls._null_cache['null']
|
|
40
42
|
|
|
41
43
|
class LQFT:
|
|
42
|
-
"""Legacy Pure Python Iterative Implementation."""
|
|
43
44
|
def __init__(self, bit_partition=5, max_bits=256):
|
|
44
45
|
self.partition = bit_partition
|
|
45
46
|
self.max_bits = max_bits
|
|
@@ -62,7 +63,7 @@ class LQFT:
|
|
|
62
63
|
break
|
|
63
64
|
curr = curr.children[segment]
|
|
64
65
|
bit_depth += self.partition
|
|
65
|
-
|
|
66
|
+
|
|
66
67
|
new_sub_node = None
|
|
67
68
|
if curr is null_node:
|
|
68
69
|
new_sub_node = LQFTNode.get_canonical(value, None, h)
|
|
@@ -82,7 +83,7 @@ class LQFT:
|
|
|
82
83
|
temp_depth += self.partition
|
|
83
84
|
if new_sub_node is None:
|
|
84
85
|
new_sub_node = LQFTNode.get_canonical(value, curr.children, h)
|
|
85
|
-
|
|
86
|
+
|
|
86
87
|
for entry in reversed(path):
|
|
87
88
|
if entry[0] == "split":
|
|
88
89
|
new_sub_node = LQFTNode.get_canonical(None, {entry[1]: new_sub_node}, None)
|
|
@@ -103,8 +104,9 @@ class LQFT:
|
|
|
103
104
|
if bit_depth >= self.max_bits: break
|
|
104
105
|
return None
|
|
105
106
|
|
|
107
|
+
|
|
106
108
|
# ---------------------------------------------------------
|
|
107
|
-
#
|
|
109
|
+
# ADAPTIVE ENTERPRISE ENGINE (v0.3.0)
|
|
108
110
|
# ---------------------------------------------------------
|
|
109
111
|
try:
|
|
110
112
|
import lqft_c_engine
|
|
@@ -115,21 +117,40 @@ except ImportError:
|
|
|
115
117
|
class AdaptiveLQFT:
|
|
116
118
|
"""
|
|
117
119
|
A polymorphic, heuristic-driven data structure wrapper.
|
|
118
|
-
- Scale <
|
|
119
|
-
- Scale >
|
|
120
|
+
- Scale < threshold: Acts as an ultra-lightweight C-Hash (Python Dict).
|
|
121
|
+
- Scale > threshold: Automatically migrates to the Native C-Engine LQFT
|
|
120
122
|
for Merkle-DAG deduplication and folding.
|
|
121
123
|
"""
|
|
122
124
|
def __init__(self, migration_threshold=50000):
|
|
123
125
|
self.threshold = migration_threshold
|
|
124
126
|
self.size = 0
|
|
125
127
|
self.is_native = False
|
|
126
|
-
|
|
127
|
-
# The "Mini Version": Python's highly optimized built-in dictionary
|
|
128
128
|
self._light_store = {}
|
|
129
|
+
|
|
130
|
+
# --- Systems Architecture: Process Memory Limit ---
|
|
131
|
+
self.auto_purge_enabled = True
|
|
132
|
+
# Instead of global OS RAM, we set a hard cap for THIS specific process.
|
|
133
|
+
self.max_memory_mb = 1000.0 # 1 Gigabyte Limit
|
|
134
|
+
self.total_ops = 0
|
|
135
|
+
self._process = psutil.Process(os.getpid())
|
|
136
|
+
|
|
137
|
+
def _validate_type(self, key, value=None):
|
|
138
|
+
"""Strict type guarding to prevent arbitrary objects from bleeding into C-Memory."""
|
|
139
|
+
if not isinstance(key, str):
|
|
140
|
+
raise TypeError(f"LQFT keys must be strings. Received: {type(key).__name__}")
|
|
141
|
+
if value is not None and not isinstance(value, str):
|
|
142
|
+
raise TypeError(f"LQFT values must be strings. Received: {type(value).__name__}")
|
|
129
143
|
|
|
130
144
|
def _get_64bit_hash(self, key):
|
|
131
145
|
"""Generates a 64-bit unsigned hash for the C-Engine."""
|
|
132
|
-
return int(hashlib.md5(
|
|
146
|
+
return int(hashlib.md5(key.encode()).hexdigest()[:16], 16)
|
|
147
|
+
|
|
148
|
+
def purge(self):
|
|
149
|
+
"""Manual Purge Override to instantly free RAM."""
|
|
150
|
+
current_mb = self._process.memory_info().rss / (1024 * 1024)
|
|
151
|
+
if current_mb >= self.max_memory_mb:
|
|
152
|
+
print(f"\n[⚠️ CIRCUIT Breaker] Engine exceeded {self.max_memory_mb} MB limit (Currently {current_mb:.1f} MB). Auto-Purging!")
|
|
153
|
+
self.clear()
|
|
133
154
|
|
|
134
155
|
def _migrate_to_native(self):
|
|
135
156
|
"""The 'Curve Flip' mechanism: moves all data to the Heavy Engine."""
|
|
@@ -142,58 +163,75 @@ class AdaptiveLQFT:
|
|
|
142
163
|
h = self._get_64bit_hash(key)
|
|
143
164
|
lqft_c_engine.insert(h, val)
|
|
144
165
|
|
|
145
|
-
# Clear the lightweight store to free up memory
|
|
146
166
|
self._light_store.clear()
|
|
147
167
|
self.is_native = True
|
|
148
168
|
|
|
149
169
|
def insert(self, key, value):
|
|
170
|
+
# 1. Type Guard (Blocks the Poison Pill test)
|
|
171
|
+
self._validate_type(key, value)
|
|
172
|
+
|
|
173
|
+
# 2. Performance Safety: Process Memory Check
|
|
174
|
+
self.total_ops += 1
|
|
175
|
+
if self.auto_purge_enabled and self.total_ops % 5000 == 0:
|
|
176
|
+
current_mb = self._process.memory_info().rss / (1024 * 1024)
|
|
177
|
+
if current_mb >= self.max_memory_mb:
|
|
178
|
+
self.purge()
|
|
179
|
+
|
|
150
180
|
if not self.is_native:
|
|
151
|
-
|
|
152
|
-
if key not in self._light_store:
|
|
181
|
+
if key not in self._light_store:
|
|
153
182
|
self.size += 1
|
|
154
183
|
self._light_store[key] = value
|
|
155
184
|
|
|
156
|
-
|
|
157
|
-
if self.size >= self.threshold:
|
|
185
|
+
if self.size >= self.threshold:
|
|
158
186
|
self._migrate_to_native()
|
|
159
187
|
else:
|
|
160
|
-
# Phase 2: Massive Data Operations (Native C-Heap)
|
|
161
188
|
h = self._get_64bit_hash(key)
|
|
162
189
|
lqft_c_engine.insert(h, value)
|
|
163
190
|
|
|
164
|
-
def
|
|
191
|
+
def remove(self, key):
|
|
192
|
+
self._validate_type(key)
|
|
193
|
+
|
|
165
194
|
if not self.is_native:
|
|
195
|
+
if key in self._light_store:
|
|
196
|
+
del self._light_store[key]
|
|
197
|
+
self.size -= 1
|
|
198
|
+
else:
|
|
199
|
+
h = self._get_64bit_hash(key)
|
|
200
|
+
lqft_c_engine.delete(h)
|
|
201
|
+
|
|
202
|
+
def delete(self, key):
|
|
203
|
+
self.remove(key)
|
|
204
|
+
|
|
205
|
+
def search(self, key):
|
|
206
|
+
self._validate_type(key)
|
|
207
|
+
|
|
208
|
+
if not self.is_native:
|
|
166
209
|
return self._light_store.get(key, None)
|
|
167
210
|
else:
|
|
168
211
|
h = self._get_64bit_hash(key)
|
|
169
212
|
return lqft_c_engine.search(h)
|
|
170
213
|
|
|
171
214
|
def clear(self):
|
|
172
|
-
"""
|
|
173
|
-
Memory Reclamation: Manually trigger C-level heap cleanup.
|
|
174
|
-
In the Adaptive model, this handles both the Python dict and the C-Registry.
|
|
175
|
-
"""
|
|
176
215
|
self._light_store.clear()
|
|
177
216
|
self.size = 0
|
|
178
|
-
if C_ENGINE_READY:
|
|
217
|
+
if C_ENGINE_READY:
|
|
179
218
|
return lqft_c_engine.free_all()
|
|
180
219
|
return 0
|
|
181
220
|
|
|
221
|
+
def get_stats(self):
|
|
222
|
+
if self.is_native and C_ENGINE_READY:
|
|
223
|
+
return lqft_c_engine.get_metrics()
|
|
224
|
+
return {"physical_nodes": 0}
|
|
225
|
+
|
|
182
226
|
def __del__(self):
|
|
183
|
-
|
|
184
|
-
Finalizer: Reclaims unmanaged C memory when the Python object is deleted.
|
|
185
|
-
Crucial for preventing memory leaks in long-running systems.
|
|
186
|
-
"""
|
|
187
|
-
try:
|
|
227
|
+
try:
|
|
188
228
|
self.clear()
|
|
189
|
-
except:
|
|
190
|
-
# Silence errors during late interpreter shutdown/garbage collection
|
|
229
|
+
except:
|
|
191
230
|
pass
|
|
192
231
|
|
|
193
232
|
def status(self):
|
|
194
|
-
"""Returns the current state of the engine."""
|
|
195
233
|
return {
|
|
196
234
|
"mode": "Native Merkle-DAG" if self.is_native else "Lightweight C-Hash",
|
|
197
|
-
"items": self.size,
|
|
235
|
+
"items": self.size if not self.is_native else lqft_c_engine.get_metrics().get('physical_nodes', self.size),
|
|
198
236
|
"threshold": self.threshold
|
|
199
237
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lqft-python-engine
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary: LQFT Engine:
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: LQFT Engine: Memory Circuit Breaker & Strict Type Safety (v5.0 Stable)
|
|
5
5
|
Home-page: https://github.com/ParjadM/Log-Quantum-Fractal-Tree-LQFT-
|
|
6
6
|
Author: Parjad Minooei
|
|
7
7
|
License: MIT
|
|
@@ -27,8 +27,8 @@ lqft_extension = Extension(
|
|
|
27
27
|
|
|
28
28
|
setup(
|
|
29
29
|
name="lqft-python-engine",
|
|
30
|
-
version="0.
|
|
31
|
-
description="LQFT Engine:
|
|
30
|
+
version="0.3.0",
|
|
31
|
+
description="LQFT Engine: Memory Circuit Breaker & Strict Type Safety (v5.0 Stable)",
|
|
32
32
|
long_description=long_description,
|
|
33
33
|
long_description_content_type="text/markdown",
|
|
34
34
|
author="Parjad Minooei",
|
|
File without changes
|
{lqft_python_engine-0.1.9 → lqft_python_engine-0.3.0}/lqft_python_engine.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{lqft_python_engine-0.1.9 → lqft_python_engine-0.3.0}/lqft_python_engine.egg-info/requires.txt
RENAMED
|
File without changes
|
{lqft_python_engine-0.1.9 → lqft_python_engine-0.3.0}/lqft_python_engine.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|