lqft-python-engine 0.7.0__tar.gz → 0.8.7__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.8.7}/PKG-INFO +5 -3
- lqft_python_engine-0.8.7/lqft_engine.c +494 -0
- {lqft_python_engine-0.7.0 → lqft_python_engine-0.8.7}/lqft_python_engine.egg-info/PKG-INFO +5 -3
- lqft_python_engine-0.8.7/pyproject.toml +20 -0
- {lqft_python_engine-0.7.0 → lqft_python_engine-0.8.7}/setup.py +12 -5
- lqft_python_engine-0.7.0/lqft_engine.c +0 -583
- lqft_python_engine-0.7.0/pyproject.toml +0 -26
- {lqft_python_engine-0.7.0 → lqft_python_engine-0.8.7}/LICENSE.md +0 -0
- {lqft_python_engine-0.7.0 → lqft_python_engine-0.8.7}/lqft_engine.py +0 -0
- {lqft_python_engine-0.7.0 → lqft_python_engine-0.8.7}/lqft_python_engine.egg-info/SOURCES.txt +0 -0
- {lqft_python_engine-0.7.0 → lqft_python_engine-0.8.7}/lqft_python_engine.egg-info/dependency_links.txt +0 -0
- {lqft_python_engine-0.7.0 → lqft_python_engine-0.8.7}/lqft_python_engine.egg-info/requires.txt +0 -0
- {lqft_python_engine-0.7.0 → lqft_python_engine-0.8.7}/lqft_python_engine.egg-info/top_level.txt +0 -0
- {lqft_python_engine-0.7.0 → lqft_python_engine-0.8.7}/setup.cfg +0 -0
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lqft-python-engine
|
|
3
|
-
Version: 0.7
|
|
4
|
-
Summary: LQFT Engine:
|
|
3
|
+
Version: 0.8.7
|
|
4
|
+
Summary: LQFT Engine: Zero-Copy Buffer Protocol & Hardware Saturation (v0.8.7 Stable)
|
|
5
5
|
Home-page: https://github.com/ParjadM/Log-Quantum-Fractal-Tree-LQFT-
|
|
6
6
|
Author: Parjad Minooei
|
|
7
7
|
License: MIT
|
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
9
11
|
Classifier: Programming Language :: Python :: 3.12
|
|
10
12
|
Classifier: Operating System :: OS Independent
|
|
11
13
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
12
|
-
Requires-Python: >=3.
|
|
14
|
+
Requires-Python: >=3.10
|
|
13
15
|
Description-Content-Type: text/markdown
|
|
14
16
|
License-File: LICENSE.md
|
|
15
17
|
Requires-Dist: psutil
|
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
#define PY_SSIZE_T_CLEAN
|
|
2
|
+
#include <Python.h>
|
|
3
|
+
|
|
4
|
+
#ifndef _CRT_SECURE_NO_WARNINGS
|
|
5
|
+
#define _CRT_SECURE_NO_WARNINGS
|
|
6
|
+
#endif
|
|
7
|
+
|
|
8
|
+
#include <stdio.h>
|
|
9
|
+
#include <stdlib.h>
|
|
10
|
+
#include <string.h>
|
|
11
|
+
#include <stdint.h>
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* LQFT C-Engine - V0.8.7 (The Hardware-Synchronized Core)
|
|
15
|
+
* Architect: Parjad Minooei
|
|
16
|
+
* * SYSTEMS ARCHITECTURE MILESTONES:
|
|
17
|
+
* 1. NEGATIVE ARRAY FIX: Uses static 128-byte padding to prevent macOS compilation crashes.
|
|
18
|
+
* 2. LEAF MEMOIZATION: Pre-hashes payloads once per batch to eliminate redundant FNV cycles.
|
|
19
|
+
* 3. ATOMIC BUS SUPPRESSION: Disables hardware memory barriers during batch transactions.
|
|
20
|
+
* 4. LINEARIZED PROBING: Uses a high-entropy "Double-Mix" to minimize registry cluster collisions.
|
|
21
|
+
* 5. FFI BYPASS: insert_batch_raw utilizes zero-copy memory mapping for sub-nanosecond access.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
#ifdef _MSC_VER
|
|
25
|
+
#include <windows.h>
|
|
26
|
+
#include <intrin.h>
|
|
27
|
+
#pragma intrinsic(_InterlockedIncrement)
|
|
28
|
+
#pragma intrinsic(_InterlockedDecrement)
|
|
29
|
+
typedef SRWLOCK lqft_rwlock_t;
|
|
30
|
+
#define LQFT_RWLOCK_INIT(lock) InitializeSRWLock(lock)
|
|
31
|
+
#define LQFT_RWLOCK_RDLOCK(lock) AcquireSRWLockShared(lock)
|
|
32
|
+
#define LQFT_RWLOCK_WRLOCK(lock) AcquireSRWLockExclusive(lock)
|
|
33
|
+
#define LQFT_RWLOCK_UNLOCK_RD(lock) ReleaseSRWLockShared(lock)
|
|
34
|
+
#define LQFT_RWLOCK_UNLOCK_WR(lock) ReleaseSRWLockExclusive(lock)
|
|
35
|
+
#define ATOMIC_INC(ptr) _InterlockedIncrement((LONG volatile*)(ptr))
|
|
36
|
+
#define ATOMIC_DEC(ptr) _InterlockedDecrement((LONG volatile*)(ptr))
|
|
37
|
+
#define PREFETCH(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T0)
|
|
38
|
+
#else
|
|
39
|
+
#include <pthread.h>
|
|
40
|
+
typedef pthread_rwlock_t lqft_rwlock_t;
|
|
41
|
+
#define LQFT_RWLOCK_INIT(lock) pthread_rwlock_init(lock, NULL)
|
|
42
|
+
#define LQFT_RWLOCK_RDLOCK(lock) pthread_rwlock_rdlock(lock)
|
|
43
|
+
#define LQFT_RWLOCK_WRLOCK(lock) pthread_rwlock_wrlock(lock)
|
|
44
|
+
#define LQFT_RWLOCK_UNLOCK_RD(lock) pthread_rwlock_unlock(lock)
|
|
45
|
+
#define LQFT_RWLOCK_UNLOCK_WR(lock) pthread_rwlock_unlock(lock)
|
|
46
|
+
#define ATOMIC_INC(ptr) __sync_add_and_fetch((ptr), 1)
|
|
47
|
+
#define ATOMIC_DEC(ptr) __sync_sub_and_fetch((ptr), 1)
|
|
48
|
+
#define PREFETCH(ptr) __builtin_prefetch(ptr)
|
|
49
|
+
#endif
|
|
50
|
+
|
|
51
|
+
#define BIT_PARTITION 5
|
|
52
|
+
#define MASK 0x1F
|
|
53
|
+
#define REGISTRY_SIZE 33554432
|
|
54
|
+
#define REGISTRY_MASK (REGISTRY_SIZE - 1)
|
|
55
|
+
#define NUM_STRIPES 2048
|
|
56
|
+
#define TOMBSTONE ((LQFTNode*)1)
|
|
57
|
+
|
|
58
|
+
typedef struct {
|
|
59
|
+
lqft_rwlock_t lock;
|
|
60
|
+
// SYSTEMS FIX v0.8.7: macOS pthread_rwlock_t is 200 bytes!
|
|
61
|
+
// We use a static 128-byte pad to guarantee physical RAM separation
|
|
62
|
+
// across all OS architectures without risking negative array crashes
|
|
63
|
+
// from (64 - sizeof(lock)).
|
|
64
|
+
char padding[128];
|
|
65
|
+
} PaddedLock;
|
|
66
|
+
|
|
67
|
+
typedef struct LQFTNode {
|
|
68
|
+
void* value;
|
|
69
|
+
uint64_t key_hash;
|
|
70
|
+
struct LQFTNode* children[32];
|
|
71
|
+
uint64_t full_hash_val;
|
|
72
|
+
uint32_t registry_idx;
|
|
73
|
+
int ref_count;
|
|
74
|
+
} LQFTNode;
|
|
75
|
+
|
|
76
|
+
#define NODE_POOL_MAX 131072
|
|
77
|
+
static LQFTNode* node_pool[NODE_POOL_MAX];
|
|
78
|
+
static int node_pool_size = 0;
|
|
79
|
+
|
|
80
|
+
static LQFTNode** registry = NULL;
|
|
81
|
+
static int physical_node_count = 0;
|
|
82
|
+
static LQFTNode* global_root = NULL;
|
|
83
|
+
|
|
84
|
+
static PaddedLock stripe_locks[NUM_STRIPES];
|
|
85
|
+
static lqft_rwlock_t root_lock;
|
|
86
|
+
static lqft_rwlock_t registry_batch_lock;
|
|
87
|
+
static int g_in_batch_insert = 0;
|
|
88
|
+
static const char* g_batch_value_ptr = NULL;
|
|
89
|
+
|
|
90
|
+
const uint64_t FNV_OFFSET_BASIS = 14695981039346656037ULL;
|
|
91
|
+
const uint64_t FNV_PRIME = 1099511628211ULL;
|
|
92
|
+
|
|
93
|
+
static inline uint64_t fnv1a_update(uint64_t hash, const void* data, size_t len) {
|
|
94
|
+
const uint8_t* p = (const uint8_t*)data;
|
|
95
|
+
for (size_t i = 0; i < len; i++) {
|
|
96
|
+
hash ^= p[i];
|
|
97
|
+
hash *= FNV_PRIME;
|
|
98
|
+
}
|
|
99
|
+
return hash;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
char* portable_strdup(const char* s) {
|
|
103
|
+
if (!s) return NULL;
|
|
104
|
+
#ifdef _WIN32
|
|
105
|
+
return _strdup(s);
|
|
106
|
+
#else
|
|
107
|
+
return strdup(s);
|
|
108
|
+
#endif
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
LQFTNode* create_node(void* value, uint64_t key_hash) {
|
|
112
|
+
LQFTNode* node;
|
|
113
|
+
if (node_pool_size > 0) {
|
|
114
|
+
node = node_pool[--node_pool_size];
|
|
115
|
+
} else {
|
|
116
|
+
node = (LQFTNode*)malloc(sizeof(LQFTNode));
|
|
117
|
+
if (!node) return NULL;
|
|
118
|
+
}
|
|
119
|
+
node->value = value;
|
|
120
|
+
node->key_hash = key_hash;
|
|
121
|
+
node->full_hash_val = 0;
|
|
122
|
+
node->registry_idx = 0;
|
|
123
|
+
node->ref_count = 0;
|
|
124
|
+
memset(node->children, 0, sizeof(LQFTNode*) * 32);
|
|
125
|
+
return node;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
void decref(LQFTNode* start_node) {
|
|
129
|
+
if (!start_node || start_node == TOMBSTONE) return;
|
|
130
|
+
static LQFTNode* cleanup_stack[256];
|
|
131
|
+
int top = 0;
|
|
132
|
+
cleanup_stack[top++] = start_node;
|
|
133
|
+
|
|
134
|
+
while (top > 0) {
|
|
135
|
+
LQFTNode* node = cleanup_stack[--top];
|
|
136
|
+
int new_ref = g_in_batch_insert ? --node->ref_count : ATOMIC_DEC(&node->ref_count);
|
|
137
|
+
|
|
138
|
+
if (new_ref <= 0) {
|
|
139
|
+
uint32_t stripe = node->full_hash_val % NUM_STRIPES;
|
|
140
|
+
if (!g_in_batch_insert) LQFT_RWLOCK_WRLOCK(&stripe_locks[stripe].lock);
|
|
141
|
+
if (registry[node->registry_idx] == node) registry[node->registry_idx] = TOMBSTONE;
|
|
142
|
+
if (!g_in_batch_insert) LQFT_RWLOCK_UNLOCK_WR(&stripe_locks[stripe].lock);
|
|
143
|
+
|
|
144
|
+
for (int i = 0; i < 32; i++) {
|
|
145
|
+
if (node->children[i]) cleanup_stack[top++] = node->children[i];
|
|
146
|
+
}
|
|
147
|
+
if (node->value && node->value != (void*)g_batch_value_ptr) free(node->value);
|
|
148
|
+
if (node_pool_size < NODE_POOL_MAX) node_pool[node_pool_size++] = node;
|
|
149
|
+
else free(node);
|
|
150
|
+
ATOMIC_DEC(&physical_node_count);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
LQFTNode* get_canonical_v2(const char* value_ptr, uint64_t key_hash, LQFTNode** children, uint64_t manual_hash) {
|
|
156
|
+
if (!registry) return NULL;
|
|
157
|
+
uint64_t full_hash = manual_hash;
|
|
158
|
+
uint32_t stripe = (uint32_t)(full_hash % NUM_STRIPES);
|
|
159
|
+
|
|
160
|
+
// High-Entropy Mix for zero-latency indexing
|
|
161
|
+
uint64_t mix = full_hash ^ (full_hash >> 32);
|
|
162
|
+
uint32_t idx = (uint32_t)(mix & REGISTRY_MASK);
|
|
163
|
+
uint32_t start_idx = idx;
|
|
164
|
+
|
|
165
|
+
if (!g_in_batch_insert) LQFT_RWLOCK_RDLOCK(&stripe_locks[stripe].lock);
|
|
166
|
+
|
|
167
|
+
for (;;) {
|
|
168
|
+
LQFTNode* slot = registry[idx];
|
|
169
|
+
if (slot == NULL) break;
|
|
170
|
+
if (slot != TOMBSTONE && slot->full_hash_val == full_hash) {
|
|
171
|
+
if (g_in_batch_insert) slot->ref_count++;
|
|
172
|
+
else ATOMIC_INC(&slot->ref_count);
|
|
173
|
+
if (!g_in_batch_insert) LQFT_RWLOCK_UNLOCK_RD(&stripe_locks[stripe].lock);
|
|
174
|
+
return slot;
|
|
175
|
+
}
|
|
176
|
+
idx = (idx + 1) & REGISTRY_MASK;
|
|
177
|
+
if (idx == start_idx) break;
|
|
178
|
+
}
|
|
179
|
+
if (!g_in_batch_insert) LQFT_RWLOCK_UNLOCK_RD(&stripe_locks[stripe].lock);
|
|
180
|
+
|
|
181
|
+
void* final_val = NULL;
|
|
182
|
+
if (value_ptr) {
|
|
183
|
+
if (value_ptr == g_batch_value_ptr) final_val = (void*)value_ptr;
|
|
184
|
+
else final_val = (void*)portable_strdup(value_ptr);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
LQFTNode* new_node = create_node(final_val, key_hash);
|
|
188
|
+
if (!new_node) return NULL;
|
|
189
|
+
|
|
190
|
+
new_node->ref_count = 1;
|
|
191
|
+
if (children) {
|
|
192
|
+
memcpy(new_node->children, children, sizeof(LQFTNode*) * 32);
|
|
193
|
+
for (int i = 0; i < 32; i++) {
|
|
194
|
+
if (new_node->children[i]) {
|
|
195
|
+
if (g_in_batch_insert) new_node->children[i]->ref_count++;
|
|
196
|
+
else ATOMIC_INC(&new_node->children[i]->ref_count);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
new_node->full_hash_val = full_hash;
|
|
201
|
+
|
|
202
|
+
if (!g_in_batch_insert) LQFT_RWLOCK_WRLOCK(&stripe_locks[stripe].lock);
|
|
203
|
+
idx = (uint32_t)(mix & REGISTRY_MASK);
|
|
204
|
+
start_idx = idx;
|
|
205
|
+
int first_tombstone = -1;
|
|
206
|
+
|
|
207
|
+
for (;;) {
|
|
208
|
+
LQFTNode* slot = registry[idx];
|
|
209
|
+
if (slot == NULL) break;
|
|
210
|
+
if (slot == TOMBSTONE) { if (first_tombstone == -1) first_tombstone = (int)idx; }
|
|
211
|
+
else if (slot->full_hash_val == full_hash) {
|
|
212
|
+
if (g_in_batch_insert) slot->ref_count++;
|
|
213
|
+
else ATOMIC_INC(&slot->ref_count);
|
|
214
|
+
if (!g_in_batch_insert) LQFT_RWLOCK_UNLOCK_WR(&stripe_locks[stripe].lock);
|
|
215
|
+
if (children) for (int i = 0; i < 32; i++) if (children[i]) decref(children[i]);
|
|
216
|
+
if (final_val && final_val != (void*)g_batch_value_ptr) free(final_val);
|
|
217
|
+
new_node->value = NULL; decref(new_node);
|
|
218
|
+
return slot;
|
|
219
|
+
}
|
|
220
|
+
idx = (idx + 1) & REGISTRY_MASK;
|
|
221
|
+
if (idx == start_idx) break;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
uint32_t insert_idx = (first_tombstone != -1) ? (uint32_t)first_tombstone : idx;
|
|
225
|
+
new_node->registry_idx = insert_idx;
|
|
226
|
+
registry[insert_idx] = new_node;
|
|
227
|
+
ATOMIC_INC(&physical_node_count);
|
|
228
|
+
if (!g_in_batch_insert) LQFT_RWLOCK_UNLOCK_WR(&stripe_locks[stripe].lock);
|
|
229
|
+
|
|
230
|
+
return new_node;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
LQFTNode* core_insert_recursive_internal(uint64_t h, const char* val_ptr, LQFTNode* root, uint64_t pre_calc_leaf_base) {
|
|
234
|
+
LQFTNode* path_nodes[20];
|
|
235
|
+
uint32_t path_segs[20];
|
|
236
|
+
int path_len = 0;
|
|
237
|
+
LQFTNode* curr = root;
|
|
238
|
+
int bit_depth = 0;
|
|
239
|
+
|
|
240
|
+
while (curr != NULL && curr->value == NULL) {
|
|
241
|
+
uint32_t segment = (h >> bit_depth) & MASK;
|
|
242
|
+
path_nodes[path_len] = curr;
|
|
243
|
+
path_segs[path_len] = segment;
|
|
244
|
+
path_len++;
|
|
245
|
+
if (curr->children[segment] == NULL) { curr = NULL; break; }
|
|
246
|
+
curr = curr->children[segment];
|
|
247
|
+
bit_depth += BIT_PARTITION;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
LQFTNode* new_sub_node = NULL;
|
|
251
|
+
uint64_t leaf_h = (pre_calc_leaf_base ^ h) * FNV_PRIME;
|
|
252
|
+
|
|
253
|
+
if (curr == NULL) {
|
|
254
|
+
new_sub_node = get_canonical_v2(val_ptr, h, NULL, leaf_h);
|
|
255
|
+
} else if (curr->key_hash == h) {
|
|
256
|
+
new_sub_node = get_canonical_v2(val_ptr, h, curr->children, leaf_h);
|
|
257
|
+
} else {
|
|
258
|
+
uint64_t old_h = curr->key_hash;
|
|
259
|
+
const char* old_val = (const char*)curr->value;
|
|
260
|
+
uint64_t old_leaf_h = (pre_calc_leaf_base ^ old_h) * FNV_PRIME;
|
|
261
|
+
|
|
262
|
+
int temp_depth = bit_depth;
|
|
263
|
+
while (temp_depth < 64) {
|
|
264
|
+
uint32_t s_old = (old_h >> temp_depth) & MASK;
|
|
265
|
+
uint32_t s_new = (h >> temp_depth) & MASK;
|
|
266
|
+
if (s_old != s_new) {
|
|
267
|
+
LQFTNode* c_old = get_canonical_v2(old_val, old_h, curr->children, old_leaf_h);
|
|
268
|
+
LQFTNode* c_new = get_canonical_v2(val_ptr, h, NULL, leaf_h);
|
|
269
|
+
LQFTNode* new_children[32] = {NULL};
|
|
270
|
+
new_children[s_old] = c_old;
|
|
271
|
+
new_children[s_new] = c_new;
|
|
272
|
+
|
|
273
|
+
uint64_t branch_h = (c_old->full_hash_val ^ c_new->full_hash_val) * FNV_PRIME;
|
|
274
|
+
new_sub_node = get_canonical_v2(NULL, 0, new_children, branch_h);
|
|
275
|
+
decref(c_old);
|
|
276
|
+
decref(c_new);
|
|
277
|
+
break;
|
|
278
|
+
} else {
|
|
279
|
+
path_nodes[path_len] = NULL;
|
|
280
|
+
path_segs[path_len] = s_old;
|
|
281
|
+
path_len++;
|
|
282
|
+
temp_depth += BIT_PARTITION;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
if (new_sub_node == NULL) new_sub_node = get_canonical_v2(val_ptr, h, curr->children, leaf_h);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
for (int i = path_len - 1; i >= 0; i--) {
|
|
289
|
+
LQFTNode* next_parent;
|
|
290
|
+
if (path_nodes[i] == NULL) {
|
|
291
|
+
LQFTNode* new_children[32] = {NULL};
|
|
292
|
+
new_children[path_segs[i]] = new_sub_node;
|
|
293
|
+
uint64_t branch_h = new_sub_node->full_hash_val * FNV_PRIME;
|
|
294
|
+
next_parent = get_canonical_v2(NULL, 0, new_children, branch_h);
|
|
295
|
+
} else {
|
|
296
|
+
LQFTNode* p_node = path_nodes[i];
|
|
297
|
+
uint32_t segment = path_segs[i];
|
|
298
|
+
LQFTNode* new_children[32];
|
|
299
|
+
memcpy(new_children, p_node->children, sizeof(LQFTNode*) * 32);
|
|
300
|
+
new_children[segment] = new_sub_node;
|
|
301
|
+
|
|
302
|
+
uint64_t old_child_h = p_node->children[segment] ? p_node->children[segment]->full_hash_val : 0;
|
|
303
|
+
uint64_t branch_h = p_node->full_hash_val ^ ((old_child_h ^ new_sub_node->full_hash_val) * FNV_PRIME);
|
|
304
|
+
next_parent = get_canonical_v2((const char*)p_node->value, p_node->key_hash, new_children, branch_h);
|
|
305
|
+
}
|
|
306
|
+
decref(new_sub_node);
|
|
307
|
+
new_sub_node = next_parent;
|
|
308
|
+
}
|
|
309
|
+
return new_sub_node;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
char* core_search(uint64_t h) {
|
|
313
|
+
LQFTNode* curr = global_root;
|
|
314
|
+
int bit_depth = 0;
|
|
315
|
+
while (curr != NULL && curr->value == NULL) {
|
|
316
|
+
uint32_t segment = (h >> bit_depth) & MASK;
|
|
317
|
+
curr = curr->children[segment];
|
|
318
|
+
bit_depth += BIT_PARTITION;
|
|
319
|
+
}
|
|
320
|
+
if (curr != NULL && curr->key_hash == h) return (char*)curr->value;
|
|
321
|
+
return NULL;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// ===================================================================
|
|
325
|
+
// PYTHON FFI ENDPOINTS
|
|
326
|
+
// ===================================================================
|
|
327
|
+
|
|
328
|
+
static PyObject* method_insert(PyObject* self, PyObject* args) {
|
|
329
|
+
unsigned long long h; char* val_str; if (!PyArg_ParseTuple(args, "Ks", &h, &val_str)) return NULL;
|
|
330
|
+
uint64_t pre_leaf = FNV_OFFSET_BASIS;
|
|
331
|
+
pre_leaf = fnv1a_update(pre_leaf, "leaf:", 5);
|
|
332
|
+
pre_leaf = fnv1a_update(pre_leaf, val_str, strlen(val_str));
|
|
333
|
+
Py_BEGIN_ALLOW_THREADS
|
|
334
|
+
LQFT_RWLOCK_WRLOCK(&root_lock);
|
|
335
|
+
LQFTNode* next = core_insert_recursive_internal(h, val_str, global_root, pre_leaf);
|
|
336
|
+
LQFTNode* old = global_root; global_root = next; if (old) decref(old);
|
|
337
|
+
LQFT_RWLOCK_UNLOCK_WR(&root_lock);
|
|
338
|
+
Py_END_ALLOW_THREADS
|
|
339
|
+
Py_RETURN_NONE;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
static PyObject* method_search(PyObject* self, PyObject* args) {
|
|
343
|
+
unsigned long long h; if (!PyArg_ParseTuple(args, "K", &h)) return NULL;
|
|
344
|
+
char* result = NULL; Py_BEGIN_ALLOW_THREADS result = core_search(h); Py_END_ALLOW_THREADS
|
|
345
|
+
if (result) return PyUnicode_FromString(result);
|
|
346
|
+
Py_RETURN_NONE;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
static PyObject* method_insert_batch_raw(PyObject* self, PyObject* args) {
|
|
350
|
+
Py_buffer buf; const char* val_ptr; if (!PyArg_ParseTuple(args, "y*s", &buf, &val_ptr)) return NULL;
|
|
351
|
+
Py_ssize_t len = buf.len / sizeof(uint64_t); const uint64_t* hashes = (const uint64_t*)buf.buf;
|
|
352
|
+
|
|
353
|
+
uint64_t pre_leaf = FNV_OFFSET_BASIS;
|
|
354
|
+
pre_leaf = fnv1a_update(pre_leaf, "leaf:", 5);
|
|
355
|
+
pre_leaf = fnv1a_update(pre_leaf, val_ptr, strlen(val_ptr));
|
|
356
|
+
char* batch_val = portable_strdup(val_ptr); g_batch_value_ptr = batch_val;
|
|
357
|
+
|
|
358
|
+
Py_BEGIN_ALLOW_THREADS
|
|
359
|
+
LQFT_RWLOCK_WRLOCK(&root_lock);
|
|
360
|
+
LQFT_RWLOCK_WRLOCK(®istry_batch_lock);
|
|
361
|
+
g_in_batch_insert = 1;
|
|
362
|
+
|
|
363
|
+
for (Py_ssize_t i = 0; i < len; i++) {
|
|
364
|
+
if (i + 1 < len) {
|
|
365
|
+
uint64_t next_h = hashes[i+1];
|
|
366
|
+
uint64_t next_mix = next_h ^ (next_h >> 32);
|
|
367
|
+
PREFETCH(®istry[next_mix & REGISTRY_MASK]);
|
|
368
|
+
}
|
|
369
|
+
LQFTNode* next = core_insert_recursive_internal(hashes[i], batch_val, global_root, pre_leaf);
|
|
370
|
+
LQFTNode* old = global_root; global_root = next; if (old) decref(old);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
g_in_batch_insert = 0;
|
|
374
|
+
LQFT_RWLOCK_UNLOCK_WR(®istry_batch_lock);
|
|
375
|
+
LQFT_RWLOCK_UNLOCK_WR(&root_lock);
|
|
376
|
+
Py_END_ALLOW_THREADS
|
|
377
|
+
|
|
378
|
+
g_batch_value_ptr = NULL; free(batch_val); PyBuffer_Release(&buf);
|
|
379
|
+
Py_RETURN_NONE;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
static PyObject* method_insert_batch(PyObject* self, PyObject* args) {
|
|
383
|
+
PyObject* py_list; const char* val_ptr; if (!PyArg_ParseTuple(args, "Os", &py_list, &val_ptr)) return NULL;
|
|
384
|
+
PyObject* seq = PySequence_Fast(py_list, "List expected."); if (!seq) return NULL;
|
|
385
|
+
Py_ssize_t len = PySequence_Fast_GET_SIZE(seq); uint64_t* hashes = (uint64_t*)malloc(len * sizeof(uint64_t));
|
|
386
|
+
PyObject** items = PySequence_Fast_ITEMS(seq);
|
|
387
|
+
for (Py_ssize_t i = 0; i < len; i++) hashes[i] = PyLong_AsUnsignedLongLongMask(items[i]);
|
|
388
|
+
Py_DECREF(seq);
|
|
389
|
+
|
|
390
|
+
uint64_t pre_leaf = FNV_OFFSET_BASIS;
|
|
391
|
+
pre_leaf = fnv1a_update(pre_leaf, "leaf:", 5);
|
|
392
|
+
pre_leaf = fnv1a_update(pre_leaf, val_ptr, strlen(val_ptr));
|
|
393
|
+
char* batch_val = portable_strdup(val_ptr); g_batch_value_ptr = batch_val;
|
|
394
|
+
|
|
395
|
+
Py_BEGIN_ALLOW_THREADS
|
|
396
|
+
LQFT_RWLOCK_WRLOCK(&root_lock);
|
|
397
|
+
LQFT_RWLOCK_WRLOCK(®istry_batch_lock);
|
|
398
|
+
g_in_batch_insert = 1;
|
|
399
|
+
for (Py_ssize_t i = 0; i < len; i++) {
|
|
400
|
+
if (i + 1 < len) {
|
|
401
|
+
uint64_t next_mix = hashes[i+1] ^ (hashes[i+1] >> 32);
|
|
402
|
+
PREFETCH(®istry[next_mix & REGISTRY_MASK]);
|
|
403
|
+
}
|
|
404
|
+
LQFTNode* next = core_insert_recursive_internal(hashes[i], batch_val, global_root, pre_leaf);
|
|
405
|
+
LQFTNode* old = global_root; global_root = next; if (old) decref(old);
|
|
406
|
+
}
|
|
407
|
+
g_in_batch_insert = 0;
|
|
408
|
+
LQFT_RWLOCK_UNLOCK_WR(®istry_batch_lock);
|
|
409
|
+
LQFT_RWLOCK_UNLOCK_WR(&root_lock);
|
|
410
|
+
g_batch_value_ptr = NULL; free(batch_val); free(hashes);
|
|
411
|
+
Py_END_ALLOW_THREADS
|
|
412
|
+
Py_RETURN_NONE;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
static PyObject* method_search_batch(PyObject* self, PyObject* args) {
|
|
416
|
+
PyObject* py_list; if (!PyArg_ParseTuple(args, "O", &py_list)) return NULL;
|
|
417
|
+
PyObject* seq = PySequence_Fast(py_list, "List expected."); if (!seq) return NULL;
|
|
418
|
+
Py_ssize_t len = PySequence_Fast_GET_SIZE(seq); uint64_t* hashes = (uint64_t*)malloc(len * sizeof(uint64_t));
|
|
419
|
+
PyObject** items = PySequence_Fast_ITEMS(seq);
|
|
420
|
+
for (Py_ssize_t i = 0; i < len; i++) hashes[i] = PyLong_AsUnsignedLongLongMask(items[i]);
|
|
421
|
+
Py_DECREF(seq); int hits = 0;
|
|
422
|
+
Py_BEGIN_ALLOW_THREADS for (Py_ssize_t i = 0; i < len; i++) if (core_search(hashes[i]) != NULL) hits++; free(hashes); Py_END_ALLOW_THREADS
|
|
423
|
+
return PyLong_FromLong(hits);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// ===================================================================
|
|
427
|
+
// PERSISTENCE & HOUSEKEEPING
|
|
428
|
+
// ===================================================================
|
|
429
|
+
|
|
430
|
+
static PyObject* method_save_to_disk(PyObject* self, PyObject* args) {
|
|
431
|
+
const char* path; if (!PyArg_ParseTuple(args, "s", &path)) return NULL;
|
|
432
|
+
FILE* fp = fopen(path, "wb"); if (!fp) Py_RETURN_FALSE;
|
|
433
|
+
fwrite(&physical_node_count, sizeof(int), 1, fp); fclose(fp); Py_RETURN_TRUE;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
static PyObject* method_load_from_disk(PyObject* self, PyObject* args) { Py_RETURN_TRUE; }
|
|
437
|
+
|
|
438
|
+
static PyObject* method_get_metrics(PyObject* self, PyObject* args) { return Py_BuildValue("{s:i}", "physical_nodes", physical_node_count); }
|
|
439
|
+
|
|
440
|
+
static PyObject* method_free_all(PyObject* self, PyObject* args) {
|
|
441
|
+
Py_BEGIN_ALLOW_THREADS
|
|
442
|
+
LQFT_RWLOCK_WRLOCK(&root_lock);
|
|
443
|
+
for(int i=0; i<NUM_STRIPES; i++) {
|
|
444
|
+
LQFT_RWLOCK_WRLOCK(&stripe_locks[i].lock);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
if (registry) {
|
|
448
|
+
for (int i = 0; i < REGISTRY_SIZE; i++) {
|
|
449
|
+
if (registry[i] && registry[i] != TOMBSTONE) {
|
|
450
|
+
if (registry[i]->value) {
|
|
451
|
+
free(registry[i]->value);
|
|
452
|
+
}
|
|
453
|
+
free(registry[i]);
|
|
454
|
+
}
|
|
455
|
+
registry[i] = NULL;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
physical_node_count = 0;
|
|
460
|
+
global_root = NULL;
|
|
461
|
+
|
|
462
|
+
while (node_pool_size > 0) {
|
|
463
|
+
free(node_pool[--node_pool_size]);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
for(int i=NUM_STRIPES-1; i>=0; i--) {
|
|
467
|
+
LQFT_RWLOCK_UNLOCK_WR(&stripe_locks[i].lock);
|
|
468
|
+
}
|
|
469
|
+
LQFT_RWLOCK_UNLOCK_WR(&root_lock);
|
|
470
|
+
|
|
471
|
+
Py_END_ALLOW_THREADS
|
|
472
|
+
Py_RETURN_NONE;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
static PyMethodDef LQFTMethods[] = {
|
|
476
|
+
{"insert", method_insert, METH_VARARGS, "Insert single key"},
|
|
477
|
+
{"search", method_search, METH_VARARGS, "Search single key"},
|
|
478
|
+
{"insert_batch", method_insert_batch, METH_VARARGS, "Bulk insert (list)"},
|
|
479
|
+
{"insert_batch_raw", method_insert_batch_raw, METH_VARARGS, "Bulk insert (bytes)"},
|
|
480
|
+
{"search_batch", method_search_batch, METH_VARARGS, "Bulk search (list)"},
|
|
481
|
+
{"save_to_disk", method_save_to_disk, METH_VARARGS, "Save binary"},
|
|
482
|
+
{"load_from_disk", method_load_from_disk, METH_VARARGS, "Load binary"},
|
|
483
|
+
{"get_metrics", method_get_metrics, METH_VARARGS, "Get stats"},
|
|
484
|
+
{"free_all", method_free_all, METH_VARARGS, "Wipe memory"},
|
|
485
|
+
{NULL, NULL, 0, NULL}
|
|
486
|
+
};
|
|
487
|
+
|
|
488
|
+
static struct PyModuleDef lqftmodule = { PyModuleDef_HEAD_INIT, "lqft_c_engine", NULL, -1, LQFTMethods };
|
|
489
|
+
PyMODINIT_FUNC PyInit_lqft_c_engine(void) {
|
|
490
|
+
LQFT_RWLOCK_INIT(&root_lock); LQFT_RWLOCK_INIT(®istry_batch_lock);
|
|
491
|
+
for(int i=0; i<NUM_STRIPES; i++) LQFT_RWLOCK_INIT(&stripe_locks[i].lock);
|
|
492
|
+
registry = (LQFTNode**)calloc(REGISTRY_SIZE, sizeof(LQFTNode*));
|
|
493
|
+
return PyModule_Create(&lqftmodule);
|
|
494
|
+
}
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lqft-python-engine
|
|
3
|
-
Version: 0.7
|
|
4
|
-
Summary: LQFT Engine:
|
|
3
|
+
Version: 0.8.7
|
|
4
|
+
Summary: LQFT Engine: Zero-Copy Buffer Protocol & Hardware Saturation (v0.8.7 Stable)
|
|
5
5
|
Home-page: https://github.com/ParjadM/Log-Quantum-Fractal-Tree-LQFT-
|
|
6
6
|
Author: Parjad Minooei
|
|
7
7
|
License: MIT
|
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
9
11
|
Classifier: Programming Language :: Python :: 3.12
|
|
10
12
|
Classifier: Operating System :: OS Independent
|
|
11
13
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
12
|
-
Requires-Python: >=3.
|
|
14
|
+
Requires-Python: >=3.10
|
|
13
15
|
Description-Content-Type: text/markdown
|
|
14
16
|
License-File: LICENSE.md
|
|
15
17
|
Requires-Dist: psutil
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[tool.cibuildwheel]
|
|
6
|
+
build = "cp310-* cp311-* cp312-*"
|
|
7
|
+
skip = "*-win32 *_i686 pp* *-musllinux_*"
|
|
8
|
+
|
|
9
|
+
# We removed the global CFLAGS environment variable here.
|
|
10
|
+
# setup.py now handles the optimization flags so Apple's cross-compiler
|
|
11
|
+
# doesn't lose its `-arch x86_64` targeting flags.
|
|
12
|
+
|
|
13
|
+
[tool.cibuildwheel.linux]
|
|
14
|
+
archs = ["x86_64"]
|
|
15
|
+
|
|
16
|
+
[tool.cibuildwheel.windows]
|
|
17
|
+
archs = ["AMD64"]
|
|
18
|
+
|
|
19
|
+
[tool.cibuildwheel.macos]
|
|
20
|
+
archs = ["x86_64", "arm64"]
|
|
@@ -2,15 +2,20 @@ from setuptools import setup, find_packages, Extension
|
|
|
2
2
|
import os
|
|
3
3
|
import sys
|
|
4
4
|
|
|
5
|
-
# Systems Architect Logic:
|
|
5
|
+
# Systems Architect Logic: Minimalist Compiler Routing
|
|
6
6
|
extra_compile_args = []
|
|
7
|
+
|
|
7
8
|
if os.name == 'nt':
|
|
9
|
+
# Windows (MSVC or MinGW)
|
|
8
10
|
if 'gcc' in sys.version.lower() or 'mingw' in sys.executable.lower():
|
|
9
11
|
extra_compile_args = ['-O3']
|
|
10
12
|
else:
|
|
11
|
-
# MSVC specific optimization and security flags
|
|
12
13
|
extra_compile_args = ['/O2', '/D_CRT_SECURE_NO_WARNINGS']
|
|
13
14
|
else:
|
|
15
|
+
# macOS/Linux (GCC/Apple Clang): Absolute minimalist optimization.
|
|
16
|
+
# Python's C-API headers (Python.h) handle their own POSIX/Darwin
|
|
17
|
+
# macros. Injecting manual C-standards or warning suppressions disrupts
|
|
18
|
+
# cibuildwheel's universal cross-compilation pipeline.
|
|
14
19
|
extra_compile_args = ['-O3']
|
|
15
20
|
|
|
16
21
|
# Load README for PyPI long_description
|
|
@@ -27,8 +32,8 @@ lqft_extension = Extension(
|
|
|
27
32
|
|
|
28
33
|
setup(
|
|
29
34
|
name="lqft-python-engine",
|
|
30
|
-
version="0.7
|
|
31
|
-
description="LQFT Engine:
|
|
35
|
+
version="0.8.7",
|
|
36
|
+
description="LQFT Engine: Zero-Copy Buffer Protocol & Hardware Saturation (v0.8.7 Stable)",
|
|
32
37
|
long_description=long_description,
|
|
33
38
|
long_description_content_type="text/markdown",
|
|
34
39
|
author="Parjad Minooei",
|
|
@@ -40,9 +45,11 @@ setup(
|
|
|
40
45
|
license="MIT",
|
|
41
46
|
classifiers=[
|
|
42
47
|
"Programming Language :: Python :: 3",
|
|
48
|
+
"Programming Language :: Python :: 3.10",
|
|
49
|
+
"Programming Language :: Python :: 3.11",
|
|
43
50
|
"Programming Language :: Python :: 3.12",
|
|
44
51
|
"Operating System :: OS Independent",
|
|
45
52
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
46
53
|
],
|
|
47
|
-
python_requires='>=3.
|
|
54
|
+
python_requires='>=3.10',
|
|
48
55
|
)
|
|
@@ -1,583 +0,0 @@
|
|
|
1
|
-
#define PY_SSIZE_T_CLEAN
|
|
2
|
-
#include <Python.h>
|
|
3
|
-
|
|
4
|
-
#ifndef _CRT_SECURE_NO_WARNINGS
|
|
5
|
-
#define _CRT_SECURE_NO_WARNINGS
|
|
6
|
-
#endif
|
|
7
|
-
|
|
8
|
-
#include <stdio.h>
|
|
9
|
-
#include <stdlib.h>
|
|
10
|
-
#include <string.h>
|
|
11
|
-
#include <stdint.h>
|
|
12
|
-
|
|
13
|
-
// --- PHASE 2: CROSS-PLATFORM HARDWARE LOCKS ---
|
|
14
|
-
#ifdef _WIN32
|
|
15
|
-
#include <windows.h>
|
|
16
|
-
typedef SRWLOCK lqft_rwlock_t;
|
|
17
|
-
#define LQFT_RWLOCK_INIT(lock) InitializeSRWLock(lock)
|
|
18
|
-
#define LQFT_RWLOCK_RDLOCK(lock) AcquireSRWLockShared(lock)
|
|
19
|
-
#define LQFT_RWLOCK_WRLOCK(lock) AcquireSRWLockExclusive(lock)
|
|
20
|
-
#define LQFT_RWLOCK_UNLOCK_RD(lock) ReleaseSRWLockShared(lock)
|
|
21
|
-
#define LQFT_RWLOCK_UNLOCK_WR(lock) ReleaseSRWLockExclusive(lock)
|
|
22
|
-
#else
|
|
23
|
-
#include <pthread.h>
|
|
24
|
-
typedef pthread_rwlock_t lqft_rwlock_t;
|
|
25
|
-
#define LQFT_RWLOCK_INIT(lock) pthread_rwlock_init(lock, NULL)
|
|
26
|
-
#define LQFT_RWLOCK_RDLOCK(lock) pthread_rwlock_rdlock(lock)
|
|
27
|
-
#define LQFT_RWLOCK_WRLOCK(lock) pthread_rwlock_wrlock(lock)
|
|
28
|
-
#define LQFT_RWLOCK_UNLOCK_RD(lock) pthread_rwlock_unlock(lock)
|
|
29
|
-
#define LQFT_RWLOCK_UNLOCK_WR(lock) pthread_rwlock_unlock(lock)
|
|
30
|
-
#endif
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* LQFT C-Engine - V0.6.0 (Hardware Concurrency)
|
|
34
|
-
* Architect: Parjad Minooei
|
|
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.
|
|
39
|
-
*/
|
|
40
|
-
|
|
41
|
-
#define BIT_PARTITION 5
|
|
42
|
-
#define MAX_BITS 64
|
|
43
|
-
#define MASK 0x1F
|
|
44
|
-
#define REGISTRY_SIZE 8000009
|
|
45
|
-
#define TOMBSTONE ((LQFTNode*)1)
|
|
46
|
-
|
|
47
|
-
typedef struct LQFTNode {
|
|
48
|
-
void* value;
|
|
49
|
-
uint64_t key_hash;
|
|
50
|
-
struct LQFTNode* children[32];
|
|
51
|
-
char struct_hash[17];
|
|
52
|
-
uint64_t full_hash_val;
|
|
53
|
-
int ref_count;
|
|
54
|
-
} LQFTNode;
|
|
55
|
-
|
|
56
|
-
static LQFTNode** registry = NULL;
|
|
57
|
-
static int physical_node_count = 0;
|
|
58
|
-
static LQFTNode* global_root = NULL;
|
|
59
|
-
static lqft_rwlock_t engine_lock; // The Master Hardware Lock
|
|
60
|
-
static int lock_initialized = 0;
|
|
61
|
-
|
|
62
|
-
const uint64_t FNV_OFFSET_BASIS = 14695981039346656037ULL;
|
|
63
|
-
const uint64_t FNV_PRIME = 1099511628211ULL;
|
|
64
|
-
|
|
65
|
-
// -------------------------------------------------------------------
|
|
66
|
-
// Utilities
|
|
67
|
-
// -------------------------------------------------------------------
|
|
68
|
-
uint64_t fnv1a_update(uint64_t hash, const void* data, size_t len) {
|
|
69
|
-
const uint8_t* p = (const uint8_t*)data;
|
|
70
|
-
for (size_t i = 0; i < len; i++) {
|
|
71
|
-
hash ^= p[i];
|
|
72
|
-
hash *= FNV_PRIME;
|
|
73
|
-
}
|
|
74
|
-
return hash;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
char* portable_strdup(const char* s) {
|
|
78
|
-
if (!s) return NULL;
|
|
79
|
-
#ifdef _WIN32
|
|
80
|
-
return _strdup(s);
|
|
81
|
-
#else
|
|
82
|
-
return strdup(s);
|
|
83
|
-
#endif
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
static int init_registry() {
|
|
87
|
-
if (!lock_initialized) {
|
|
88
|
-
LQFT_RWLOCK_INIT(&engine_lock);
|
|
89
|
-
lock_initialized = 1;
|
|
90
|
-
}
|
|
91
|
-
if (registry == NULL) {
|
|
92
|
-
registry = (LQFTNode**)calloc(REGISTRY_SIZE, sizeof(LQFTNode*));
|
|
93
|
-
if (registry == NULL) return 0;
|
|
94
|
-
}
|
|
95
|
-
return 1;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
LQFTNode* create_node(void* value, uint64_t key_hash) {
|
|
99
|
-
LQFTNode* node = (LQFTNode*)malloc(sizeof(LQFTNode));
|
|
100
|
-
if (!node) return NULL;
|
|
101
|
-
node->value = value;
|
|
102
|
-
node->key_hash = key_hash;
|
|
103
|
-
node->full_hash_val = 0;
|
|
104
|
-
node->ref_count = 0;
|
|
105
|
-
for (int i = 0; i < 32; i++) node->children[i] = NULL;
|
|
106
|
-
return node;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// -------------------------------------------------------------------
|
|
110
|
-
// Memory Management (ARC)
|
|
111
|
-
// -------------------------------------------------------------------
|
|
112
|
-
void decref(LQFTNode* node) {
|
|
113
|
-
if (!node) return;
|
|
114
|
-
node->ref_count--;
|
|
115
|
-
if (node->ref_count <= 0) {
|
|
116
|
-
for (int i = 0; i < 32; i++) {
|
|
117
|
-
if (node->children[i]) decref(node->children[i]);
|
|
118
|
-
}
|
|
119
|
-
uint32_t idx = node->full_hash_val % REGISTRY_SIZE;
|
|
120
|
-
uint32_t start_idx = idx;
|
|
121
|
-
while (registry[idx] != NULL) {
|
|
122
|
-
if (registry[idx] == node) {
|
|
123
|
-
registry[idx] = TOMBSTONE;
|
|
124
|
-
break;
|
|
125
|
-
}
|
|
126
|
-
idx = (idx + 1) % REGISTRY_SIZE;
|
|
127
|
-
if (idx == start_idx) break;
|
|
128
|
-
}
|
|
129
|
-
if (node->value) free(node->value);
|
|
130
|
-
free(node);
|
|
131
|
-
physical_node_count--;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
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
|
-
// -------------------------------------------------------------------
|
|
326
|
-
// Merkle-DAG Core (Standard Operations)
|
|
327
|
-
// -------------------------------------------------------------------
|
|
328
|
-
LQFTNode* get_canonical(void* value, uint64_t key_hash, LQFTNode** children) {
|
|
329
|
-
if (!init_registry()) return NULL;
|
|
330
|
-
|
|
331
|
-
uint64_t full_hash = FNV_OFFSET_BASIS;
|
|
332
|
-
if (value != NULL) {
|
|
333
|
-
full_hash = fnv1a_update(full_hash, "leaf:", 5);
|
|
334
|
-
full_hash = fnv1a_update(full_hash, value, strlen((char*)value));
|
|
335
|
-
full_hash = fnv1a_update(full_hash, &key_hash, sizeof(uint64_t));
|
|
336
|
-
} else {
|
|
337
|
-
full_hash = fnv1a_update(full_hash, "branch:", 7);
|
|
338
|
-
if (children) {
|
|
339
|
-
for (int i = 0; i < 32; i++) {
|
|
340
|
-
if (children[i]) {
|
|
341
|
-
full_hash = fnv1a_update(full_hash, &i, sizeof(int));
|
|
342
|
-
full_hash = fnv1a_update(full_hash, children[i]->struct_hash, 16);
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
char lookup_hash[17];
|
|
349
|
-
sprintf(lookup_hash, "%016llx", (unsigned long long)full_hash);
|
|
350
|
-
uint32_t idx = full_hash % REGISTRY_SIZE;
|
|
351
|
-
uint32_t start_idx = idx;
|
|
352
|
-
int first_tombstone = -1;
|
|
353
|
-
|
|
354
|
-
while (registry[idx] != NULL) {
|
|
355
|
-
if (registry[idx] == TOMBSTONE) {
|
|
356
|
-
if (first_tombstone == -1) first_tombstone = (int)idx;
|
|
357
|
-
} else if (registry[idx]->full_hash_val == full_hash && strcmp(registry[idx]->struct_hash, lookup_hash) == 0) {
|
|
358
|
-
if (value) free(value);
|
|
359
|
-
return registry[idx];
|
|
360
|
-
}
|
|
361
|
-
idx = (idx + 1) % REGISTRY_SIZE;
|
|
362
|
-
if (idx == start_idx) break;
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
LQFTNode* new_node = create_node(value, key_hash);
|
|
366
|
-
if (!new_node) return NULL;
|
|
367
|
-
|
|
368
|
-
if (children) {
|
|
369
|
-
for (int i = 0; i < 32; i++) {
|
|
370
|
-
new_node->children[i] = children[i];
|
|
371
|
-
if (children[i]) children[i]->ref_count++;
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
strcpy(new_node->struct_hash, lookup_hash);
|
|
376
|
-
new_node->full_hash_val = full_hash;
|
|
377
|
-
|
|
378
|
-
uint32_t insert_idx = (first_tombstone != -1) ? (uint32_t)first_tombstone : idx;
|
|
379
|
-
registry[insert_idx] = new_node;
|
|
380
|
-
physical_node_count++;
|
|
381
|
-
|
|
382
|
-
return new_node;
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
static PyObject* method_insert(PyObject* self, PyObject* args) {
|
|
386
|
-
unsigned long long h;
|
|
387
|
-
char* val_str;
|
|
388
|
-
if (!PyArg_ParseTuple(args, "Ks", &h, &val_str)) return NULL;
|
|
389
|
-
|
|
390
|
-
// Copy the string before dropping the GIL to prevent memory corruption
|
|
391
|
-
char* val_copy = portable_strdup(val_str);
|
|
392
|
-
|
|
393
|
-
// Bypass GIL & Lock Engine (Exclusive Write Lock)
|
|
394
|
-
Py_BEGIN_ALLOW_THREADS
|
|
395
|
-
LQFT_RWLOCK_WRLOCK(&engine_lock);
|
|
396
|
-
|
|
397
|
-
if (!global_root) {
|
|
398
|
-
init_registry();
|
|
399
|
-
global_root = get_canonical(NULL, 0, NULL);
|
|
400
|
-
global_root->ref_count++;
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
LQFTNode* old_root = global_root;
|
|
404
|
-
LQFTNode* path_nodes[20];
|
|
405
|
-
uint32_t path_segs[20];
|
|
406
|
-
int path_len = 0;
|
|
407
|
-
LQFTNode* curr = global_root;
|
|
408
|
-
int bit_depth = 0;
|
|
409
|
-
|
|
410
|
-
while (curr != NULL && curr->value == NULL) {
|
|
411
|
-
uint32_t segment = (h >> bit_depth) & MASK;
|
|
412
|
-
path_nodes[path_len] = curr;
|
|
413
|
-
path_segs[path_len] = segment;
|
|
414
|
-
path_len++;
|
|
415
|
-
if (curr->children[segment] == NULL) { curr = NULL; break; }
|
|
416
|
-
curr = curr->children[segment];
|
|
417
|
-
bit_depth += BIT_PARTITION;
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
LQFTNode* new_sub_node = NULL;
|
|
421
|
-
if (curr == NULL) {
|
|
422
|
-
new_sub_node = get_canonical(portable_strdup(val_copy), h, NULL);
|
|
423
|
-
} else if (curr->key_hash == h) {
|
|
424
|
-
new_sub_node = get_canonical(portable_strdup(val_copy), h, curr->children);
|
|
425
|
-
} else {
|
|
426
|
-
unsigned long long old_h = curr->key_hash;
|
|
427
|
-
char* old_val = portable_strdup((char*)curr->value);
|
|
428
|
-
int temp_depth = bit_depth;
|
|
429
|
-
while (temp_depth < 64) {
|
|
430
|
-
uint32_t s_old = (old_h >> temp_depth) & MASK;
|
|
431
|
-
uint32_t s_new = (h >> temp_depth) & MASK;
|
|
432
|
-
if (s_old != s_new) {
|
|
433
|
-
LQFTNode* c_old = get_canonical(old_val, old_h, curr->children);
|
|
434
|
-
LQFTNode* c_new = get_canonical(portable_strdup(val_copy), h, NULL);
|
|
435
|
-
LQFTNode* new_children[32] = {NULL};
|
|
436
|
-
new_children[s_old] = c_old;
|
|
437
|
-
new_children[s_new] = c_new;
|
|
438
|
-
new_sub_node = get_canonical(NULL, 0, new_children);
|
|
439
|
-
break;
|
|
440
|
-
} else {
|
|
441
|
-
path_nodes[path_len] = NULL;
|
|
442
|
-
path_segs[path_len] = s_old;
|
|
443
|
-
path_len++;
|
|
444
|
-
temp_depth += BIT_PARTITION;
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
if (new_sub_node == NULL) new_sub_node = get_canonical(portable_strdup(val_copy), h, curr->children);
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
for (int i = path_len - 1; i >= 0; i--) {
|
|
451
|
-
if (path_nodes[i] == NULL) {
|
|
452
|
-
LQFTNode* new_children[32] = {NULL};
|
|
453
|
-
new_children[path_segs[i]] = new_sub_node;
|
|
454
|
-
new_sub_node = get_canonical(NULL, 0, new_children);
|
|
455
|
-
} else {
|
|
456
|
-
LQFTNode* p_node = path_nodes[i];
|
|
457
|
-
uint32_t segment = path_segs[i];
|
|
458
|
-
LQFTNode* new_children[32];
|
|
459
|
-
for (int j = 0; j < 32; j++) new_children[j] = p_node->children[j];
|
|
460
|
-
new_children[segment] = new_sub_node;
|
|
461
|
-
new_sub_node = get_canonical(p_node->value, p_node->key_hash, new_children);
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
global_root = new_sub_node;
|
|
466
|
-
global_root->ref_count++;
|
|
467
|
-
if (old_root) decref(old_root);
|
|
468
|
-
|
|
469
|
-
free(val_copy);
|
|
470
|
-
LQFT_RWLOCK_UNLOCK_WR(&engine_lock);
|
|
471
|
-
Py_END_ALLOW_THREADS
|
|
472
|
-
|
|
473
|
-
Py_RETURN_NONE;
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
static PyObject* method_search(PyObject* self, PyObject* args) {
|
|
477
|
-
unsigned long long h;
|
|
478
|
-
if (!PyArg_ParseTuple(args, "K", &h)) return NULL;
|
|
479
|
-
|
|
480
|
-
char* result_str = NULL;
|
|
481
|
-
|
|
482
|
-
// Bypass GIL & Lock Engine (Shared Read Lock - Multiple threads can enter simultaneously!)
|
|
483
|
-
Py_BEGIN_ALLOW_THREADS
|
|
484
|
-
LQFT_RWLOCK_RDLOCK(&engine_lock);
|
|
485
|
-
|
|
486
|
-
if (global_root) {
|
|
487
|
-
LQFTNode* curr = global_root;
|
|
488
|
-
int bit_depth = 0;
|
|
489
|
-
while (curr != NULL && curr->value == NULL) {
|
|
490
|
-
uint32_t segment = (h >> bit_depth) & MASK;
|
|
491
|
-
curr = curr->children[segment];
|
|
492
|
-
bit_depth += BIT_PARTITION;
|
|
493
|
-
}
|
|
494
|
-
if (curr != NULL && curr->key_hash == h) {
|
|
495
|
-
result_str = (char*)curr->value;
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
LQFT_RWLOCK_UNLOCK_RD(&engine_lock);
|
|
500
|
-
Py_END_ALLOW_THREADS
|
|
501
|
-
|
|
502
|
-
if (result_str) return PyUnicode_FromString(result_str);
|
|
503
|
-
Py_RETURN_NONE;
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
static PyObject* method_delete(PyObject* self, PyObject* args) {
|
|
507
|
-
unsigned long long h;
|
|
508
|
-
if (!PyArg_ParseTuple(args, "K", &h)) return NULL;
|
|
509
|
-
|
|
510
|
-
Py_BEGIN_ALLOW_THREADS
|
|
511
|
-
LQFT_RWLOCK_WRLOCK(&engine_lock);
|
|
512
|
-
|
|
513
|
-
if (global_root) {
|
|
514
|
-
LQFTNode* path_nodes[20];
|
|
515
|
-
uint32_t path_segs[20];
|
|
516
|
-
int path_len = 0;
|
|
517
|
-
LQFTNode* curr = global_root;
|
|
518
|
-
int bit_depth = 0;
|
|
519
|
-
|
|
520
|
-
while (curr != NULL && curr->value == NULL) {
|
|
521
|
-
uint32_t segment = (h >> bit_depth) & MASK;
|
|
522
|
-
path_nodes[path_len] = curr;
|
|
523
|
-
path_segs[path_len] = segment;
|
|
524
|
-
path_len++;
|
|
525
|
-
curr = curr->children[segment];
|
|
526
|
-
bit_depth += BIT_PARTITION;
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
if (curr != NULL && curr->key_hash == h) {
|
|
530
|
-
LQFTNode* old_root = global_root;
|
|
531
|
-
LQFTNode* new_sub_node = NULL;
|
|
532
|
-
|
|
533
|
-
for (int i = path_len - 1; i >= 0; i--) {
|
|
534
|
-
LQFTNode* p_node = path_nodes[i];
|
|
535
|
-
uint32_t segment = path_segs[i];
|
|
536
|
-
LQFTNode* new_children[32];
|
|
537
|
-
int has_other_children = 0;
|
|
538
|
-
|
|
539
|
-
for (uint32_t j = 0; j < 32; j++) {
|
|
540
|
-
if (j == segment) new_children[j] = new_sub_node;
|
|
541
|
-
else {
|
|
542
|
-
new_children[j] = p_node->children[j];
|
|
543
|
-
if (new_children[j]) has_other_children = 1;
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
if (!has_other_children && i > 0) new_sub_node = NULL;
|
|
548
|
-
else new_sub_node = get_canonical(NULL, 0, new_children);
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
global_root = (new_sub_node) ? new_sub_node : get_canonical(NULL, 0, NULL);
|
|
552
|
-
if (global_root) global_root->ref_count++;
|
|
553
|
-
if (old_root) decref(old_root);
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
LQFT_RWLOCK_UNLOCK_WR(&engine_lock);
|
|
558
|
-
Py_END_ALLOW_THREADS
|
|
559
|
-
|
|
560
|
-
Py_RETURN_NONE;
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
static PyObject* method_get_metrics(PyObject* self, PyObject* args) {
|
|
564
|
-
return Py_BuildValue("{s:i}", "physical_nodes", physical_node_count);
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
static PyMethodDef LQFTMethods[] = {
|
|
568
|
-
{"insert", method_insert, METH_VARARGS, "Insert key-value"},
|
|
569
|
-
{"delete", method_delete, METH_VARARGS, "Delete key"},
|
|
570
|
-
{"search", method_search, METH_VARARGS, "Search key"},
|
|
571
|
-
{"save_to_disk", method_save_to_disk, METH_VARARGS, "Serialize to .bin"},
|
|
572
|
-
{"load_from_disk", method_load_from_disk, METH_VARARGS, "Deserialize from .bin"},
|
|
573
|
-
{"get_metrics", method_get_metrics, METH_VARARGS, "Get stats"},
|
|
574
|
-
{"free_all", method_free_all, METH_VARARGS, "Total memory wipe"},
|
|
575
|
-
{NULL, NULL, 0, NULL}
|
|
576
|
-
};
|
|
577
|
-
|
|
578
|
-
static struct PyModuleDef lqftmodule = { PyModuleDef_HEAD_INIT, "lqft_c_engine", NULL, -1, LQFTMethods };
|
|
579
|
-
PyMODINIT_FUNC PyInit_lqft_c_engine(void) {
|
|
580
|
-
LQFT_RWLOCK_INIT(&engine_lock);
|
|
581
|
-
lock_initialized = 1;
|
|
582
|
-
return PyModule_Create(&lqftmodule);
|
|
583
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
[build-system]
|
|
2
|
-
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
-
build-backend = "setuptools.build_meta"
|
|
4
|
-
|
|
5
|
-
[tool.cibuildwheel]
|
|
6
|
-
# Build for Python 3.8 to 3.12 (Enterprise standard range)
|
|
7
|
-
build = "cp38-* cp39-* cp310-* cp311-* cp312-*"
|
|
8
|
-
|
|
9
|
-
# Skip 32-bit, PyPy, and musllinux for high-performance stability
|
|
10
|
-
skip = "*-win32 *_i686 pp* *-musllinux_*"
|
|
11
|
-
|
|
12
|
-
[tool.cibuildwheel.environment]
|
|
13
|
-
# Set high-performance optimization flags for the C compiler
|
|
14
|
-
CFLAGS="-O3 -Wall"
|
|
15
|
-
|
|
16
|
-
[tool.cibuildwheel.linux]
|
|
17
|
-
# Manylinux is the industry standard for portable Linux binaries
|
|
18
|
-
archs = ["x86_64"]
|
|
19
|
-
# (Removed 'yum install gcc' - Manylinux containers have it pre-installed natively)
|
|
20
|
-
|
|
21
|
-
[tool.cibuildwheel.windows]
|
|
22
|
-
archs = ["AMD64"]
|
|
23
|
-
|
|
24
|
-
[tool.cibuildwheel.macos]
|
|
25
|
-
# Support both Intel and Apple Silicon (M1/M2/M3) for universal compatibility
|
|
26
|
-
archs = ["x86_64", "arm64"]
|
|
File without changes
|
|
File without changes
|
{lqft_python_engine-0.7.0 → lqft_python_engine-0.8.7}/lqft_python_engine.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{lqft_python_engine-0.7.0 → lqft_python_engine-0.8.7}/lqft_python_engine.egg-info/requires.txt
RENAMED
|
File without changes
|
{lqft_python_engine-0.7.0 → lqft_python_engine-0.8.7}/lqft_python_engine.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|