diff --git a/sqlite3/CHANGELOG.md b/sqlite3/CHANGELOG.md index 913193fc..7c5c0ea9 100644 --- a/sqlite3/CHANGELOG.md +++ b/sqlite3/CHANGELOG.md @@ -1,3 +1,13 @@ +## 2.4.6 + +- Fix selecting large integers (being represented as a `BigInt` in Dart) + not working when compiled with dartdevc. + +## 2.4.5 + +- Fix a bug in the OPFS-locks implementation causing a deadlock when the `xSleep` + VFS call is issued. + ## 2.4.4 - Add a temporary workaround for [a Dart bug](https://github.com/dart-lang/sdk/issues/56064) diff --git a/sqlite3/lib/src/wasm/js_interop/core.dart b/sqlite3/lib/src/wasm/js_interop/core.dart index e1c9e851..a4f0a7e9 100644 --- a/sqlite3/lib/src/wasm/js_interop/core.dart +++ b/sqlite3/lib/src/wasm/js_interop/core.dart @@ -8,16 +8,18 @@ external JSBigInt _bigInt(JSAny? s); @JS('Number') external JSNumber _number(JSAny? obj); -@JS('Object') -extension type WrappedJSObject._(JSObject _) implements JSObject { - external WrappedJSObject(JSBigInt _); - +extension type WrappedJSAny._(JSAny _) implements JSAny { external static JSArray keys(JSObject o); @JS('toString') external JSString _toString(); } +@JS('Object') +extension type WrappedJSObject._(JSObject _) implements JSObject { + external static JSArray keys(JSObject o); +} + extension type JsBigInt(JSBigInt _jsBigInt) implements JSBigInt { factory JsBigInt.parse(String s) => JsBigInt(_bigInt(s.toJS)); factory JsBigInt.fromInt(int i) => JsBigInt(_bigInt(i.toJS)); @@ -42,7 +44,7 @@ extension type JsBigInt(JSBigInt _jsBigInt) implements JSBigInt { } String jsToString() { - return (WrappedJSObject(_jsBigInt))._toString().toDart; + return (_jsBigInt as WrappedJSAny)._toString().toDart; } } diff --git a/sqlite3/lib/src/wasm/vfs/async_opfs/client.dart b/sqlite3/lib/src/wasm/vfs/async_opfs/client.dart index a3aeba70..5448ad1b 100644 --- a/sqlite3/lib/src/wasm/vfs/async_opfs/client.dart +++ b/sqlite3/lib/src/wasm/vfs/async_opfs/client.dart @@ -91,8 +91,7 @@ final class WasmVfs extends BaseVirtualFileSystem { static WorkerOptions createOptions({String root = 'pkg_sqlite3_db/'}) { return WorkerOptions( - synchronizationBuffer: - SharedArrayBuffer(RequestResponseSynchronizer.byteLength), + synchronizationBuffer: RequestResponseSynchronizer.createBuffer(), communicationBuffer: SharedArrayBuffer(MessageSerializer.totalSize), root: root, ); diff --git a/sqlite3/lib/src/wasm/vfs/async_opfs/sync_channel.dart b/sqlite3/lib/src/wasm/vfs/async_opfs/sync_channel.dart index 938e3d25..b219328f 100644 --- a/sqlite3/lib/src/wasm/vfs/async_opfs/sync_channel.dart +++ b/sqlite3/lib/src/wasm/vfs/async_opfs/sync_channel.dart @@ -13,7 +13,7 @@ class RequestResponseSynchronizer { static const _responseIndex = 1; // 2 32-bit slots for the int32 array - static const byteLength = 2 * 4; + static const _byteLength = 2 * 4; /// The shared array buffer used with atomics for synchronization. /// @@ -26,17 +26,32 @@ class RequestResponseSynchronizer { RequestResponseSynchronizer._(this.buffer) : int32View = buffer.asInt32List(); factory RequestResponseSynchronizer([SharedArrayBuffer? buffer]) { - if (buffer != null && buffer.byteLength != byteLength) { - throw ArgumentError('Must be $byteLength in length'); + if (buffer != null && buffer.byteLength != _byteLength) { + throw ArgumentError('Must be $_byteLength in length'); } return RequestResponseSynchronizer._( - buffer ?? SharedArrayBuffer(byteLength)); + buffer ?? SharedArrayBuffer(_byteLength)); + } + + /// Creates a shared buffer and fills it with the initial state suitable for + /// a request synchronization channel. + static SharedArrayBuffer createBuffer() { + final buffer = SharedArrayBuffer(_byteLength); + final view = buffer.asInt32List(); + + // The server will wait for the request index to not be -1 to wait for a + // request. The initial value when allocating shared buffers is 0, which is + // also a valid opcode. + Atomics.store(view, _requestIndex, -1); + + return buffer; } /// Send a request with the given [opcode], wait for the remote worker to /// process it and returns the response code. int requestAndWaitForResponse(int opcode) { + assert(opcode >= 0); Atomics.store(int32View, _responseIndex, -1); Atomics.store(int32View, _requestIndex, opcode); Atomics.notify(int32View, _requestIndex); @@ -49,16 +64,17 @@ class RequestResponseSynchronizer { String waitForRequest() { return Atomics.waitWithTimeout( - int32View, _requestIndex, 0, asyncIdleWaitTimeMs); + int32View, _requestIndex, -1, asyncIdleWaitTimeMs); } int takeOpcode() { final opcode = Atomics.load(int32View, _requestIndex); - Atomics.store(int32View, _requestIndex, 0); + Atomics.store(int32View, _requestIndex, -1); return opcode; } void respond(int rc) { + assert(rc != -1); Atomics.store(int32View, _responseIndex, rc); Atomics.notify(int32View, _responseIndex); } diff --git a/sqlite3/lib/src/wasm/vfs/async_opfs/worker.dart b/sqlite3/lib/src/wasm/vfs/async_opfs/worker.dart index 24f371f1..35fb878c 100644 --- a/sqlite3/lib/src/wasm/vfs/async_opfs/worker.dart +++ b/sqlite3/lib/src/wasm/vfs/async_opfs/worker.dart @@ -293,14 +293,16 @@ class VfsWorker { continue; } - final opcode = WorkerOperation.values[synchronizer.takeOpcode()]; - Object? request; int rc; + WorkerOperation? opcode; + Object? request; try { - Message response; + opcode = WorkerOperation.values[synchronizer.takeOpcode()]; request = opcode.readRequest(messages); + Message response; + switch (opcode) { case WorkerOperation.xSleep: _releaseImplicitLocks(); diff --git a/sqlite3/pubspec.yaml b/sqlite3/pubspec.yaml index c5d8c7c8..339a3632 100644 --- a/sqlite3/pubspec.yaml +++ b/sqlite3/pubspec.yaml @@ -1,6 +1,6 @@ name: sqlite3 description: Provides lightweight yet convenient bindings to SQLite by using dart:ffi -version: 2.4.4 +version: 2.4.6 homepage: https://github.com/simolus3/sqlite3.dart/tree/main/sqlite3 issue_tracker: https://github.com/simolus3/sqlite3.dart/issues