Description
Hi,
When db.disconnect()/connect()
ing, some issues have been observed.
The issue is being opened against the Dart client, even though it's likely to include other libs, as that's where the behavior is being observed.
Using debugging code like:
log.fine('/powersync/$action: request');
...
switch (action) {
case 'connect':
await db.connect(connector: connector);
response = {
'db.closed': db.closed,
'db.connected': db.connected,
'db.currentStatus': '${db.currentStatus}'
};
break;
case 'disconnect':
await db.disconnect();
response = {
'db.closed': db.closed,
'db.connected': db.connected,
'db.currentStatus': '${db.currentStatus}'
};
break;
}
...
log.fine('/powersync/$action: response: $response');
The expectation is that on return from await
:
- when
connect
ing, bothdb.connected
anddb.syncStatus.connected
with betrue
db.syncStatus.uploading/downloading
will befalse
ifdb.connected
anddb.syncStatus.connected
arefalse
It's also possible for db.disconnect()/connect()
to lead to replication pausing for 30s+:
- even when there's no database activity
- all local writes have been
uploadData
d
And of most concern, db.disconnect()/connect()
can lead to:
- dropping local writes, possibly related to sqlite-core's
The first two issues can hopefully be debugged with existing or straightforward tests.
If the last issue isn't just another way to express the sqlite-core reverting local changes, I can pursue some type of simpler test case than a full Jepsen test.
Thanks!
Tests disconnect()
a random majority of nodes every ~5s for ~5s, and the connect()
all nodes.
Some annotated sample log snippets, search for '#' for annotation comments.
SyncStatus not always tracking/reflecting the actual state:
[2025-01-09 00:06:53.097713] [powersync_endpoint] [FINE] /powersync/connect: request
# suspect? connected is false even after awaiting
[2025-01-09 00:06:53.097766] [powersync_endpoint] [FINEST] statusStream: SyncStatus<connected: false connecting: false downloading: false uploading: false lastSyncedAt: 2025-01-09 00:06:50.197767, hasSynced: true, error: null>
[2025-01-09 00:06:53.097825] [powersync_endpoint] [FINE] /powersync/connect: response: {db.closed: false, db.connected: false, db.currentStatus: SyncStatus<connected: false connecting: false downloading: false uploading: false lastSyncedAt: 2025-01-09 00:06:50.197767, hasSynced: true, error: null>}
[2025-01-09 00:06:53.099358] [powersync_endpoint] [FINEST] statusStream: SyncStatus<connected: false connecting: true downloading: false uploading: false lastSyncedAt: 2025-01-09 00:06:50.197767, hasSynced: true, error: null>
# suspect? connected is false, yet uploading is true
[2025-01-09 00:06:53.099477] [powersync_endpoint] [FINEST] statusStream: SyncStatus<connected: false connecting: true downloading: false uploading: true lastSyncedAt: 2025-01-09 00:06:50.197767, hasSynced: true, error: null>
[2025-01-09 00:06:53.102568] [powersync_endpoint] [FINER] uploadData: (2) patch result: {id: d5dbe3f3-5ca9-4327-958d-7a3daa154482, k: 7, v: 1}
[2025-01-09 00:06:53.111988] [powersync_endpoint] [FINER] uploadData: (3) patch result: {id: f5ce635c-7231-475e-bc28-4ca6517283e3, k: 9, v: 1 8}
[2025-01-09 00:06:53.112972] [powersync_endpoint] [FINER] uploadData: (3) patch result: {id: 4a59b53a-badd-4333-8fa9-b4c8095c7eba, k: 8, v: 1 7}
[2025-01-09 00:06:53.117300] [powersync_endpoint] [FINER] uploadData: (4) patch result: {id: f5ce635c-7231-475e-bc28-4ca6517283e3, k: 9, v: 1 8 10}
[2025-01-09 00:06:53.118872] [powersync_endpoint] [FINEST] statusStream: SyncStatus<connected: false connecting: true downloading: false uploading: true lastSyncedAt: 2025-01-09 00:06:50.197767, hasSynced: true, error: null>
[2025-01-09 00:06:53.118922] [powersync_endpoint] [FINEST] statusStream: SyncStatus<connected: false connecting: true downloading: false uploading: false lastSyncedAt: 2025-01-09 00:06:50.197767, hasSynced: true, error: null>
# connect finally becomes true, but only after uploading is complete, e.g. clears the upload queue that was accumulated during the previous disconnect
[2025-01-09 00:06:53.133736] [powersync_endpoint] [FINEST] statusStream: SyncStatus<connected: true connecting: false downloading: false uploading: false lastSyncedAt: 2025-01-09 00:06:50.197767, hasSynced: true, error: null>
replication paused
# at the end of a test run, a majority of nodes look like
# suspect? insure connected, but note the disconnect bounce
[2025-01-09 00:08:30.584932] [powersync_endpoint] [FINE] /powersync/connect: request
[2025-01-09 00:08:30.584981] [powersync_endpoint] [FINEST] statusStream: SyncStatus<connected: false connecting: false downloading: false uploading: false lastSyncedAt: 2025-01-09 00:08:30.100527, hasSynced: true, error: null>
[2025-01-09 00:08:30.585034] [powersync_endpoint] [FINE] /powersync/connect: response: {db.closed: false, db.connected: false, db.currentStatus: SyncStatus<connected: false connecting: false downloading: false uploading: false lastSyncedAt: 2025-01-09 00:08:30.100527, hasSynced: true, error: null>}
[2025-01-09 00:08:30.586498] [powersync_endpoint] [FINEST] statusStream: SyncStatus<connected: false connecting: true downloading: false uploading: false lastSyncedAt: 2025-01-09 00:08:30.100527, hasSynced: true, error: null>
[2025-01-09 00:08:30.586722] [powersync_endpoint] [FINEST] statusStream: SyncStatus<connected: false connecting: true downloading: false uploading: true lastSyncedAt: 2025-01-09 00:08:30.100527, hasSynced: true, error: null>
# suspect? we're uploading even though not connected was/is/remains false
[2025-01-09 00:08:30.589472] [powersync_endpoint] [FINER] uploadData: (119) patch result: {id: 1f32b853-b006-4b78-8ad2-16e9c238a5a8, k: 11, v: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 17 18 23 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 99 100 101 102 103 104 105 106 107 108 110 111 113 114 115}
[2025-01-09 00:08:30.592236] [powersync_endpoint] [FINEST] statusStream: SyncStatus<connected: false connecting: true downloading: false uploading: true lastSyncedAt: 2025-01-09 00:08:30.100527, hasSynced: true, error: null>
[2025-01-09 00:08:30.592272] [powersync_endpoint] [FINEST] statusStream: SyncStatus<connected: false connecting: true downloading: false uploading: false lastSyncedAt: 2025-01-09 00:08:30.100527, hasSynced: true, error: null>
# let's explicitly wait for upload queue count == 0
[2025-01-09 00:08:30.600952] [powersync_endpoint] [FINE] /powersync/upload-queue-wait: request
[2025-01-09 00:08:30.601770] [powersync_endpoint] [FINE] /powersync/upload-queue-wait: response: {db.upload-queue-wait: queue-empty}
[2025-01-09 00:08:30.602277] [powersync_endpoint] [FINEST] statusStream: SyncStatus<connected: true connecting: false downloading: false uploading: false lastSyncedAt: 2025-01-09 00:08:30.100527, hasSynced: true, error: null>
[2025-01-09 00:08:30.602372] [powersync_endpoint] [FINEST] statusStream: SyncStatus<connected: true connecting: false downloading: true uploading: false lastSyncedAt: 2025-01-09 00:08:30.100527, hasSynced: true, error: null>
[2025-01-09 00:08:30.604702] [powersync_endpoint] [FINEST] statusStream: SyncStatus<connected: true connecting: false downloading: true uploading: false lastSyncedAt: 2025-01-09 00:08:30.100527, hasSynced: true, error: null>
[2025-01-09 00:08:30.604726] [powersync_endpoint] [FINEST] statusStream: SyncStatus<connected: true connecting: false downloading: true uploading: false lastSyncedAt: 2025-01-09 00:08:30.100527, hasSynced: true, error: null>
[2025-01-09 00:08:30.606861] [powersync_endpoint] [FINEST] statusStream: SyncStatus<connected: true connecting: false downloading: true uploading: false lastSyncedAt: 2025-01-09 00:08:30.100527, hasSynced: true, error: null>
# let's explicitly wait for db.syncStatus.downloading to become false
# suspect? we wait for 30 seconds before logging an error and continuing
# suspect? even though all test activity has stopped
# suspect? it will be 30s+ before we get an UpdateNotification<{lww}> and db.syncStatus.downloading becomes false
[2025-01-09 00:08:30.607448] [powersync_endpoint] [FINE] /powersync/downloading-wait: request
[2025-01-09 00:09:00.638623] [powersync_endpoint] [FINE] /powersync/downloading-wait: response: {ERROR: Tried 299 times every 0:00:00.100000, db.currentStatus: SyncStatus<connected: true connecting: false downloading: true uploading: false lastSyncedAt: 2025-01-09 00:08:30.100527, hasSynced: true, error: null>}
[2025-01-09 00:09:00.638968] [powersync_endpoint] [FINEST] statusStream: SyncStatus<connected: true connecting: false downloading: true uploading: false lastSyncedAt: 2025-01-09 00:08:30.100527, hasSynced: true, error: null>
[2025-01-09 00:09:00.638987] [powersync_endpoint] [FINEST] statusStream: SyncStatus<connected: true connecting: false downloading: true uploading: false lastSyncedAt: 2025-01-09 00:08:30.100527, hasSynced: true, error: null>
[2025-01-09 00:09:00.639005] [powersync_endpoint] [FINEST] statusStream: SyncStatus<connected: true connecting: false downloading: true uploading: false lastSyncedAt: 2025-01-09 00:08:30.100527, hasSynced: true, error: null>
[2025-01-09 00:09:00.639018] [powersync_endpoint] [FINEST] statusStream: SyncStatus<connected: true connecting: false downloading: true uploading: false lastSyncedAt: 2025-01-09 00:08:30.100527, hasSynced: true, error: null>
[2025-01-09 00:09:00.639263] [powersync_endpoint] [FINEST] statusStream: SyncStatus<connected: true connecting: false downloading: true uploading: false lastSyncedAt: 2025-01-09 00:08:30.100527, hasSynced: true, error: null>
[2025-01-09 00:09:00.639948] [powersync_endpoint] [FINEST] statusStream: SyncStatus<connected: true connecting: false downloading: true uploading: false lastSyncedAt: 2025-01-09 00:08:30.100527, hasSynced: true, error: null>
[2025-01-09 00:09:00.641163] [powersync_endpoint] [FINEST] statusStream: SyncStatus<connected: true connecting: false downloading: true uploading: false lastSyncedAt: 2025-01-09 00:08:30.100527, hasSynced: true, error: null>
[2025-01-09 00:09:00.641186] [powersync_endpoint] [FINEST] statusStream: SyncStatus<connected: true connecting: false downloading: true uploading: false lastSyncedAt: 2025-01-09 00:08:30.100527, hasSynced: true, error: null>
[2025-01-09 00:09:00.641251] [powersync_endpoint] [FINEST] statusStream: SyncStatus<connected: true connecting: false downloading: true uploading: false lastSyncedAt: 2025-01-09 00:08:30.100527, hasSynced: true, error: null>
[2025-01-09 00:09:00.641265] [powersync_endpoint] [FINEST] statusStream: SyncStatus<connected: true connecting: false downloading: true uploading: false lastSyncedAt: 2025-01-09 00:08:30.100527, hasSynced: true, error: null>
[2025-01-09 00:09:00.641764] [powersync_endpoint] [FINEST] statusStream: SyncStatus<connected: true connecting: false downloading: true uploading: false lastSyncedAt: 2025-01-09 00:08:30.100527, hasSynced: true, error: null>
[2025-01-09 00:09:00.642903] [powersync_endpoint] [FINEST] updates: UpdateNotification<{lww}>
[2025-01-09 00:09:00.643012] [powersync_endpoint] [FINEST] statusStream: SyncStatus<connected: true connecting: false downloading: false uploading: false lastSyncedAt: 2025-01-09 00:09:00.642986, hasSynced: true, error: null>
# final reads occur on all nodes and are consistent
client not reading its own previous write
The transaction graph shows a cycle:
-
p-> is process order
- the top transaction happened first
- appended '40' to key 17
- read key 17 and it shows the append of '40'
- the bottom transaction happened later in the same process
- did not observe the append of '40' to key 17
- the top transaction happened first
-
rw-> is logical read/write order
- it shows the bottom transaction would have logically happened first
So the graph cycles which shows a ready your own writes anomaly.
Activity