Skip to content

Commit aa41435

Browse files
authored
Merge pull request #22 from powersync-ja/fix/improve-write-performance
Remove slower defer calls to improve INSERT performance
2 parents 3068f2e + 26fa8a2 commit aa41435

File tree

4 files changed

+104
-7
lines changed

4 files changed

+104
-7
lines changed

.changeset/four-meals-grab.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@journeyapps/react-native-quick-sqlite': patch
3+
---
4+
5+
This pull request improves the performance of releasing lock operations. Executing multiple lock operations, such as individual calls to `.execute`, should see a significant performance improvement.

src/setup-open.ts

+5-7
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,6 @@ global.onLockContextIsAvailable = async (dbName: string, lockId: ContextLockID)
6868
});
6969
} catch (ex) {
7070
console.error(ex);
71-
} finally {
72-
// Always release a lock once finished
73-
closeContextLock(dbName, lockId);
7471
}
7572
});
7673
};
@@ -119,12 +116,13 @@ export function setupOpen(QuickSQLite: ISQLite) {
119116
await hooks?.lockAcquired?.();
120117
const res = await callback(context);
121118

122-
// Ensure that we only resolve after locks are freed
123-
_.defer(() => resolve(res));
119+
closeContextLock(dbName, id);
120+
resolve(res)
124121
} catch (ex) {
125-
_.defer(() => reject(ex));
122+
closeContextLock(dbName, id);
123+
reject(ex)
126124
} finally {
127-
_.defer(() => hooks?.lockReleased?.());
125+
hooks?.lockReleased?.()
128126
}
129127
}
130128
} as LockCallbackRecord);

tests/tests/sqlite/rawQueries.spec.ts

+20
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
} from 'react-native-quick-sqlite';
1212
import { beforeEach, describe, it } from '../mocha/MochaRNAdapter';
1313
import chai from 'chai';
14+
import { randomIntFromInterval, numberName } from './utils';
1415

1516
const { expect } = chai;
1617
const chance = new Chance();
@@ -62,6 +63,8 @@ export function registerBaseTests() {
6263

6364
await db.execute('DROP TABLE IF EXISTS User; ');
6465
await db.execute('CREATE TABLE User ( id INT PRIMARY KEY, name TEXT NOT NULL, age INT, networth REAL) STRICT;');
66+
67+
await db.execute('CREATE TABLE IF NOT EXISTS t1(id INTEGER PRIMARY KEY, a INTEGER, b INTEGER, c TEXT)');
6568
} catch (e) {
6669
console.warn('error on before each', e);
6770
}
@@ -590,5 +593,22 @@ export function registerBaseTests() {
590593

591594
expect(result.rows?.length).to.equal(1);
592595
});
596+
597+
it('10000 INSERTs', async () => {
598+
let start = performance.now();
599+
for (let i = 0; i < 1000; ++i) {
600+
const n = randomIntFromInterval(0, 100000);
601+
await db.execute(`INSERT INTO t1(a, b, c) VALUES(?, ?, ?)`, [
602+
i + 1,
603+
n,
604+
numberName(n),
605+
]);
606+
}
607+
await db.execute('PRAGMA wal_checkpoint(RESTART)');
608+
let end = performance.now();
609+
let duration = end - start;
610+
611+
expect(duration).lessThan(2000);
612+
});
593613
});
594614
}

tests/tests/sqlite/utils.ts

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
export function randomIntFromInterval(min: number, max: number) {
2+
// min included and max excluded
3+
return Math.random() * (max - min) + min;
4+
}
5+
6+
export function numberName(n: number) {
7+
if (n == 0) {
8+
return 'zero';
9+
}
10+
11+
let numberName: string[] = [];
12+
let d43 = Math.floor(n / 1000);
13+
if (d43 != 0) {
14+
numberName.push(names100[d43]);
15+
numberName.push('thousand');
16+
n -= d43 * 1000;
17+
}
18+
19+
let d2 = Math.floor(n / 100);
20+
if (d2 != 0) {
21+
numberName.push(names100[d2]);
22+
numberName.push('hundred');
23+
n -= d2 * 100;
24+
}
25+
26+
let d10 = n;
27+
if (d10 != 0) {
28+
numberName.push(names100[d10]);
29+
}
30+
31+
return numberName.join(' ');
32+
}
33+
34+
export function assertAlways(condition: boolean) {
35+
if (!condition) {
36+
throw Error('Assertion failed');
37+
}
38+
}
39+
40+
const digits = [
41+
'',
42+
'one',
43+
'two',
44+
'three',
45+
'four',
46+
'five',
47+
'six',
48+
'seven',
49+
'eight',
50+
'nine',
51+
];
52+
const names100: string[] = [
53+
...digits,
54+
...[
55+
'ten',
56+
'eleven',
57+
'twelve',
58+
'thirteen',
59+
'fourteen',
60+
'fifteen',
61+
'sixteen',
62+
'seventeen',
63+
'eighteen',
64+
'nineteen',
65+
],
66+
...digits.map((digit) => `twenty${digit != '' ? '-' + digit : ''}`),
67+
...digits.map((digit) => `thirty${digit != '' ? '-' + digit : ''}`),
68+
...digits.map((digit) => `forty${digit != '' ? '-' + digit : ''}`),
69+
...digits.map((digit) => `fifty${digit != '' ? '-' + digit : ''}`),
70+
...digits.map((digit) => `sixty${digit != '' ? '-' + digit : ''}`),
71+
...digits.map((digit) => `seventy${digit != '' ? '-' + digit : ''}`),
72+
...digits.map((digit) => `eighty${digit != '' ? '-' + digit : ''}`),
73+
...digits.map((digit) => `ninety${digit != '' ? '-' + digit : ''}`),
74+
];

0 commit comments

Comments
 (0)