Skip to content

Commit

Permalink
Merge pull request #155 from OP-Engineering/oscar/invalidation
Browse files Browse the repository at this point in the history
Invalidate HostObjects on module hot reload
  • Loading branch information
ospfranco authored Oct 4, 2024
2 parents e6c2cc2 + 92b60e8 commit 541a00a
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 19 deletions.
30 changes: 22 additions & 8 deletions cpp/DBHostObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,10 @@ void DBHostObject::create_jsi_functions() {
auto status = opsqlite_execute_raw(db_name, query, &params, &results);
#endif

if (invalidated) {
return;
}

invoker->invokeAsync([&rt, results = std::move(results),
status = std::move(status), resolve, reject] {
if (status.type == SQLiteOk) {
Expand Down Expand Up @@ -379,8 +383,9 @@ void DBHostObject::create_jsi_functions() {
auto resolve = std::make_shared<jsi::Value>(rt, args[0]);
auto reject = std::make_shared<jsi::Value>(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
Expand All @@ -389,9 +394,9 @@ void DBHostObject::create_jsi_functions() {
auto status = opsqlite_execute(db_name, query, &params);
#endif

// if (invalidated) {
// return;
// }
if (invalidated) {
return;
}

invoker->invokeAsync([&rt, status = std::move(status), resolve,
reject] {
Expand Down Expand Up @@ -455,9 +460,9 @@ void DBHostObject::create_jsi_functions() {
&results, metadata);
#endif

// if (invalidated) {
// return;
// }
if (invalidated) {
return;
}

invoker->invokeAsync(
[&rt,
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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
3 changes: 3 additions & 0 deletions cpp/DBHostObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -68,6 +70,7 @@ class JSI_EXPORT DBHostObject : public jsi::HostObject {
jsi::Runtime &rt;
std::vector<std::shared_ptr<ReactiveQuery>> reactive_queries;
bool is_update_hook_registered = false;
bool invalidated = false;
};

} // namespace opsqlite
5 changes: 5 additions & 0 deletions cpp/bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,17 @@ std::string _crsqlite_path;
std::string _sqlite_vec_path;
std::shared_ptr<react::CallInvoker> _invoker;
std::shared_ptr<ThreadPool> thread_pool = std::make_shared<ThreadPool>();
std::vector<std::shared_ptr<DBHostObject>> 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
// to prevent any ongoing operations from continuing work and can return early
bool invalidated = false;

void clearState() {
for (const auto &db : dbs) {
db->invalidate();
}
invalidated = true;

#ifdef OP_SQLITE_USE_LIBSQL
Expand Down Expand Up @@ -88,6 +92,7 @@ void install(jsi::Runtime &rt, std::shared_ptr<react::CallInvoker> invoker,
std::shared_ptr<DBHostObject> db = std::make_shared<DBHostObject>(
rt, path, invoker, thread_pool, name, path, _crsqlite_path,
_sqlite_vec_path, encryptionKey);
dbs.emplace_back(db);
return jsi::Object::createFromHostObject(rt, db);
});

Expand Down
2 changes: 1 addition & 1 deletion cpp/bridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ BridgeResult opsqlite_open(std::string const &name,

if (dbMap.count(name) != 0) {
throw std::runtime_error(
"[OP-SQLITE] Only JS connection per database is allowed, db name: " +
"[OP-SQLITE] Only one connection per database is allowed, db name: " +
name);
}
#endif
Expand Down
6 changes: 3 additions & 3 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -1449,4 +1449,4 @@ SPEC CHECKSUMS:

PODFILE CHECKSUM: 0ab74fecad6ac2e35f8eab32fe5772c19d2015b2

COCOAPODS: 1.14.3
COCOAPODS: 1.15.2
14 changes: 9 additions & 5 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ 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);
const [times, setTimes] = useState<number[]>([]);
const [accessingTimes, setAccessingTimes] = useState<number[]>([]);
const [prepareTimes, setPrepareTimes] = useState<number[]>([]);
Expand Down Expand Up @@ -88,14 +88,11 @@ export default function App() {
};

const createLargeDb = async () => {
setIsLoading(true);
await createLargeDB();
setIsLoading(false);
};

const queryLargeDb = async () => {
try {
setIsLoading(true);
const times = await queryLargeDB();
setTimes(times.loadFromDb);
setAccessingTimes(times.access);
Expand All @@ -105,7 +102,6 @@ export default function App() {
} catch (e) {
console.error(e);
} finally {
setIsLoading(false);
}
};

Expand All @@ -117,9 +113,17 @@ export default function App() {
Clipboard.setString(path);
};

const queryAndReload = async () => {
queryLargeDB();
setTimeout(() => {
RNRestart.restart();
}, 200);
};

return (
<SafeAreaView className="flex-1 bg-neutral-900">
<ScrollView>
<Button title="Reload app middle of query" onPress={queryAndReload} />
<Button title="Share DB" onPress={shareDb} />
<Button title="Copy DB Path" onPress={copyDbPathToClipboad} />
<Button title="Create 300k Record DB" onPress={createLargeDb} />
Expand Down
4 changes: 2 additions & 2 deletions example/src/Database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export async function querySingleRecordOnLargeDB() {
export async function queryLargeDB() {
let largeDb = open(DB_CONFIG);

largeDb.execute('PRAGMA mmap_size=268435456');
// largeDb.execute('PRAGMA mmap_size=268435456');

let times: {
loadFromDb: number[];
Expand All @@ -76,7 +76,7 @@ export async function queryLargeDB() {
rawExecution: [],
};

console.log('Querying DB');
// console.log('Querying DB');

for (let i = 0; i < 10; i++) {
// @ts-ignore
Expand Down

0 comments on commit 541a00a

Please sign in to comment.