From 1b5aa3a76139b19f15c3c3e850e9873116aa3b5d Mon Sep 17 00:00:00 2001 From: Ryan Petrich Date: Sat, 23 Jun 2018 15:49:20 -0400 Subject: [PATCH 1/3] Add support for node 10.5's --experimental-worker threading support --- src/async.h | 4 ++-- src/database.cc | 16 ++++++++-------- src/database.h | 6 +++++- src/macros.h | 2 +- src/statement.cc | 2 +- src/statement.h | 2 +- 6 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/async.h b/src/async.h index 5232c127d..29ca28a0f 100644 --- a/src/async.h +++ b/src/async.h @@ -22,11 +22,11 @@ template class Async { Parent* parent; public: - Async(Parent* parent_, Callback cb_) + Async(uv_loop_t* loop_, Parent* parent_, Callback cb_) : callback(cb_), parent(parent_) { watcher.data = this; NODE_SQLITE3_MUTEX_INIT - uv_async_init(uv_default_loop(), &watcher, reinterpret_cast(listener)); + uv_async_init(loop_, &watcher, reinterpret_cast(listener)); } static void listener(uv_async_t* handle, int status) { diff --git a/src/database.cc b/src/database.cc index 4dbd5c6ab..609c2cb6c 100644 --- a/src/database.cc +++ b/src/database.cc @@ -127,7 +127,7 @@ NAN_METHOD(Database::New) { callback = Local::Cast(info[pos++]); } - Database* db = new Database(); + Database* db = new Database(node::GetCurrentEventLoop(info.GetIsolate())); db->Wrap(info.This()); Nan::ForceSet(info.This(), Nan::New("filename").ToLocalChecked(), info[0].As(), ReadOnly); @@ -141,7 +141,7 @@ NAN_METHOD(Database::New) { } void Database::Work_BeginOpen(Baton* baton) { - int status = uv_queue_work(uv_default_loop(), + int status = uv_queue_work(baton->db->loop, &baton->request, Work_Open, (uv_after_work_cb)Work_AfterOpen); assert(status == 0); } @@ -227,7 +227,7 @@ void Database::Work_BeginClose(Baton* baton) { baton->db->RemoveCallbacks(); baton->db->closing = true; - int status = uv_queue_work(uv_default_loop(), + int status = uv_queue_work(baton->db->loop, &baton->request, Work_Close, (uv_after_work_cb)Work_AfterClose); assert(status == 0); } @@ -388,7 +388,7 @@ void Database::RegisterTraceCallback(Baton* baton) { if (db->debug_trace == NULL) { // Add it. - db->debug_trace = new AsyncTrace(db, TraceCallback); + db->debug_trace = new AsyncTrace(db->loop, db, TraceCallback); sqlite3_trace(db->_handle, TraceCallback, db); } else { @@ -426,7 +426,7 @@ void Database::RegisterProfileCallback(Baton* baton) { if (db->debug_profile == NULL) { // Add it. - db->debug_profile = new AsyncProfile(db, ProfileCallback); + db->debug_profile = new AsyncProfile(db->loop, db, ProfileCallback); sqlite3_profile(db->_handle, ProfileCallback, db); } else { @@ -467,7 +467,7 @@ void Database::RegisterUpdateCallback(Baton* baton) { if (db->update_event == NULL) { // Add it. - db->update_event = new AsyncUpdate(db, UpdateCallback); + db->update_event = new AsyncUpdate(db->loop, db, UpdateCallback); sqlite3_update_hook(db->_handle, UpdateCallback, db); } else { @@ -522,7 +522,7 @@ void Database::Work_BeginExec(Baton* baton) { assert(baton->db->open); assert(baton->db->_handle); assert(baton->db->pending == 0); - int status = uv_queue_work(uv_default_loop(), + int status = uv_queue_work(baton->db->loop, &baton->request, Work_Exec, (uv_after_work_cb)Work_AfterExec); assert(status == 0); } @@ -622,7 +622,7 @@ void Database::Work_BeginLoadExtension(Baton* baton) { assert(baton->db->open); assert(baton->db->_handle); assert(baton->db->pending == 0); - int status = uv_queue_work(uv_default_loop(), + int status = uv_queue_work(baton->db->loop, &baton->request, Work_LoadExtension, reinterpret_cast(Work_AfterLoadExtension)); assert(status == 0); } diff --git a/src/database.h b/src/database.h index c5455abe3..7d3c0eaa1 100644 --- a/src/database.h +++ b/src/database.h @@ -100,8 +100,9 @@ class Database : public Nan::ObjectWrap { friend class Statement; protected: - Database() : Nan::ObjectWrap(), + Database(uv_loop_t* loop_) : Nan::ObjectWrap(), _handle(NULL), + loop(loop_), open(false), closing(false), locked(false), @@ -172,7 +173,10 @@ class Database : public Nan::ObjectWrap { protected: sqlite3* _handle; +public: + uv_loop_t* loop; +protected: bool open; bool closing; bool locked; diff --git a/src/macros.h b/src/macros.h index 38399ee86..d08b5ecf3 100644 --- a/src/macros.h +++ b/src/macros.h @@ -122,7 +122,7 @@ const char* sqlite_authorizer_string(int type); assert(baton->stmt->prepared); \ baton->stmt->locked = true; \ baton->stmt->db->pending++; \ - int status = uv_queue_work(uv_default_loop(), \ + int status = uv_queue_work(baton->stmt->db->loop, \ &baton->request, \ Work_##type, reinterpret_cast(Work_After##type)); \ assert(status == 0); diff --git a/src/statement.cc b/src/statement.cc index 6efbe5766..00df6388e 100644 --- a/src/statement.cc +++ b/src/statement.cc @@ -115,7 +115,7 @@ NAN_METHOD(Statement::New) { void Statement::Work_BeginPrepare(Database::Baton* baton) { assert(baton->db->open); baton->db->pending++; - int status = uv_queue_work(uv_default_loop(), + int status = uv_queue_work(baton->db->loop, &baton->request, Work_Prepare, (uv_after_work_cb)Work_AfterPrepare); assert(status == 0); } diff --git a/src/statement.h b/src/statement.h index 90d295b70..39f12d3c0 100644 --- a/src/statement.h +++ b/src/statement.h @@ -174,7 +174,7 @@ class Statement : public Nan::ObjectWrap { watcher.data = this; NODE_SQLITE3_MUTEX_INIT stmt->Ref(); - uv_async_init(uv_default_loop(), &watcher, async_cb); + uv_async_init(stmt->db->loop, &watcher, async_cb); } ~Async() { From c7bdf1fce42d1625a1c98e4d8455b9858aa1167f Mon Sep 17 00:00:00 2001 From: Ryan Petrich Date: Sat, 23 Jun 2018 15:55:04 -0400 Subject: [PATCH 2/3] Add test:worker script that runs the mocha tests inside a worker --- package.json | 3 ++- scripts/mocha-as-worker.js | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 scripts/mocha-as-worker.js diff --git a/package.json b/package.json index 75298c144..25e5d0871 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,8 @@ "prepublishOnly": "npm ls", "install": "node-pre-gyp install --fallback-to-build", "pretest": "node test/support/createdb.js", - "test": "mocha -R spec --timeout 480000" + "test": "mocha -R spec --timeout 480000", + "test:worker": "node --experimental-worker scripts/mocha-as-worker.js -R spec --timeout 480000" }, "license": "BSD-3-Clause", "keywords": [ diff --git a/scripts/mocha-as-worker.js b/scripts/mocha-as-worker.js new file mode 100644 index 000000000..9803e89de --- /dev/null +++ b/scripts/mocha-as-worker.js @@ -0,0 +1,13 @@ +// Run the mocha tests in a worker +// Not a clean approach, but is sufficient to verify correctness +const worker_threads = require("worker_threads"); +const path = require("path"); + +if (worker_threads.isMainThread) { + const worker = new worker_threads.Worker(__filename, { workerData: { windowSize: process.stdout.getWindowSize() } }); + worker.on("error", console.error); +} else { + process.stdout.getWindowSize = () => worker_threads.workerData.windowSize; + const mochaPath = path.resolve(require.resolve("mocha"), "../bin/_mocha"); + require(mochaPath); +} From f91b4fe488722591d69c4279ba96a95214c43dd2 Mon Sep 17 00:00:00 2001 From: Ryan Petrich Date: Sat, 23 Jun 2018 16:10:20 -0400 Subject: [PATCH 3/3] Use the default loop when running on node 9 or earlier --- src/database.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/database.cc b/src/database.cc index 609c2cb6c..18a597958 100644 --- a/src/database.cc +++ b/src/database.cc @@ -127,7 +127,12 @@ NAN_METHOD(Database::New) { callback = Local::Cast(info[pos++]); } - Database* db = new Database(node::GetCurrentEventLoop(info.GetIsolate())); +#if NODE_MODULE_VERSION > NODE_9_0_MODULE_VERSION + uv_loop_t* loop = node::GetCurrentEventLoop(info.GetIsolate()); +#else + uv_loop_t* loop = uv_default_loop(); +#endif + Database* db = new Database(loop); db->Wrap(info.This()); Nan::ForceSet(info.This(), Nan::New("filename").ToLocalChecked(), info[0].As(), ReadOnly);