Skip to content

Commit ce6cd3d

Browse files
DominicGBauerDominicGBauer
and
DominicGBauer
authored
chore: merge master (#41)
* chore: merge master * chore: fix lint issue * chore: add version update * fix: changelog --------- Co-authored-by: DominicGBauer <[email protected]>
1 parent 922e11c commit ce6cd3d

15 files changed

+359
-116
lines changed

Diff for: .github/workflows/test.yaml

+5-5
Original file line numberDiff line numberDiff line change
@@ -32,19 +32,19 @@ jobs:
3232
include:
3333
- sqlite_version: "3440200"
3434
sqlite_url: "https://www.sqlite.org/2023/sqlite-autoconf-3440200.tar.gz"
35-
dart_sdk: 3.2.4
35+
dart_sdk: 3.3.3
3636
- sqlite_version: "3430200"
3737
sqlite_url: "https://www.sqlite.org/2023/sqlite-autoconf-3430200.tar.gz"
38-
dart_sdk: 3.2.4
38+
dart_sdk: 3.3.3
3939
- sqlite_version: "3420000"
4040
sqlite_url: "https://www.sqlite.org/2023/sqlite-autoconf-3420000.tar.gz"
41-
dart_sdk: 3.2.4
41+
dart_sdk: 3.3.3
4242
- sqlite_version: "3410100"
4343
sqlite_url: "https://www.sqlite.org/2023/sqlite-autoconf-3410100.tar.gz"
44-
dart_sdk: 3.2.4
44+
dart_sdk: 3.3.3
4545
- sqlite_version: "3380000"
4646
sqlite_url: "https://www.sqlite.org/2022/sqlite-autoconf-3380000.tar.gz"
47-
dart_sdk: 3.2.0
47+
dart_sdk: 3.3.3
4848
steps:
4949
- uses: actions/checkout@v3
5050
- uses: dart-lang/setup-dart@v1

Diff for: .gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,5 @@ assets
1717
test-db
1818
sqlite-autoconf-*
1919
doc
20+
21+
build

Diff for: CHANGELOG.md

+15-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,25 @@
1+
## 0.7.0-alpha.3
2+
3+
- Add latest changes from master
4+
15
## 0.7.0-alpha.2
26

3-
- Fix re-using a shared Mutex from https://github.com/powersync-ja/sqlite_async.dart/pull/31
7+
- Fix re-using a shared Mutex from <https://github.com/powersync-ja/sqlite_async.dart/pull/31>
48

59
## 0.7.0-alpha.1
610

711
- Added initial support for web platform.
812

13+
## 0.6.1
14+
15+
- Fix errors when closing a `SqliteDatabase`.
16+
- Configure SQLite `busy_timeout` (30s default). This fixes "database is locked (code 5)" error when using multiple `SqliteDatabase` instances for the same database.
17+
- Fix errors when opening multiple connections at the same time, e.g. when running multiple read queries concurrently
18+
right after opening the dtaabase.
19+
- Improved error handling when an Isolate crashes with an uncaught error.
20+
- Rewrite connection pool logic to fix performance issues when multiple read connections are open.
21+
- Fix using `SqliteDatabase.isolateConnectionFactory()` in multiple isolates.
22+
923
## 0.6.0
1024

1125
- Allow catching errors and continuing the transaction. This is technically a breaking change, although it should not be an issue in most cases.

Diff for: lib/src/common/abstract_open_factory.dart

+14-1
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,21 @@ abstract class AbstractDefaultSqliteOpenFactory<
8686
FutureOr<Database> open(SqliteOpenOptions options) async {
8787
var db = await openDB(options);
8888

89+
// Pragma statements don't have the same BUSY_TIMEOUT behavior as normal statements.
90+
// We add a manual retry loop for those.
8991
for (var statement in pragmaStatements(options)) {
90-
db.execute(statement);
92+
for (var tries = 0; tries < 30; tries++) {
93+
try {
94+
db.execute(statement);
95+
break;
96+
} on sqlite.SqliteException catch (e) {
97+
if (e.resultCode == sqlite.SqlError.SQLITE_BUSY && tries < 29) {
98+
continue;
99+
} else {
100+
rethrow;
101+
}
102+
}
103+
}
91104
}
92105
return db;
93106
}

Diff for: lib/src/common/port_channel.dart

+58-11
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,11 @@ abstract class PortClient {
1818
class ParentPortClient implements PortClient {
1919
late Future<SendPort> sendPortFuture;
2020
SendPort? sendPort;
21-
ReceivePort receivePort = ReceivePort();
21+
final ReceivePort _receivePort = ReceivePort();
22+
final ReceivePort _errorPort = ReceivePort();
2223
bool closed = false;
24+
Object? _closeError;
25+
String? _isolateDebugName;
2326
int _nextId = 1;
2427

2528
Map<int, Completer<Object?>> handlers = HashMap();
@@ -30,7 +33,7 @@ class ParentPortClient implements PortClient {
3033
sendPortFuture.then((value) {
3134
sendPort = value;
3235
});
33-
receivePort.listen((message) {
36+
_receivePort.listen((message) {
3437
if (message is _InitMessage) {
3538
assert(!initCompleter.isCompleted);
3639
initCompleter.complete(message.port);
@@ -57,24 +60,35 @@ class ParentPortClient implements PortClient {
5760
}
5861
close();
5962
});
63+
_errorPort.listen((message) {
64+
final [error, stackTraceString] = message;
65+
final stackTrace = stackTraceString == null
66+
? null
67+
: StackTrace.fromString(stackTraceString);
68+
if (!initCompleter.isCompleted) {
69+
initCompleter.completeError(error, stackTrace);
70+
}
71+
_close(IsolateError(cause: error, isolateDebugName: _isolateDebugName),
72+
stackTrace);
73+
});
6074
}
6175

6276
Future<void> get ready async {
6377
await sendPortFuture;
6478
}
6579

66-
void _cancelAll(Object error) {
80+
void _cancelAll(Object error, [StackTrace? stackTrace]) {
6781
var handlers = this.handlers;
6882
this.handlers = {};
6983
for (var message in handlers.values) {
70-
message.completeError(error);
84+
message.completeError(error, stackTrace);
7185
}
7286
}
7387

7488
@override
7589
Future<T> post<T>(Object message) async {
7690
if (closed) {
77-
throw ClosedException();
91+
throw _closeError ?? const ClosedException();
7892
}
7993
var completer = Completer<T>.sync();
8094
var id = _nextId++;
@@ -87,27 +101,39 @@ class ParentPortClient implements PortClient {
87101
@override
88102
void fire(Object message) async {
89103
if (closed) {
90-
throw ClosedException();
104+
throw _closeError ?? ClosedException();
91105
}
92106
final port = sendPort ?? await sendPortFuture;
93107
port.send(_FireMessage(message));
94108
}
95109

96110
RequestPortServer server() {
97-
return RequestPortServer(receivePort.sendPort);
111+
return RequestPortServer(_receivePort.sendPort);
98112
}
99113

100-
void close() async {
114+
void _close([Object? error, StackTrace? stackTrace]) {
101115
if (!closed) {
102116
closed = true;
103117

104-
receivePort.close();
105-
_cancelAll(const ClosedException());
118+
_receivePort.close();
119+
_errorPort.close();
120+
if (error == null) {
121+
_cancelAll(const ClosedException());
122+
} else {
123+
_closeError = error;
124+
_cancelAll(error, stackTrace);
125+
}
106126
}
107127
}
108128

129+
void close() {
130+
_close();
131+
}
132+
109133
tieToIsolate(Isolate isolate) {
110-
isolate.addOnExitListener(receivePort.sendPort, response: _closeMessage);
134+
_isolateDebugName = isolate.debugName;
135+
isolate.addErrorListener(_errorPort.sendPort);
136+
isolate.addOnExitListener(_receivePort.sendPort, response: _closeMessage);
111137
}
112138
}
113139

@@ -261,6 +287,27 @@ class _RequestMessage {
261287

262288
class ClosedException implements Exception {
263289
const ClosedException();
290+
291+
@override
292+
String toString() {
293+
return 'ClosedException';
294+
}
295+
}
296+
297+
class IsolateError extends Error {
298+
final Object cause;
299+
final String? isolateDebugName;
300+
301+
IsolateError({required this.cause, this.isolateDebugName});
302+
303+
@override
304+
String toString() {
305+
if (isolateDebugName != null) {
306+
return 'IsolateError in $isolateDebugName: $cause';
307+
} else {
308+
return 'IsolateError: $cause';
309+
}
310+
}
264311
}
265312

266313
class _PortChannelResult<T> {

0 commit comments

Comments
 (0)