lqft-python-engine 0.7.0__tar.gz → 0.7.5__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.7.0 → lqft_python_engine-0.7.5}/PKG-INFO +2 -2
- {lqft_python_engine-0.7.0 → lqft_python_engine-0.7.5}/lqft_engine.c +216 -203
- {lqft_python_engine-0.7.0 → lqft_python_engine-0.7.5}/lqft_python_engine.egg-info/PKG-INFO +2 -2
- {lqft_python_engine-0.7.0 → lqft_python_engine-0.7.5}/setup.py +2 -2
- {lqft_python_engine-0.7.0 → lqft_python_engine-0.7.5}/LICENSE.md +0 -0
- {lqft_python_engine-0.7.0 → lqft_python_engine-0.7.5}/lqft_engine.py +0 -0
- {lqft_python_engine-0.7.0 → lqft_python_engine-0.7.5}/lqft_python_engine.egg-info/SOURCES.txt +0 -0
- {lqft_python_engine-0.7.0 → lqft_python_engine-0.7.5}/lqft_python_engine.egg-info/dependency_links.txt +0 -0
- {lqft_python_engine-0.7.0 → lqft_python_engine-0.7.5}/lqft_python_engine.egg-info/requires.txt +0 -0
- {lqft_python_engine-0.7.0 → lqft_python_engine-0.7.5}/lqft_python_engine.egg-info/top_level.txt +0 -0
- {lqft_python_engine-0.7.0 → lqft_python_engine-0.7.5}/pyproject.toml +0 -0
- {lqft_python_engine-0.7.0 → lqft_python_engine-0.7.5}/setup.cfg +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lqft-python-engine
|
|
3
|
-
Version: 0.7.
|
|
4
|
-
Summary: LQFT Engine: Strict Native C-Core & Hardware Concurrency (v0.7.
|
|
3
|
+
Version: 0.7.5
|
|
4
|
+
Summary: LQFT Engine: Strict Native C-Core & Hardware Concurrency (v0.7.5 Stable)
|
|
5
5
|
Home-page: https://github.com/ParjadM/Log-Quantum-Fractal-Tree-LQFT-
|
|
6
6
|
Author: Parjad Minooei
|
|
7
7
|
License: MIT
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
#include <string.h>
|
|
11
11
|
#include <stdint.h>
|
|
12
12
|
|
|
13
|
-
// ---
|
|
13
|
+
// --- CROSS-PLATFORM HARDWARE LOCKS ---
|
|
14
14
|
#ifdef _WIN32
|
|
15
15
|
#include <windows.h>
|
|
16
16
|
typedef SRWLOCK lqft_rwlock_t;
|
|
@@ -30,12 +30,12 @@
|
|
|
30
30
|
#endif
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
|
-
* LQFT C-Engine - V0.
|
|
33
|
+
* LQFT C-Engine - V0.7.0 (Strict Native Concurrency)
|
|
34
34
|
* Architect: Parjad Minooei
|
|
35
35
|
* * CHANGE LOG:
|
|
36
|
-
* -
|
|
37
|
-
* -
|
|
38
|
-
* -
|
|
36
|
+
* - Full GIL bypass implemented on all exposed Python endpoints.
|
|
37
|
+
* - Strict Separation of Concerns: PyArg parsing -> Drop GIL -> C++ Logic -> Reacquire GIL -> Py_BuildValue.
|
|
38
|
+
* - Thread-safe early returns fixed.
|
|
39
39
|
*/
|
|
40
40
|
|
|
41
41
|
#define BIT_PARTITION 5
|
|
@@ -56,7 +56,7 @@ typedef struct LQFTNode {
|
|
|
56
56
|
static LQFTNode** registry = NULL;
|
|
57
57
|
static int physical_node_count = 0;
|
|
58
58
|
static LQFTNode* global_root = NULL;
|
|
59
|
-
static lqft_rwlock_t engine_lock;
|
|
59
|
+
static lqft_rwlock_t engine_lock;
|
|
60
60
|
static int lock_initialized = 0;
|
|
61
61
|
|
|
62
62
|
const uint64_t FNV_OFFSET_BASIS = 14695981039346656037ULL;
|
|
@@ -106,9 +106,6 @@ LQFTNode* create_node(void* value, uint64_t key_hash) {
|
|
|
106
106
|
return node;
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
// -------------------------------------------------------------------
|
|
110
|
-
// Memory Management (ARC)
|
|
111
|
-
// -------------------------------------------------------------------
|
|
112
109
|
void decref(LQFTNode* node) {
|
|
113
110
|
if (!node) return;
|
|
114
111
|
node->ref_count--;
|
|
@@ -132,198 +129,8 @@ void decref(LQFTNode* node) {
|
|
|
132
129
|
}
|
|
133
130
|
}
|
|
134
131
|
|
|
135
|
-
static PyObject* method_free_all(PyObject* self, PyObject* args) {
|
|
136
|
-
Py_BEGIN_ALLOW_THREADS
|
|
137
|
-
LQFT_RWLOCK_WRLOCK(&engine_lock);
|
|
138
|
-
if (registry != NULL) {
|
|
139
|
-
for (int i = 0; i < REGISTRY_SIZE; i++) {
|
|
140
|
-
if (registry[i] != NULL && registry[i] != TOMBSTONE) {
|
|
141
|
-
if (registry[i]->value) free(registry[i]->value);
|
|
142
|
-
free(registry[i]);
|
|
143
|
-
}
|
|
144
|
-
registry[i] = NULL;
|
|
145
|
-
}
|
|
146
|
-
free(registry);
|
|
147
|
-
registry = NULL;
|
|
148
|
-
}
|
|
149
|
-
physical_node_count = 0;
|
|
150
|
-
global_root = NULL;
|
|
151
|
-
LQFT_RWLOCK_UNLOCK_WR(&engine_lock);
|
|
152
|
-
Py_END_ALLOW_THREADS
|
|
153
|
-
|
|
154
|
-
Py_RETURN_NONE;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// -------------------------------------------------------------------
|
|
158
|
-
// Disk Persistence (Binary Serialization)
|
|
159
|
-
// -------------------------------------------------------------------
|
|
160
|
-
static PyObject* method_save_to_disk(PyObject* self, PyObject* args) {
|
|
161
|
-
const char* filepath;
|
|
162
|
-
if (!PyArg_ParseTuple(args, "s", &filepath)) return NULL;
|
|
163
|
-
|
|
164
|
-
int success = 1;
|
|
165
|
-
|
|
166
|
-
// Release GIL, Lock Engine for Writing
|
|
167
|
-
Py_BEGIN_ALLOW_THREADS
|
|
168
|
-
LQFT_RWLOCK_WRLOCK(&engine_lock);
|
|
169
|
-
|
|
170
|
-
if (!registry) {
|
|
171
|
-
success = 0;
|
|
172
|
-
} else {
|
|
173
|
-
FILE* fp = fopen(filepath, "wb");
|
|
174
|
-
if (!fp) {
|
|
175
|
-
success = 0;
|
|
176
|
-
} else {
|
|
177
|
-
char magic[4] = "LQFT";
|
|
178
|
-
fwrite(magic, 1, 4, fp);
|
|
179
|
-
fwrite(&physical_node_count, sizeof(int), 1, fp);
|
|
180
|
-
uint64_t root_hash = global_root ? global_root->full_hash_val : 0;
|
|
181
|
-
fwrite(&root_hash, sizeof(uint64_t), 1, fp);
|
|
182
|
-
|
|
183
|
-
for (int i = 0; i < REGISTRY_SIZE; i++) {
|
|
184
|
-
LQFTNode* node = registry[i];
|
|
185
|
-
if (node != NULL && node != TOMBSTONE) {
|
|
186
|
-
fwrite(&node->full_hash_val, sizeof(uint64_t), 1, fp);
|
|
187
|
-
fwrite(&node->key_hash, sizeof(uint64_t), 1, fp);
|
|
188
|
-
fwrite(node->struct_hash, 1, 17, fp);
|
|
189
|
-
fwrite(&node->ref_count, sizeof(int), 1, fp);
|
|
190
|
-
|
|
191
|
-
int has_val = (node->value != NULL) ? 1 : 0;
|
|
192
|
-
fwrite(&has_val, sizeof(int), 1, fp);
|
|
193
|
-
if (has_val) {
|
|
194
|
-
int v_len = (int)strlen((char*)node->value);
|
|
195
|
-
fwrite(&v_len, sizeof(int), 1, fp);
|
|
196
|
-
fwrite(node->value, 1, v_len, fp);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
uint64_t child_refs[32] = {0};
|
|
200
|
-
for (int c = 0; c < 32; c++) {
|
|
201
|
-
if (node->children[c]) child_refs[c] = node->children[c]->full_hash_val;
|
|
202
|
-
}
|
|
203
|
-
fwrite(child_refs, sizeof(uint64_t), 32, fp);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
fclose(fp);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
LQFT_RWLOCK_UNLOCK_WR(&engine_lock);
|
|
210
|
-
Py_END_ALLOW_THREADS
|
|
211
|
-
|
|
212
|
-
if (!success) return PyErr_SetFromErrno(PyExc_IOError);
|
|
213
|
-
Py_RETURN_TRUE;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
LQFTNode* find_in_registry(uint64_t full_hash) {
|
|
217
|
-
if (full_hash == 0) return NULL;
|
|
218
|
-
uint32_t idx = full_hash % REGISTRY_SIZE;
|
|
219
|
-
uint32_t start_idx = idx;
|
|
220
|
-
while (registry[idx] != NULL) {
|
|
221
|
-
if (registry[idx] != TOMBSTONE && registry[idx]->full_hash_val == full_hash) {
|
|
222
|
-
return registry[idx];
|
|
223
|
-
}
|
|
224
|
-
idx = (idx + 1) % REGISTRY_SIZE;
|
|
225
|
-
if (idx == start_idx) break;
|
|
226
|
-
}
|
|
227
|
-
return NULL;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
static PyObject* method_load_from_disk(PyObject* self, PyObject* args) {
|
|
231
|
-
const char* filepath;
|
|
232
|
-
if (!PyArg_ParseTuple(args, "s", &filepath)) return NULL;
|
|
233
|
-
|
|
234
|
-
int success = 1;
|
|
235
|
-
int format_error = 0;
|
|
236
|
-
|
|
237
|
-
Py_BEGIN_ALLOW_THREADS
|
|
238
|
-
LQFT_RWLOCK_WRLOCK(&engine_lock);
|
|
239
|
-
|
|
240
|
-
FILE* fp = fopen(filepath, "rb");
|
|
241
|
-
if (!fp) {
|
|
242
|
-
success = 0;
|
|
243
|
-
} else {
|
|
244
|
-
char magic[5] = {0};
|
|
245
|
-
fread(magic, 1, 4, fp);
|
|
246
|
-
if (strcmp(magic, "LQFT") != 0) {
|
|
247
|
-
fclose(fp);
|
|
248
|
-
format_error = 1;
|
|
249
|
-
success = 0;
|
|
250
|
-
} else {
|
|
251
|
-
// Internal clear
|
|
252
|
-
if (registry != NULL) {
|
|
253
|
-
for (int i = 0; i < REGISTRY_SIZE; i++) {
|
|
254
|
-
if (registry[i] != NULL && registry[i] != TOMBSTONE) {
|
|
255
|
-
if (registry[i]->value) free(registry[i]->value);
|
|
256
|
-
free(registry[i]);
|
|
257
|
-
}
|
|
258
|
-
registry[i] = NULL;
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
physical_node_count = 0;
|
|
262
|
-
global_root = NULL;
|
|
263
|
-
init_registry();
|
|
264
|
-
|
|
265
|
-
int total_nodes;
|
|
266
|
-
uint64_t root_hash;
|
|
267
|
-
fread(&total_nodes, sizeof(int), 1, fp);
|
|
268
|
-
fread(&root_hash, sizeof(uint64_t), 1, fp);
|
|
269
|
-
|
|
270
|
-
uint64_t* all_child_refs = (uint64_t*)malloc(total_nodes * 32 * sizeof(uint64_t));
|
|
271
|
-
LQFTNode** loaded_nodes = (LQFTNode**)malloc(total_nodes * sizeof(LQFTNode*));
|
|
272
|
-
|
|
273
|
-
for (int i = 0; i < total_nodes; i++) {
|
|
274
|
-
LQFTNode* node = create_node(NULL, 0);
|
|
275
|
-
fread(&node->full_hash_val, sizeof(uint64_t), 1, fp);
|
|
276
|
-
fread(&node->key_hash, sizeof(uint64_t), 1, fp);
|
|
277
|
-
fread(node->struct_hash, 1, 17, fp);
|
|
278
|
-
fread(&node->ref_count, sizeof(int), 1, fp);
|
|
279
|
-
|
|
280
|
-
int has_val;
|
|
281
|
-
fread(&has_val, sizeof(int), 1, fp);
|
|
282
|
-
if (has_val) {
|
|
283
|
-
int v_len;
|
|
284
|
-
fread(&v_len, sizeof(int), 1, fp);
|
|
285
|
-
char* val_str = (char*)malloc(v_len + 1);
|
|
286
|
-
fread(val_str, 1, v_len, fp);
|
|
287
|
-
val_str[v_len] = '\0';
|
|
288
|
-
node->value = val_str;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
fread(&all_child_refs[i * 32], sizeof(uint64_t), 32, fp);
|
|
292
|
-
|
|
293
|
-
uint32_t idx = node->full_hash_val % REGISTRY_SIZE;
|
|
294
|
-
while (registry[idx] != NULL) idx = (idx + 1) % REGISTRY_SIZE;
|
|
295
|
-
registry[idx] = node;
|
|
296
|
-
loaded_nodes[i] = node;
|
|
297
|
-
physical_node_count++;
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
for (int i = 0; i < total_nodes; i++) {
|
|
301
|
-
for (int c = 0; c < 32; c++) {
|
|
302
|
-
uint64_t target_hash = all_child_refs[i * 32 + c];
|
|
303
|
-
if (target_hash != 0) loaded_nodes[i]->children[c] = find_in_registry(target_hash);
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
global_root = find_in_registry(root_hash);
|
|
308
|
-
free(all_child_refs);
|
|
309
|
-
free(loaded_nodes);
|
|
310
|
-
fclose(fp);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
LQFT_RWLOCK_UNLOCK_WR(&engine_lock);
|
|
314
|
-
Py_END_ALLOW_THREADS
|
|
315
|
-
|
|
316
|
-
if (format_error) {
|
|
317
|
-
PyErr_SetString(PyExc_ValueError, "Invalid LQFT binary file format.");
|
|
318
|
-
return NULL;
|
|
319
|
-
}
|
|
320
|
-
if (!success) return PyErr_SetFromErrno(PyExc_IOError);
|
|
321
|
-
|
|
322
|
-
Py_RETURN_TRUE;
|
|
323
|
-
}
|
|
324
|
-
|
|
325
132
|
// -------------------------------------------------------------------
|
|
326
|
-
// Merkle-DAG Core (
|
|
133
|
+
// Merkle-DAG Core logic (Called ONLY while GIL is released)
|
|
327
134
|
// -------------------------------------------------------------------
|
|
328
135
|
LQFTNode* get_canonical(void* value, uint64_t key_hash, LQFTNode** children) {
|
|
329
136
|
if (!init_registry()) return NULL;
|
|
@@ -382,15 +189,35 @@ LQFTNode* get_canonical(void* value, uint64_t key_hash, LQFTNode** children) {
|
|
|
382
189
|
return new_node;
|
|
383
190
|
}
|
|
384
191
|
|
|
192
|
+
LQFTNode* find_in_registry(uint64_t full_hash) {
|
|
193
|
+
if (full_hash == 0) return NULL;
|
|
194
|
+
uint32_t idx = full_hash % REGISTRY_SIZE;
|
|
195
|
+
uint32_t start_idx = idx;
|
|
196
|
+
while (registry[idx] != NULL) {
|
|
197
|
+
if (registry[idx] != TOMBSTONE && registry[idx]->full_hash_val == full_hash) {
|
|
198
|
+
return registry[idx];
|
|
199
|
+
}
|
|
200
|
+
idx = (idx + 1) % REGISTRY_SIZE;
|
|
201
|
+
if (idx == start_idx) break;
|
|
202
|
+
}
|
|
203
|
+
return NULL;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// -------------------------------------------------------------------
|
|
207
|
+
// EXPOSED PYTHON ENDPOINTS (STRICT GIL BOUNDARIES)
|
|
208
|
+
// -------------------------------------------------------------------
|
|
209
|
+
|
|
385
210
|
static PyObject* method_insert(PyObject* self, PyObject* args) {
|
|
386
211
|
unsigned long long h;
|
|
387
212
|
char* val_str;
|
|
213
|
+
|
|
214
|
+
// 1. Py API Call: Must happen BEFORE dropping the GIL
|
|
388
215
|
if (!PyArg_ParseTuple(args, "Ks", &h, &val_str)) return NULL;
|
|
389
216
|
|
|
390
|
-
//
|
|
217
|
+
// 2. Safe duplication to unmanaged C memory before dropping GIL
|
|
391
218
|
char* val_copy = portable_strdup(val_str);
|
|
392
219
|
|
|
393
|
-
//
|
|
220
|
+
// 3. Drop GIL: Pure C execution begins across multiple threads
|
|
394
221
|
Py_BEGIN_ALLOW_THREADS
|
|
395
222
|
LQFT_RWLOCK_WRLOCK(&engine_lock);
|
|
396
223
|
|
|
@@ -468,18 +295,23 @@ static PyObject* method_insert(PyObject* self, PyObject* args) {
|
|
|
468
295
|
|
|
469
296
|
free(val_copy);
|
|
470
297
|
LQFT_RWLOCK_UNLOCK_WR(&engine_lock);
|
|
298
|
+
|
|
299
|
+
// 4. Reacquire GIL: Execution returns to Python
|
|
471
300
|
Py_END_ALLOW_THREADS
|
|
472
301
|
|
|
302
|
+
// 5. Py API Call: Return Python Object
|
|
473
303
|
Py_RETURN_NONE;
|
|
474
304
|
}
|
|
475
305
|
|
|
476
306
|
static PyObject* method_search(PyObject* self, PyObject* args) {
|
|
477
307
|
unsigned long long h;
|
|
308
|
+
|
|
309
|
+
// 1. Py API Call BEFORE GIL Drop
|
|
478
310
|
if (!PyArg_ParseTuple(args, "K", &h)) return NULL;
|
|
479
311
|
|
|
480
312
|
char* result_str = NULL;
|
|
481
313
|
|
|
482
|
-
//
|
|
314
|
+
// 2. Drop GIL: Shared Read Lock allows true multi-core concurrent reads
|
|
483
315
|
Py_BEGIN_ALLOW_THREADS
|
|
484
316
|
LQFT_RWLOCK_RDLOCK(&engine_lock);
|
|
485
317
|
|
|
@@ -497,16 +329,22 @@ static PyObject* method_search(PyObject* self, PyObject* args) {
|
|
|
497
329
|
}
|
|
498
330
|
|
|
499
331
|
LQFT_RWLOCK_UNLOCK_RD(&engine_lock);
|
|
332
|
+
|
|
333
|
+
// 3. Reacquire GIL
|
|
500
334
|
Py_END_ALLOW_THREADS
|
|
501
335
|
|
|
336
|
+
// 4. Py API Call AFTER GIL Acquired
|
|
502
337
|
if (result_str) return PyUnicode_FromString(result_str);
|
|
503
338
|
Py_RETURN_NONE;
|
|
504
339
|
}
|
|
505
340
|
|
|
506
341
|
static PyObject* method_delete(PyObject* self, PyObject* args) {
|
|
507
342
|
unsigned long long h;
|
|
343
|
+
|
|
344
|
+
// 1. Py API Call BEFORE GIL Drop
|
|
508
345
|
if (!PyArg_ParseTuple(args, "K", &h)) return NULL;
|
|
509
346
|
|
|
347
|
+
// 2. Drop GIL
|
|
510
348
|
Py_BEGIN_ALLOW_THREADS
|
|
511
349
|
LQFT_RWLOCK_WRLOCK(&engine_lock);
|
|
512
350
|
|
|
@@ -554,6 +392,180 @@ static PyObject* method_delete(PyObject* self, PyObject* args) {
|
|
|
554
392
|
}
|
|
555
393
|
}
|
|
556
394
|
|
|
395
|
+
LQFT_RWLOCK_UNLOCK_WR(&engine_lock);
|
|
396
|
+
|
|
397
|
+
// 3. Reacquire GIL
|
|
398
|
+
Py_END_ALLOW_THREADS
|
|
399
|
+
|
|
400
|
+
// 4. Py API Call AFTER GIL Acquired
|
|
401
|
+
Py_RETURN_NONE;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
static PyObject* method_save_to_disk(PyObject* self, PyObject* args) {
|
|
405
|
+
const char* filepath;
|
|
406
|
+
if (!PyArg_ParseTuple(args, "s", &filepath)) return NULL;
|
|
407
|
+
|
|
408
|
+
int success = 1;
|
|
409
|
+
|
|
410
|
+
Py_BEGIN_ALLOW_THREADS
|
|
411
|
+
LQFT_RWLOCK_WRLOCK(&engine_lock);
|
|
412
|
+
|
|
413
|
+
if (!registry) {
|
|
414
|
+
success = 0;
|
|
415
|
+
} else {
|
|
416
|
+
FILE* fp = fopen(filepath, "wb");
|
|
417
|
+
if (!fp) {
|
|
418
|
+
success = 0;
|
|
419
|
+
} else {
|
|
420
|
+
char magic[4] = "LQFT";
|
|
421
|
+
fwrite(magic, 1, 4, fp);
|
|
422
|
+
fwrite(&physical_node_count, sizeof(int), 1, fp);
|
|
423
|
+
uint64_t root_hash = global_root ? global_root->full_hash_val : 0;
|
|
424
|
+
fwrite(&root_hash, sizeof(uint64_t), 1, fp);
|
|
425
|
+
|
|
426
|
+
for (int i = 0; i < REGISTRY_SIZE; i++) {
|
|
427
|
+
LQFTNode* node = registry[i];
|
|
428
|
+
if (node != NULL && node != TOMBSTONE) {
|
|
429
|
+
fwrite(&node->full_hash_val, sizeof(uint64_t), 1, fp);
|
|
430
|
+
fwrite(&node->key_hash, sizeof(uint64_t), 1, fp);
|
|
431
|
+
fwrite(node->struct_hash, 1, 17, fp);
|
|
432
|
+
fwrite(&node->ref_count, sizeof(int), 1, fp);
|
|
433
|
+
|
|
434
|
+
int has_val = (node->value != NULL) ? 1 : 0;
|
|
435
|
+
fwrite(&has_val, sizeof(int), 1, fp);
|
|
436
|
+
if (has_val) {
|
|
437
|
+
int v_len = (int)strlen((char*)node->value);
|
|
438
|
+
fwrite(&v_len, sizeof(int), 1, fp);
|
|
439
|
+
fwrite(node->value, 1, v_len, fp);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
uint64_t child_refs[32] = {0};
|
|
443
|
+
for (int c = 0; c < 32; c++) {
|
|
444
|
+
if (node->children[c]) child_refs[c] = node->children[c]->full_hash_val;
|
|
445
|
+
}
|
|
446
|
+
fwrite(child_refs, sizeof(uint64_t), 32, fp);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
fclose(fp);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
LQFT_RWLOCK_UNLOCK_WR(&engine_lock);
|
|
453
|
+
Py_END_ALLOW_THREADS
|
|
454
|
+
|
|
455
|
+
if (!success) return PyErr_SetFromErrno(PyExc_IOError);
|
|
456
|
+
Py_RETURN_TRUE;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
static PyObject* method_load_from_disk(PyObject* self, PyObject* args) {
|
|
460
|
+
const char* filepath;
|
|
461
|
+
if (!PyArg_ParseTuple(args, "s", &filepath)) return NULL;
|
|
462
|
+
|
|
463
|
+
int success = 1;
|
|
464
|
+
int format_error = 0;
|
|
465
|
+
|
|
466
|
+
Py_BEGIN_ALLOW_THREADS
|
|
467
|
+
LQFT_RWLOCK_WRLOCK(&engine_lock);
|
|
468
|
+
|
|
469
|
+
FILE* fp = fopen(filepath, "rb");
|
|
470
|
+
if (!fp) {
|
|
471
|
+
success = 0;
|
|
472
|
+
} else {
|
|
473
|
+
char magic[5] = {0};
|
|
474
|
+
fread(magic, 1, 4, fp);
|
|
475
|
+
if (strcmp(magic, "LQFT") != 0) {
|
|
476
|
+
fclose(fp);
|
|
477
|
+
format_error = 1;
|
|
478
|
+
success = 0;
|
|
479
|
+
} else {
|
|
480
|
+
if (registry != NULL) {
|
|
481
|
+
for (int i = 0; i < REGISTRY_SIZE; i++) {
|
|
482
|
+
if (registry[i] != NULL && registry[i] != TOMBSTONE) {
|
|
483
|
+
if (registry[i]->value) free(registry[i]->value);
|
|
484
|
+
free(registry[i]);
|
|
485
|
+
}
|
|
486
|
+
registry[i] = NULL;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
physical_node_count = 0;
|
|
490
|
+
global_root = NULL;
|
|
491
|
+
init_registry();
|
|
492
|
+
|
|
493
|
+
int total_nodes;
|
|
494
|
+
uint64_t root_hash;
|
|
495
|
+
fread(&total_nodes, sizeof(int), 1, fp);
|
|
496
|
+
fread(&root_hash, sizeof(uint64_t), 1, fp);
|
|
497
|
+
|
|
498
|
+
uint64_t* all_child_refs = (uint64_t*)malloc(total_nodes * 32 * sizeof(uint64_t));
|
|
499
|
+
LQFTNode** loaded_nodes = (LQFTNode**)malloc(total_nodes * sizeof(LQFTNode*));
|
|
500
|
+
|
|
501
|
+
for (int i = 0; i < total_nodes; i++) {
|
|
502
|
+
LQFTNode* node = create_node(NULL, 0);
|
|
503
|
+
fread(&node->full_hash_val, sizeof(uint64_t), 1, fp);
|
|
504
|
+
fread(&node->key_hash, sizeof(uint64_t), 1, fp);
|
|
505
|
+
fread(node->struct_hash, 1, 17, fp);
|
|
506
|
+
fread(&node->ref_count, sizeof(int), 1, fp);
|
|
507
|
+
|
|
508
|
+
int has_val;
|
|
509
|
+
fread(&has_val, sizeof(int), 1, fp);
|
|
510
|
+
if (has_val) {
|
|
511
|
+
int v_len;
|
|
512
|
+
fread(&v_len, sizeof(int), 1, fp);
|
|
513
|
+
char* val_str = (char*)malloc(v_len + 1);
|
|
514
|
+
fread(val_str, 1, v_len, fp);
|
|
515
|
+
val_str[v_len] = '\0';
|
|
516
|
+
node->value = val_str;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
fread(&all_child_refs[i * 32], sizeof(uint64_t), 32, fp);
|
|
520
|
+
|
|
521
|
+
uint32_t idx = node->full_hash_val % REGISTRY_SIZE;
|
|
522
|
+
while (registry[idx] != NULL) idx = (idx + 1) % REGISTRY_SIZE;
|
|
523
|
+
registry[idx] = node;
|
|
524
|
+
loaded_nodes[i] = node;
|
|
525
|
+
physical_node_count++;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
for (int i = 0; i < total_nodes; i++) {
|
|
529
|
+
for (int c = 0; c < 32; c++) {
|
|
530
|
+
uint64_t target_hash = all_child_refs[i * 32 + c];
|
|
531
|
+
if (target_hash != 0) loaded_nodes[i]->children[c] = find_in_registry(target_hash);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
global_root = find_in_registry(root_hash);
|
|
536
|
+
free(all_child_refs);
|
|
537
|
+
free(loaded_nodes);
|
|
538
|
+
fclose(fp);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
LQFT_RWLOCK_UNLOCK_WR(&engine_lock);
|
|
542
|
+
Py_END_ALLOW_THREADS
|
|
543
|
+
|
|
544
|
+
if (format_error) {
|
|
545
|
+
PyErr_SetString(PyExc_ValueError, "Invalid LQFT binary file format.");
|
|
546
|
+
return NULL;
|
|
547
|
+
}
|
|
548
|
+
if (!success) return PyErr_SetFromErrno(PyExc_IOError);
|
|
549
|
+
|
|
550
|
+
Py_RETURN_TRUE;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
static PyObject* method_free_all(PyObject* self, PyObject* args) {
|
|
554
|
+
Py_BEGIN_ALLOW_THREADS
|
|
555
|
+
LQFT_RWLOCK_WRLOCK(&engine_lock);
|
|
556
|
+
if (registry != NULL) {
|
|
557
|
+
for (int i = 0; i < REGISTRY_SIZE; i++) {
|
|
558
|
+
if (registry[i] != NULL && registry[i] != TOMBSTONE) {
|
|
559
|
+
if (registry[i]->value) free(registry[i]->value);
|
|
560
|
+
free(registry[i]);
|
|
561
|
+
}
|
|
562
|
+
registry[i] = NULL;
|
|
563
|
+
}
|
|
564
|
+
free(registry);
|
|
565
|
+
registry = NULL;
|
|
566
|
+
}
|
|
567
|
+
physical_node_count = 0;
|
|
568
|
+
global_root = NULL;
|
|
557
569
|
LQFT_RWLOCK_UNLOCK_WR(&engine_lock);
|
|
558
570
|
Py_END_ALLOW_THREADS
|
|
559
571
|
|
|
@@ -561,6 +573,7 @@ static PyObject* method_delete(PyObject* self, PyObject* args) {
|
|
|
561
573
|
}
|
|
562
574
|
|
|
563
575
|
static PyObject* method_get_metrics(PyObject* self, PyObject* args) {
|
|
576
|
+
// Fast un-locked fetch (metric tracking), pure Py API
|
|
564
577
|
return Py_BuildValue("{s:i}", "physical_nodes", physical_node_count);
|
|
565
578
|
}
|
|
566
579
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lqft-python-engine
|
|
3
|
-
Version: 0.7.
|
|
4
|
-
Summary: LQFT Engine: Strict Native C-Core & Hardware Concurrency (v0.7.
|
|
3
|
+
Version: 0.7.5
|
|
4
|
+
Summary: LQFT Engine: Strict Native C-Core & Hardware Concurrency (v0.7.5 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.7.
|
|
31
|
-
description="LQFT Engine: Strict Native C-Core & Hardware Concurrency (v0.7.
|
|
30
|
+
version="0.7.5",
|
|
31
|
+
description="LQFT Engine: Strict Native C-Core & Hardware Concurrency (v0.7.5 Stable)",
|
|
32
32
|
long_description=long_description,
|
|
33
33
|
long_description_content_type="text/markdown",
|
|
34
34
|
author="Parjad Minooei",
|
|
File without changes
|
|
File without changes
|
{lqft_python_engine-0.7.0 → lqft_python_engine-0.7.5}/lqft_python_engine.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{lqft_python_engine-0.7.0 → lqft_python_engine-0.7.5}/lqft_python_engine.egg-info/requires.txt
RENAMED
|
File without changes
|
{lqft_python_engine-0.7.0 → lqft_python_engine-0.7.5}/lqft_python_engine.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|