Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Invalidate HostObjects on module hot reload #155

Merged
merged 3 commits into from
Oct 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading