From 482bc3a0dbbeed644e91c2a0159ada588dccfbf3 Mon Sep 17 00:00:00 2001 From: Abe Tomoaki Date: Fri, 25 Oct 2024 08:50:23 +0900 Subject: [PATCH 1/4] Fix: JS: Improve error handling of batch addition Crash if there is an error in batch addition. Example: ``` const usearch = require('usearch'); const index = new usearch.Index({ metric: 'l2sq', connectivity: 16, dimensions: 3 }); index.add(42n, new Float32Array([0.2, 0.6, 0.4])); index.add( [41n, 42n, 43n], [[0.1, 0.6, 0.4], [0.2, 0.6, 0.4], [0.3, 0.6, 0.4]] ) ``` `42n` is duplicated, which causes an error, but then it crash. It seems that it is not better to throw an exception during the process, so we changed it to throw it after it is completed. --- javascript/lib.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/javascript/lib.cpp b/javascript/lib.cpp index b259f0b0..b82534a9 100644 --- a/javascript/lib.cpp +++ b/javascript/lib.cpp @@ -165,13 +165,16 @@ void CompiledIndex::Add(Napi::CallbackInfo const& ctx) { // Create an instance of the executor with the default number of threads auto run_parallel = [&](auto vectors) { + std::string error = ""; executor_stl_t executor; executor.fixed(tasks, [&](std::size_t /*thread_idx*/, std::size_t task_idx) { add_result_t result = native_->add(static_cast(keys[task_idx]), vectors + task_idx * native_->dimensions()); if (!result) - Napi::Error::New(ctx.Env(), result.error.release()).ThrowAsJavaScriptException(); + error += ""; }); + if (error.size() > 0) + Napi::Error::New(ctx.Env(), error).ThrowAsJavaScriptException(); }; Napi::TypedArray vectors = ctx[1].As(); From b20a6e9e9b296c65c0e2009a9d3ee41f185c9a6e Mon Sep 17 00:00:00 2001 From: Abe Tomoaki Date: Fri, 1 Nov 2024 15:01:10 +0900 Subject: [PATCH 2/4] Update tests --- javascript/usearch.test.js | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/javascript/usearch.test.js b/javascript/usearch.test.js index 5210a2bd..482c994f 100644 --- a/javascript/usearch.test.js +++ b/javascript/usearch.test.js @@ -166,7 +166,28 @@ test('Invalid operations', async (t) => { () => index.add(42n, new Float32Array([0.2, 0.6, 0.4])), { name: 'Error', - message: 'Duplicate keys not allowed in high-level wrappers' + message: '' + } + ); + }); + + await t.test('Batch add containing the same key', () => { + const index = new usearch.Index({ + metric: "l2sq", + connectivity: 16, + dimensions: 3, + }); + index.add(42n, new Float32Array([0.2, 0.6, 0.4])); + assert.throws( + () => { + index.add( + [41n, 42n, 43n], + [[0.1, 0.6, 0.4], [0.2, 0.6, 0.4], [0.3, 0.6, 0.4]] + ); + }, + { + name: 'Error', + message: '' } ); }); @@ -232,7 +253,7 @@ test('Serialization', async (t) => { () => index.add(43n, new Float32Array([0.2, 0.6, 0.4])), { name: 'Error', - message: "Can't add to an immutable index" + message: "" } ); }); From 8884a8d54090b43fe7bebbea8fb3908d72452c07 Mon Sep 17 00:00:00 2001 From: Abe Tomoaki Date: Sat, 2 Nov 2024 20:42:12 +0900 Subject: [PATCH 3/4] Use mutex --- javascript/lib.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/javascript/lib.cpp b/javascript/lib.cpp index b82534a9..f583c933 100644 --- a/javascript/lib.cpp +++ b/javascript/lib.cpp @@ -44,6 +44,7 @@ class CompiledIndex : public Napi::ObjectWrap { Napi::Value Count(Napi::CallbackInfo const& ctx); std::unique_ptr native_; + std::mutex mtx; }; Napi::Object CompiledIndex::Init(Napi::Env env, Napi::Object exports) { @@ -170,8 +171,10 @@ void CompiledIndex::Add(Napi::CallbackInfo const& ctx) { executor.fixed(tasks, [&](std::size_t /*thread_idx*/, std::size_t task_idx) { add_result_t result = native_->add(static_cast(keys[task_idx]), vectors + task_idx * native_->dimensions()); - if (!result) + if (!result) { + std::lock_guard lock(mtx); error += ""; + } }); if (error.size() > 0) Napi::Error::New(ctx.Env(), error).ThrowAsJavaScriptException(); From aaac9eca5e1dd3abff783dc77150ef04f2fcb20a Mon Sep 17 00:00:00 2001 From: Abe Tomoaki Date: Sat, 2 Nov 2024 20:42:34 +0900 Subject: [PATCH 4/4] Use `append` instead of `+` --- javascript/lib.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/javascript/lib.cpp b/javascript/lib.cpp index f583c933..81f5c2d7 100644 --- a/javascript/lib.cpp +++ b/javascript/lib.cpp @@ -173,7 +173,12 @@ void CompiledIndex::Add(Napi::CallbackInfo const& ctx) { vectors + task_idx * native_->dimensions()); if (!result) { std::lock_guard lock(mtx); - error += ""; + error + .append(""); } }); if (error.size() > 0)