lqft-python-engine 0.2.0__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.2.0 → lqft_python_engine-0.3.0}/PKG-INFO +2 -2
- {lqft_python_engine-0.2.0 → lqft_python_engine-0.3.0}/lqft_engine.c +129 -38
- {lqft_python_engine-0.2.0 → lqft_python_engine-0.3.0}/lqft_engine.py +58 -36
- {lqft_python_engine-0.2.0 → lqft_python_engine-0.3.0}/lqft_python_engine.egg-info/PKG-INFO +2 -2
- {lqft_python_engine-0.2.0 → lqft_python_engine-0.3.0}/setup.py +2 -2
- {lqft_python_engine-0.2.0 → lqft_python_engine-0.3.0}/LICENSE.md +0 -0
- {lqft_python_engine-0.2.0 → lqft_python_engine-0.3.0}/lqft_python_engine.egg-info/SOURCES.txt +0 -0
- {lqft_python_engine-0.2.0 → lqft_python_engine-0.3.0}/lqft_python_engine.egg-info/dependency_links.txt +0 -0
- {lqft_python_engine-0.2.0 → lqft_python_engine-0.3.0}/lqft_python_engine.egg-info/requires.txt +0 -0
- {lqft_python_engine-0.2.0 → lqft_python_engine-0.3.0}/lqft_python_engine.egg-info/top_level.txt +0 -0
- {lqft_python_engine-0.2.0 → lqft_python_engine-0.3.0}/pure_python_ds.py +0 -0
- {lqft_python_engine-0.2.0 → lqft_python_engine-0.3.0}/pyproject.toml +0 -0
- {lqft_python_engine-0.2.0 → 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,8 +1,10 @@
|
|
|
1
1
|
import hashlib
|
|
2
2
|
import weakref
|
|
3
|
+
import psutil
|
|
4
|
+
import os
|
|
3
5
|
|
|
4
6
|
# ---------------------------------------------------------
|
|
5
|
-
# LEGACY PURE PYTHON LQFT (For reference/fallback
|
|
7
|
+
# LEGACY PURE PYTHON LQFT (For reference/fallback)
|
|
6
8
|
# ---------------------------------------------------------
|
|
7
9
|
class LQFTNode:
|
|
8
10
|
__slots__ = ['children', 'value', 'key_hash', 'struct_hash', '__weakref__']
|
|
@@ -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
|
|
@@ -123,13 +125,32 @@ class AdaptiveLQFT:
|
|
|
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."""
|
|
@@ -140,36 +161,36 @@ class AdaptiveLQFT:
|
|
|
140
161
|
|
|
141
162
|
for key, val in self._light_store.items():
|
|
142
163
|
h = self._get_64bit_hash(key)
|
|
143
|
-
lqft_c_engine.insert(h,
|
|
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
|
-
else:
|
|
160
|
-
# Phase 2: Massive Data Operations (Native C-Heap)
|
|
161
|
-
h = self._get_64bit_hash(key)
|
|
162
|
-
lqft_c_engine.insert(h, str(value))
|
|
163
|
-
|
|
164
|
-
def search(self, key):
|
|
165
|
-
if not self.is_native:
|
|
166
|
-
return self._light_store.get(key, None)
|
|
167
187
|
else:
|
|
168
188
|
h = self._get_64bit_hash(key)
|
|
169
|
-
|
|
189
|
+
lqft_c_engine.insert(h, value)
|
|
170
190
|
|
|
171
191
|
def remove(self, key):
|
|
172
|
-
|
|
192
|
+
self._validate_type(key)
|
|
193
|
+
|
|
173
194
|
if not self.is_native:
|
|
174
195
|
if key in self._light_store:
|
|
175
196
|
del self._light_store[key]
|
|
@@ -179,35 +200,36 @@ class AdaptiveLQFT:
|
|
|
179
200
|
lqft_c_engine.delete(h)
|
|
180
201
|
|
|
181
202
|
def delete(self, key):
|
|
182
|
-
"""Alias for remove to satisfy all testing suites."""
|
|
183
203
|
self.remove(key)
|
|
184
204
|
|
|
205
|
+
def search(self, key):
|
|
206
|
+
self._validate_type(key)
|
|
207
|
+
|
|
208
|
+
if not self.is_native:
|
|
209
|
+
return self._light_store.get(key, None)
|
|
210
|
+
else:
|
|
211
|
+
h = self._get_64bit_hash(key)
|
|
212
|
+
return lqft_c_engine.search(h)
|
|
213
|
+
|
|
185
214
|
def clear(self):
|
|
186
|
-
"""
|
|
187
|
-
Memory Reclamation: Manually trigger heap cleanup.
|
|
188
|
-
In the Adaptive model, this handles both the Python dict and the C-Registry.
|
|
189
|
-
"""
|
|
190
215
|
self._light_store.clear()
|
|
191
216
|
self.size = 0
|
|
192
|
-
if C_ENGINE_READY:
|
|
217
|
+
if C_ENGINE_READY:
|
|
193
218
|
return lqft_c_engine.free_all()
|
|
194
219
|
return 0
|
|
195
220
|
|
|
196
221
|
def get_stats(self):
|
|
197
|
-
|
|
198
|
-
if self.is_native and C_ENGINE_READY:
|
|
222
|
+
if self.is_native and C_ENGINE_READY:
|
|
199
223
|
return lqft_c_engine.get_metrics()
|
|
200
224
|
return {"physical_nodes": 0}
|
|
201
225
|
|
|
202
226
|
def __del__(self):
|
|
203
|
-
|
|
204
|
-
try:
|
|
227
|
+
try:
|
|
205
228
|
self.clear()
|
|
206
|
-
except:
|
|
229
|
+
except:
|
|
207
230
|
pass
|
|
208
231
|
|
|
209
232
|
def status(self):
|
|
210
|
-
"""Returns the current state of the engine."""
|
|
211
233
|
return {
|
|
212
234
|
"mode": "Native Merkle-DAG" if self.is_native else "Lightweight C-Hash",
|
|
213
235
|
"items": self.size if not self.is_native else lqft_c_engine.get_metrics().get('physical_nodes', self.size),
|
|
@@ -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.2.0 → lqft_python_engine-0.3.0}/lqft_python_engine.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{lqft_python_engine-0.2.0 → lqft_python_engine-0.3.0}/lqft_python_engine.egg-info/requires.txt
RENAMED
|
File without changes
|
{lqft_python_engine-0.2.0 → 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
|