cozy-pouch-link 60.30.3 → 60.30.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -39,6 +39,21 @@ function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflec
|
|
|
39
39
|
|
|
40
40
|
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
|
|
41
41
|
|
|
42
|
+
// busy_timeout is per-connection, not per-database, and applies to the
|
|
43
|
+
// statements issued after it. Two values are needed because the statements it
|
|
44
|
+
// covers here do not run on the same thread:
|
|
45
|
+
//
|
|
46
|
+
// - journal_mode=WAL runs through executeSync, ON the JS thread, and needs the
|
|
47
|
+
// write lock to switch. Under a replication batch it would wait for the
|
|
48
|
+
// whole timeout, freezing the UI, hence the short value. Losing that race is
|
|
49
|
+
// harmless: the mode is persistent, so the next open retries it, and it is a
|
|
50
|
+
// no-op once the database is already in WAL.
|
|
51
|
+
// - queries run through executeAsync, OFF the JS thread, so waiting costs
|
|
52
|
+
// latency rather than responsiveness. A short value there would make them
|
|
53
|
+
// fail during a bulk insert and fall back to pouch-find for no reason.
|
|
54
|
+
var SETUP_BUSY_TIMEOUT_MS = 250;
|
|
55
|
+
var QUERY_BUSY_TIMEOUT_MS = 5000;
|
|
56
|
+
|
|
42
57
|
var SQLiteQueryEngine = /*#__PURE__*/function (_DatabaseQueryEngine) {
|
|
43
58
|
(0, _inherits2.default)(SQLiteQueryEngine, _DatabaseQueryEngine);
|
|
44
59
|
|
|
@@ -87,19 +102,31 @@ var SQLiteQueryEngine = /*#__PURE__*/function (_DatabaseQueryEngine) {
|
|
|
87
102
|
},
|
|
88
103
|
get: function get() {
|
|
89
104
|
if (resolved) return resolved;
|
|
90
|
-
|
|
105
|
+
var handle = (0, _opSqlite.open)({
|
|
91
106
|
name: fileDbName
|
|
107
|
+
}); // Each pragma is independent and best-effort: journal_mode can lose the
|
|
108
|
+
// race for the write lock, and sharing one try/catch would then skip the
|
|
109
|
+
// query timeout and strand the connection on the setup one.
|
|
110
|
+
|
|
111
|
+
var applyPragma = function applyPragma(sql) {
|
|
112
|
+
try {
|
|
113
|
+
handle.executeSync(sql);
|
|
114
|
+
} catch (err) {
|
|
115
|
+
_logger.default.error(err);
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
applyPragma("PRAGMA busy_timeout=".concat(SETUP_BUSY_TIMEOUT_MS));
|
|
120
|
+
applyPragma('PRAGMA journal_mode=WAL');
|
|
121
|
+
applyPragma("PRAGMA busy_timeout=".concat(QUERY_BUSY_TIMEOUT_MS));
|
|
122
|
+
resolved = handle;
|
|
123
|
+
Promise.resolve().then(function () {
|
|
124
|
+
return (0, _sql.executeSQL)(handle, (0, _sql.makeSQLCreateDocIDIndex)());
|
|
125
|
+
}).then(function () {
|
|
126
|
+
return (0, _sql.executeSQL)(handle, (0, _sql.makeSQLCreateDeletedIndex)());
|
|
127
|
+
}).catch(function (err) {
|
|
128
|
+
return _logger.default.error(err);
|
|
92
129
|
});
|
|
93
|
-
|
|
94
|
-
try {
|
|
95
|
-
(0, _sql.executeSQL)(resolved, 'PRAGMA journal_mode=WAL');
|
|
96
|
-
(0, _sql.executeSQL)(resolved, 'PRAGMA busy_timeout=5000');
|
|
97
|
-
(0, _sql.executeSQL)(resolved, (0, _sql.makeSQLCreateDocIDIndex)());
|
|
98
|
-
(0, _sql.executeSQL)(resolved, (0, _sql.makeSQLCreateDeletedIndex)());
|
|
99
|
-
} catch (err) {
|
|
100
|
-
_logger.default.error(err);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
130
|
return resolved;
|
|
104
131
|
}
|
|
105
132
|
});
|
|
@@ -3,6 +3,8 @@ import PouchDBQueryEngine from '../pouchdb/pouchdb'
|
|
|
3
3
|
import SQLiteQueryEngine from './sqliteDb.native'
|
|
4
4
|
|
|
5
5
|
jest.mock('@op-engineering/op-sqlite', () => ({ open: jest.fn() }))
|
|
6
|
+
|
|
7
|
+
import { open } from '@op-engineering/op-sqlite'
|
|
6
8
|
jest.mock('../pouchdb/pouchdb')
|
|
7
9
|
|
|
8
10
|
// The engine answers a query it cannot translate - or one SQLite rejects - by
|
|
@@ -68,3 +70,89 @@ describe('SQLiteQueryEngine find fallback', () => {
|
|
|
68
70
|
expect(PouchDBQueryEngine).not.toHaveBeenCalled()
|
|
69
71
|
})
|
|
70
72
|
})
|
|
73
|
+
|
|
74
|
+
describe('SQLiteQueryEngine openDB setup', () => {
|
|
75
|
+
const setup = ({ createIndexFails = false } = {}) => {
|
|
76
|
+
const executeSync = jest.fn()
|
|
77
|
+
const executeAsync = jest.fn(() =>
|
|
78
|
+
createIndexFails
|
|
79
|
+
? Promise.reject(new Error('database is locked'))
|
|
80
|
+
: Promise.resolve({ rows: { length: 0, item: () => undefined } })
|
|
81
|
+
)
|
|
82
|
+
open.mockReturnValue({ executeSync, executeAsync })
|
|
83
|
+
const engine = new SQLiteQueryEngine({ client: {} }, 'io.cozy.files')
|
|
84
|
+
engine.openDB('cozy-files')
|
|
85
|
+
return { engine, executeSync, executeAsync }
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
it('applies the pragmas synchronously so a query cannot outrun them', () => {
|
|
89
|
+
const { engine, executeSync } = setup()
|
|
90
|
+
|
|
91
|
+
expect(engine.db).toBeDefined()
|
|
92
|
+
expect(executeSync).toHaveBeenCalled()
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
it('sets busy_timeout before switching the journal mode', () => {
|
|
96
|
+
const { engine, executeSync } = setup()
|
|
97
|
+
void engine.db
|
|
98
|
+
|
|
99
|
+
const statements = executeSync.mock.calls.map(([sql]) => sql)
|
|
100
|
+
const firstTimeout = statements.findIndex(sql =>
|
|
101
|
+
sql.includes('busy_timeout')
|
|
102
|
+
)
|
|
103
|
+
const journalMode = statements.findIndex(sql =>
|
|
104
|
+
sql.includes('journal_mode')
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
expect(firstTimeout).toBeGreaterThanOrEqual(0)
|
|
108
|
+
expect(journalMode).toBeGreaterThan(firstTimeout)
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
it('keeps a locked CREATE INDEX from becoming an unhandled rejection', async () => {
|
|
112
|
+
const { engine } = setup({ createIndexFails: true })
|
|
113
|
+
const unhandled = jest.fn()
|
|
114
|
+
process.on('unhandledRejection', unhandled)
|
|
115
|
+
|
|
116
|
+
void engine.db
|
|
117
|
+
await new Promise(resolve => setImmediate(resolve))
|
|
118
|
+
await new Promise(resolve => setImmediate(resolve))
|
|
119
|
+
|
|
120
|
+
process.off('unhandledRejection', unhandled)
|
|
121
|
+
expect(unhandled).not.toHaveBeenCalled()
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
it('still returns a usable handle when the pragmas throw', () => {
|
|
125
|
+
open.mockReturnValue({
|
|
126
|
+
executeSync: jest.fn(() => {
|
|
127
|
+
throw new Error('database is locked')
|
|
128
|
+
}),
|
|
129
|
+
executeAsync: jest.fn().mockResolvedValue({})
|
|
130
|
+
})
|
|
131
|
+
const engine = new SQLiteQueryEngine({ client: {} }, 'io.cozy.files')
|
|
132
|
+
engine.openDB('cozy-files')
|
|
133
|
+
|
|
134
|
+
expect(engine.db).toBeDefined()
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
it('still raises the query timeout when the journal-mode switch is refused', () => {
|
|
138
|
+
const executeSync = jest.fn(sql => {
|
|
139
|
+
if (sql.includes('journal_mode')) {
|
|
140
|
+
throw new Error('database is locked')
|
|
141
|
+
}
|
|
142
|
+
})
|
|
143
|
+
open.mockReturnValue({
|
|
144
|
+
executeSync,
|
|
145
|
+
executeAsync: jest.fn().mockResolvedValue({})
|
|
146
|
+
})
|
|
147
|
+
const engine = new SQLiteQueryEngine({ client: {} }, 'io.cozy.files')
|
|
148
|
+
engine.openDB('cozy-files')
|
|
149
|
+
|
|
150
|
+
void engine.db
|
|
151
|
+
|
|
152
|
+
const timeouts = executeSync.mock.calls
|
|
153
|
+
.map(([sql]) => sql)
|
|
154
|
+
.filter(sql => sql.includes('busy_timeout'))
|
|
155
|
+
expect(timeouts).toHaveLength(2)
|
|
156
|
+
expect(timeouts[timeouts.length - 1]).toContain('5000')
|
|
157
|
+
})
|
|
158
|
+
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cozy-pouch-link",
|
|
3
|
-
"version": "60.30.
|
|
3
|
+
"version": "60.30.6",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "types/index.d.ts",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"url": "git+https://github.com/linagora/cozy-client.git"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"cozy-client": "^60.30.
|
|
16
|
+
"cozy-client": "^60.30.6",
|
|
17
17
|
"pouchdb-browser": "^7.2.2",
|
|
18
18
|
"pouchdb-find": "^7.2.2"
|
|
19
19
|
},
|
|
@@ -41,5 +41,5 @@
|
|
|
41
41
|
"typecheck": "tsc -p tsconfig.json"
|
|
42
42
|
},
|
|
43
43
|
"sideEffects": false,
|
|
44
|
-
"gitHead": "
|
|
44
|
+
"gitHead": "88101a3d13943828cd1cfcf39c40535c0a259afa"
|
|
45
45
|
}
|