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.
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lqft-python-engine
3
- Version: 0.7.0
4
- Summary: LQFT Engine: Strict Native C-Core & Hardware Concurrency (v0.7.0 Stable)
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
- // --- PHASE 2: CROSS-PLATFORM HARDWARE LOCKS ---
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.6.0 (Hardware Concurrency)
33
+ * LQFT C-Engine - V0.7.0 (Strict Native Concurrency)
34
34
  * Architect: Parjad Minooei
35
35
  * * CHANGE LOG:
36
- * - Implemented SRWLOCK / pthread_rwlock for true multi-core utilization.
37
- * - Bypassed Python GIL using Py_BEGIN_ALLOW_THREADS.
38
- * - Fixed Macro brace expansions for thread safe early returns.
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; // The Master Hardware 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 (Standard Operations)
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
- // Copy the string before dropping the GIL to prevent memory corruption
217
+ // 2. Safe duplication to unmanaged C memory before dropping GIL
391
218
  char* val_copy = portable_strdup(val_str);
392
219
 
393
- // Bypass GIL & Lock Engine (Exclusive Write Lock)
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
- // Bypass GIL & Lock Engine (Shared Read Lock - Multiple threads can enter simultaneously!)
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.0
4
- Summary: LQFT Engine: Strict Native C-Core & Hardware Concurrency (v0.7.0 Stable)
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.0",
31
- description="LQFT Engine: Strict Native C-Core & Hardware Concurrency (v0.7.0 Stable)",
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",