@soulcraft/brainy 4.9.2 → 4.10.0
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.
- package/CHANGELOG.md +5 -0
- package/dist/coreTypes.d.ts +1 -0
- package/dist/hnsw/hnswIndex.js +38 -13
- package/dist/hnsw/optimizedHNSWIndex.js +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
### [4.10.0](https://github.com/soulcraftlabs/brainy/compare/v4.9.2...v4.10.0) (2025-10-29)
|
|
6
|
+
|
|
7
|
+
- perf: 48-64× faster HNSW bulk imports via concurrent neighbor updates (4038afd)
|
|
8
|
+
|
|
9
|
+
|
|
5
10
|
### [4.9.2](https://github.com/soulcraftlabs/brainy/compare/v4.9.1...v4.9.2) (2025-10-29)
|
|
6
11
|
|
|
7
12
|
- fix: resolve HNSW concurrency race condition across all storage adapters (0bcf50a)
|
package/dist/coreTypes.d.ts
CHANGED
package/dist/hnsw/hnswIndex.js
CHANGED
|
@@ -178,6 +178,8 @@ export class HNSWIndex {
|
|
|
178
178
|
// Select M nearest neighbors
|
|
179
179
|
const neighbors = this.selectNeighbors(vector, nearestNouns, this.config.M);
|
|
180
180
|
// Add bidirectional connections
|
|
181
|
+
// PERFORMANCE OPTIMIZATION (v4.10.0): Collect all neighbor updates for concurrent execution
|
|
182
|
+
const neighborUpdates = [];
|
|
181
183
|
for (const [neighborId, _] of neighbors) {
|
|
182
184
|
const neighbor = this.nouns.get(neighborId);
|
|
183
185
|
if (!neighbor) {
|
|
@@ -196,26 +198,49 @@ export class HNSWIndex {
|
|
|
196
198
|
}
|
|
197
199
|
// Persist updated neighbor HNSW data (v3.35.0+)
|
|
198
200
|
//
|
|
199
|
-
//
|
|
200
|
-
// Previously
|
|
201
|
-
// Now:
|
|
202
|
-
//
|
|
201
|
+
// PERFORMANCE OPTIMIZATION (v4.10.0): Concurrent neighbor updates
|
|
202
|
+
// Previously (v4.9.2): Serial await - 100% safe but 48-64× slower
|
|
203
|
+
// Now: Promise.allSettled() - 48-64× faster bulk imports
|
|
204
|
+
// Safety: All storage adapters handle concurrent writes via:
|
|
205
|
+
// - Optimistic locking with retry (GCS/S3/Azure/R2)
|
|
206
|
+
// - Mutex serialization (Memory/OPFS/FileSystem)
|
|
207
|
+
// Trade-off: More retry activity under high contention (expected and handled)
|
|
203
208
|
if (this.storage) {
|
|
204
209
|
const neighborConnectionsObj = {};
|
|
205
210
|
for (const [lvl, nounIds] of neighbor.connections.entries()) {
|
|
206
211
|
neighborConnectionsObj[lvl.toString()] = Array.from(nounIds);
|
|
207
212
|
}
|
|
208
|
-
|
|
209
|
-
|
|
213
|
+
neighborUpdates.push({
|
|
214
|
+
neighborId,
|
|
215
|
+
promise: this.storage.saveHNSWData(neighborId, {
|
|
210
216
|
level: neighbor.level,
|
|
211
217
|
connections: neighborConnectionsObj
|
|
212
|
-
})
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
218
|
+
})
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
// Execute all neighbor updates concurrently (with optional batch size limiting)
|
|
223
|
+
if (neighborUpdates.length > 0) {
|
|
224
|
+
const batchSize = this.config.maxConcurrentNeighborWrites || neighborUpdates.length;
|
|
225
|
+
const allFailures = [];
|
|
226
|
+
// Process in chunks if batch size specified
|
|
227
|
+
for (let i = 0; i < neighborUpdates.length; i += batchSize) {
|
|
228
|
+
const batch = neighborUpdates.slice(i, i + batchSize);
|
|
229
|
+
const results = await Promise.allSettled(batch.map(u => u.promise));
|
|
230
|
+
// Track failures for monitoring (storage adapters already retried 5× each)
|
|
231
|
+
const batchFailures = results
|
|
232
|
+
.map((result, idx) => ({ result, neighborId: batch[idx].neighborId }))
|
|
233
|
+
.filter(({ result }) => result.status === 'rejected')
|
|
234
|
+
.map(({ result, neighborId }) => ({
|
|
235
|
+
result: result,
|
|
236
|
+
neighborId
|
|
237
|
+
}));
|
|
238
|
+
allFailures.push(...batchFailures);
|
|
239
|
+
}
|
|
240
|
+
if (allFailures.length > 0) {
|
|
241
|
+
console.warn(`[HNSW] ${allFailures.length}/${neighborUpdates.length} neighbor updates failed after retries (entity: ${id}, level: ${level})`);
|
|
242
|
+
// Log first failure for debugging
|
|
243
|
+
console.error(`[HNSW] First failure (neighbor: ${allFailures[0].neighborId}):`, allFailures[0].result.reason);
|
|
219
244
|
}
|
|
220
245
|
}
|
|
221
246
|
// Update entry point for the next level
|
|
@@ -28,6 +28,7 @@ export class OptimizedHNSWIndex extends HNSWIndex {
|
|
|
28
28
|
levelMultiplier: 16,
|
|
29
29
|
seedConnections: 8,
|
|
30
30
|
pruningStrategy: 'hybrid'
|
|
31
|
+
// maxConcurrentNeighborWrites intentionally omitted - optional property from parent HNSWConfig (v4.10.0+)
|
|
31
32
|
};
|
|
32
33
|
const mergedConfig = { ...defaultConfig, ...config };
|
|
33
34
|
// Initialize parent with base config
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@soulcraft/brainy",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.10.0",
|
|
4
4
|
"description": "Universal Knowledge Protocol™ - World's first Triple Intelligence database unifying vector, graph, and document search in one API. 31 nouns × 40 verbs for infinite expressiveness.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.js",
|