Skip to content

Commit f091a94

Browse files
prevent database is locked errors
1 parent 2f8b30c commit f091a94

File tree

4 files changed

+60
-10
lines changed

4 files changed

+60
-10
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@powersync/node': patch
3+
---
4+
5+
[`node:sqlite`] Prevent `database is locked` errors when instantiating the database.

packages/node/src/db/WorkerConnectionPool.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
1+
import * as Comlink from 'comlink';
12
import fs from 'node:fs/promises';
23
import * as path from 'node:path';
34
import { Worker } from 'node:worker_threads';
4-
import * as Comlink from 'comlink';
55

66
import {
77
BaseObserver,
88
BatchedUpdateNotification,
99
DBAdapter,
1010
DBAdapterListener,
11-
LockContext,
12-
Transaction,
1311
DBLockOptions,
14-
QueryResult
12+
LockContext,
13+
QueryResult,
14+
Transaction
1515
} from '@powersync/common';
1616
import { Remote } from 'comlink';
1717
import { AsyncResource } from 'node:async_hooks';
18+
import { isBundledToCommonJs } from '../utils/modules.js';
1819
import { AsyncDatabase, AsyncDatabaseOpener } from './AsyncDatabase.js';
1920
import { RemoteConnection } from './RemoteConnection.js';
2021
import { NodeDatabaseImplementation, NodeSQLOpenOptions } from './options.js';
21-
import { isBundledToCommonJs } from '../utils/modules.js';
2222

2323
export type BetterSQLite3LockContext = LockContext & {
2424
executeBatch(query: string, params?: any[][]): Promise<QueryResult>;
@@ -135,10 +135,12 @@ export class WorkerConnectionPool extends BaseObserver<DBAdapterListener> implem
135135
if (this.options.initializeConnection) {
136136
await this.options.initializeConnection(connection, isWriter);
137137
}
138-
139-
await connection.execute('pragma journal_mode = WAL');
140138
if (!isWriter) {
141139
await connection.execute('pragma query_only = true');
140+
} else {
141+
// We only need to enable this on the writer connection.
142+
// We can get `database is locked` errors if we enable this on concurrently opening read connections.
143+
await connection.execute('pragma journal_mode = WAL');
142144
}
143145

144146
return connection;

packages/node/tests/PowerSyncDatabase.test.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import * as path from 'node:path';
22
import { Worker } from 'node:worker_threads';
33

4-
import { vi, expect, test } from 'vitest';
5-
import { AppSchema, databaseTest, tempDirectoryTest } from './utils';
4+
import { LockContext } from '@powersync/common';
5+
import { randomUUID } from 'node:crypto';
6+
import { expect, test, vi } from 'vitest';
67
import { CrudEntry, CrudTransaction, PowerSyncDatabase } from '../lib';
78
import { WorkerOpener } from '../lib/db/options';
8-
import { LockContext } from '@powersync/common';
9+
import { AppSchema, databaseTest, tempDirectoryTest } from './utils';
910

1011
test('validates options', async () => {
1112
await expect(async () => {
@@ -203,3 +204,22 @@ databaseTest('getCrudTransactions', async ({ database }) => {
203204
const remainingTransaction = await database.getNextCrudTransaction();
204205
expect(remainingTransaction?.crud).toHaveLength(15);
205206
});
207+
208+
tempDirectoryTest('should not present database is locked errors on startup', async ({ tmpdir }) => {
209+
for (let i = 0; i < 10; i++) {
210+
const database = new PowerSyncDatabase({
211+
schema: AppSchema,
212+
database: {
213+
dbFilename: `${randomUUID()}.sqlite`,
214+
dbLocation: tmpdir,
215+
implementation: {
216+
type: 'node:sqlite'
217+
}
218+
}
219+
});
220+
221+
// This should not throw
222+
await database.waitForReady();
223+
await database.close();
224+
}
225+
});

pnpm-workspace.yaml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,26 @@ packages:
33
- packages/*
44
- tools/*
55
- docs/
6+
7+
ignoredBuiltDependencies:
8+
- '@journeyapps/wa-sqlite'
9+
- '@parcel/watcher'
10+
- '@swc/core'
11+
- core-js
12+
- core-js-pure
13+
- detox
14+
- dtrace-provider
15+
- electron
16+
- electron-winstaller
17+
- esbuild
18+
- lmdb
19+
- lzma-native
20+
- msgpackr-extract
21+
- react-native-elements
22+
- supabase
23+
- unrs-resolver
24+
- vue-demi
25+
26+
onlyBuiltDependencies:
27+
- better-sqlite3
28+
- better-sqlite3-multiple-ciphers

0 commit comments

Comments
 (0)