From 796a2fecd5135af93fd52563e6d62f0080fed6a7 Mon Sep 17 00:00:00 2001 From: Oscar Franco Date: Fri, 4 Oct 2024 08:45:47 +0200 Subject: [PATCH] Invalidate HostObjects on module hot reload --- cpp/DBHostObject.cpp | 30 ++++++++++++++++++++++-------- cpp/DBHostObject.h | 3 +++ cpp/bindings.cpp | 5 +++++ example/ios/Podfile.lock | 6 +++--- example/src/App.tsx | 9 +++++++++ example/src/Database.ts | 4 ++-- 6 files changed, 44 insertions(+), 13 deletions(-) diff --git a/cpp/DBHostObject.cpp b/cpp/DBHostObject.cpp index 8d592d5e..c3663dd1 100644 --- a/cpp/DBHostObject.cpp +++ b/cpp/DBHostObject.cpp @@ -333,6 +333,10 @@ void DBHostObject::create_jsi_functions() { auto status = opsqlite_execute_raw(db_name, query, ¶ms, &results); #endif + if (invalidated) { + return; + } + invoker->invokeAsync([&rt, results = std::move(results), status = std::move(status), resolve, reject] { if (status.type == SQLiteOk) { @@ -379,8 +383,9 @@ void DBHostObject::create_jsi_functions() { auto resolve = std::make_shared(rt, args[0]); auto reject = std::make_shared(rt, args[1]); - auto task = [&rt, this, query = std::move(query), params = std::move(params), resolve, - reject, invoker = this->jsCallInvoker]() { + auto task = [&rt, this, query = std::move(query), + params = std::move(params), resolve, reject, + invoker = this->jsCallInvoker]() { try { #ifdef OP_SQLITE_USE_LIBSQL @@ -389,9 +394,9 @@ void DBHostObject::create_jsi_functions() { auto status = opsqlite_execute(db_name, query, ¶ms); #endif - // if (invalidated) { - // return; - // } + if (invalidated) { + return; + } invoker->invokeAsync([&rt, status = std::move(status), resolve, reject] { @@ -455,9 +460,9 @@ void DBHostObject::create_jsi_functions() { &results, metadata); #endif - // if (invalidated) { - // return; - // } + if (invalidated) { + return; + } invoker->invokeAsync( [&rt, @@ -533,6 +538,11 @@ void DBHostObject::create_jsi_functions() { #else auto batchResult = opsqlite_execute_batch(db_name, commands.get()); #endif + + if (invalidated) { + return; + } + jsCallInvoker->invokeAsync([&rt, batchResult = std::move(batchResult), resolve, reject] { if (batchResult.type == SQLiteOk) { @@ -934,4 +944,8 @@ void DBHostObject::set(jsi::Runtime &rt, const jsi::PropNameID &name, throw std::runtime_error("You cannot write to this object!"); } +void DBHostObject::invalidate() { invalidated = true; } + +DBHostObject::~DBHostObject() { invalidated = true; } + } // namespace opsqlite diff --git a/cpp/DBHostObject.h b/cpp/DBHostObject.h index de3b9d38..dcb694c5 100644 --- a/cpp/DBHostObject.h +++ b/cpp/DBHostObject.h @@ -51,6 +51,8 @@ class JSI_EXPORT DBHostObject : public jsi::HostObject { jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propNameID); void set(jsi::Runtime &rt, const jsi::PropNameID &name, const jsi::Value &value); + void invalidate(); + ~DBHostObject(); private: void auto_register_update_hook(); @@ -68,6 +70,7 @@ class JSI_EXPORT DBHostObject : public jsi::HostObject { jsi::Runtime &rt; std::vector> reactive_queries; bool is_update_hook_registered = false; + bool invalidated = false; }; } // namespace opsqlite diff --git a/cpp/bindings.cpp b/cpp/bindings.cpp index f5a3c482..b471d3d9 100644 --- a/cpp/bindings.cpp +++ b/cpp/bindings.cpp @@ -24,6 +24,7 @@ std::string _crsqlite_path; std::string _sqlite_vec_path; std::shared_ptr _invoker; std::shared_ptr thread_pool = std::make_shared(); +std::vector> dbs; // React native will try to clean the module on JS context invalidation // (CodePush/Hot Reload) The clearState function is called and we use this flag @@ -31,6 +32,9 @@ std::shared_ptr thread_pool = std::make_shared(); bool invalidated = false; void clearState() { + for (const auto &db : dbs) { + db->invalidate(); + } invalidated = true; #ifdef OP_SQLITE_USE_LIBSQL @@ -88,6 +92,7 @@ void install(jsi::Runtime &rt, std::shared_ptr invoker, std::shared_ptr db = std::make_shared( rt, path, invoker, thread_pool, name, path, _crsqlite_path, _sqlite_vec_path, encryptionKey); + dbs.emplace_back(db); return jsi::Object::createFromHostObject(rt, db); }); diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index e5b4a9f9..7d911f98 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -10,7 +10,7 @@ PODS: - hermes-engine (0.74.0): - hermes-engine/Pre-built (= 0.74.0) - hermes-engine/Pre-built (0.74.0) - - op-sqlite (9.0.0): + - op-sqlite (9.1.1): - React - React-callinvoker - React-Core @@ -1393,7 +1393,7 @@ SPEC CHECKSUMS: GCDWebServer: 2c156a56c8226e2d5c0c3f208a3621ccffbe3ce4 glog: c5d68082e772fa1c511173d6b30a9de2c05a69a2 hermes-engine: 6eae7edb2f563ee41d7c1f91f4f2e57c26d8a5c3 - op-sqlite: 4a145846fefc46b14350344450809144775d2ec3 + op-sqlite: 5a3b7ff78f8a4423ba1ed9831c0965fd7926f86a RCT-Folly: 045d6ecaa59d826c5736dfba0b2f4083ff8d79df RCTDeprecation: 3ca8b6c36bfb302e1895b72cfe7db0de0c92cd47 RCTRequired: 9fc183af555fd0c89a366c34c1ae70b7e03b1dc5 @@ -1449,4 +1449,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 0ab74fecad6ac2e35f8eab32fe5772c19d2015b2 -COCOAPODS: 1.14.3 +COCOAPODS: 1.15.2 diff --git a/example/src/App.tsx b/example/src/App.tsx index e679d3c8..dea6f11d 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -18,6 +18,7 @@ import {setServerResults, startServer, stopServer} from './server'; import {open} from '@op-engineering/op-sqlite'; import Share from 'react-native-share'; import {createLargeDB, queryLargeDB} from './Database'; +import RNRestart from 'react-native-restart'; export default function App() { const [isLoading, setIsLoading] = useState(false); @@ -117,9 +118,17 @@ export default function App() { Clipboard.setString(path); }; + const queryAndReload = async () => { + queryLargeDB(); + setTimeout(() => { + RNRestart.restart(); + }, 200); + }; + return ( +