@harperfast/harper 5.3.0 → 5.3.1
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.
- package/bin/copyDb.ts +5 -1
- package/bin/deployRenderer.ts +3 -0
- package/components/Application.ts +66 -22
- package/components/DESIGN.md +89 -36
- package/components/componentLoader.ts +2 -0
- package/components/deploymentRecorder.ts +18 -1
- package/components/installFingerprint.ts +123 -0
- package/components/mcp/DESIGN.md +4 -4
- package/components/operations.js +29 -0
- package/config/DESIGN.md +5 -5
- package/dataLayer/DESIGN.md +37 -22
- package/dataLayer/backupRepository.ts +248 -0
- package/dataLayer/restoreMarker.ts +30 -75
- package/dataLayer/rocksdbBackup.ts +253 -110
- package/dist/bin/copyDb.js +3 -0
- package/dist/bin/copyDb.js.map +1 -1
- package/dist/bin/deployRenderer.js +3 -0
- package/dist/bin/deployRenderer.js.map +1 -1
- package/dist/components/Application.d.ts +5 -0
- package/dist/components/Application.js +51 -19
- package/dist/components/Application.js.map +1 -1
- package/dist/components/componentLoader.js +2 -0
- package/dist/components/componentLoader.js.map +1 -1
- package/dist/components/deploymentRecorder.js +18 -1
- package/dist/components/deploymentRecorder.js.map +1 -1
- package/dist/components/installFingerprint.d.ts +39 -0
- package/dist/components/installFingerprint.js +113 -0
- package/dist/components/installFingerprint.js.map +1 -0
- package/dist/components/operations.d.ts +2 -0
- package/dist/components/operations.js +31 -0
- package/dist/components/operations.js.map +1 -1
- package/dist/dataLayer/backupRepository.d.ts +33 -0
- package/dist/dataLayer/backupRepository.js +232 -0
- package/dist/dataLayer/backupRepository.js.map +1 -0
- package/dist/dataLayer/restoreMarker.d.ts +4 -1
- package/dist/dataLayer/restoreMarker.js +29 -68
- package/dist/dataLayer/restoreMarker.js.map +1 -1
- package/dist/dataLayer/rocksdbBackup.js +221 -112
- package/dist/dataLayer/rocksdbBackup.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js.map +1 -1
- package/dist/json/systemSchema.json +14 -0
- package/dist/resources/DatabaseTransaction.d.ts +140 -11
- package/dist/resources/DatabaseTransaction.js +1055 -464
- package/dist/resources/DatabaseTransaction.js.map +1 -1
- package/dist/resources/IterableEventQueue.d.ts +2 -1
- package/dist/resources/IterableEventQueue.js +16 -8
- package/dist/resources/IterableEventQueue.js.map +1 -1
- package/dist/resources/LMDBTransaction.d.ts +13 -2
- package/dist/resources/LMDBTransaction.js +219 -93
- package/dist/resources/LMDBTransaction.js.map +1 -1
- package/dist/resources/RecordEncoder.js +2 -3
- package/dist/resources/RecordEncoder.js.map +1 -1
- package/dist/resources/Resource.js +5 -6
- package/dist/resources/Resource.js.map +1 -1
- package/dist/resources/ResourceInterface.d.ts +3 -1
- package/dist/resources/ResourceInterface.js.map +1 -1
- package/dist/resources/RocksIndexStore.d.ts +2 -1
- package/dist/resources/RocksIndexStore.js +3 -0
- package/dist/resources/RocksIndexStore.js.map +1 -1
- package/dist/resources/Table.js +116 -12
- package/dist/resources/Table.js.map +1 -1
- package/dist/resources/analytics/write.js +6 -2
- package/dist/resources/analytics/write.js.map +1 -1
- package/dist/resources/auditStore.d.ts +71 -17
- package/dist/resources/auditStore.js +248 -64
- package/dist/resources/auditStore.js.map +1 -1
- package/dist/resources/branchDatabase.js +2 -0
- package/dist/resources/branchDatabase.js.map +1 -1
- package/dist/resources/databases.js +8 -2
- package/dist/resources/databases.js.map +1 -1
- package/dist/resources/indexes/fullTextNativeBinding.d.ts +6 -2
- package/dist/resources/indexes/fullTextNativeBinding.js +12 -2
- package/dist/resources/indexes/fullTextNativeBinding.js.map +1 -1
- package/dist/resources/indexes/fullTextQueryIndex.d.ts +4 -0
- package/dist/resources/indexes/fullTextQueryIndex.js +207 -10
- package/dist/resources/indexes/fullTextQueryIndex.js.map +1 -1
- package/dist/resources/models/Models.d.ts +11 -0
- package/dist/resources/models/Models.js +95 -4
- package/dist/resources/models/Models.js.map +1 -1
- package/dist/resources/models/backendRegistry.d.ts +8 -0
- package/dist/resources/models/backendRegistry.js +15 -1
- package/dist/resources/models/backendRegistry.js.map +1 -1
- package/dist/resources/models/bootstrap.d.ts +2 -0
- package/dist/resources/models/bootstrap.js +6 -0
- package/dist/resources/models/bootstrap.js.map +1 -1
- package/dist/resources/models/calibration.d.ts +88 -0
- package/dist/resources/models/calibration.js +244 -0
- package/dist/resources/models/calibration.js.map +1 -0
- package/dist/resources/models/calibrationStore.d.ts +163 -0
- package/dist/resources/models/calibrationStore.js +986 -0
- package/dist/resources/models/calibrationStore.js.map +1 -0
- package/dist/resources/models/decisionStore.d.ts +24 -0
- package/dist/resources/models/decisionStore.js +45 -0
- package/dist/resources/models/decisionStore.js.map +1 -1
- package/dist/resources/models/generativeDecision.js +44 -15
- package/dist/resources/models/generativeDecision.js.map +1 -1
- package/dist/resources/models/types.d.ts +7 -0
- package/dist/resources/recordLock.d.ts +8 -5
- package/dist/resources/recordLock.js +6 -4
- package/dist/resources/recordLock.js.map +1 -1
- package/dist/resources/replayLogs.js +8 -1
- package/dist/resources/replayLogs.js.map +1 -1
- package/dist/resources/scheduler/engine.d.ts +4 -0
- package/dist/resources/scheduler/engine.js +30 -2
- package/dist/resources/scheduler/engine.js.map +1 -1
- package/dist/resources/search.d.ts +16 -4
- package/dist/resources/search.js +117 -13
- package/dist/resources/search.js.map +1 -1
- package/dist/resources/transaction.js +85 -5
- package/dist/resources/transaction.js.map +1 -1
- package/dist/resources/transactionBroadcast.d.ts +8 -0
- package/dist/resources/transactionBroadcast.js +65 -0
- package/dist/resources/transactionBroadcast.js.map +1 -1
- package/dist/security/keys.d.ts +1 -1
- package/dist/security/keys.js +170 -120
- package/dist/security/keys.js.map +1 -1
- package/dist/server/http.js +10 -0
- package/dist/server/http.js.map +1 -1
- package/dist/server/serverHelpers/Request.js +11 -2
- package/dist/server/serverHelpers/Request.js.map +1 -1
- package/dist/server/serverHelpers/contentTypes.js +8 -3
- package/dist/server/serverHelpers/contentTypes.js.map +1 -1
- package/dist/server/serverHelpers/uwsServer.js +38 -7
- package/dist/server/serverHelpers/uwsServer.js.map +1 -1
- package/dist/server/threads/manageThreads.d.ts +3 -3
- package/dist/server/threads/manageThreads.js +15 -13
- package/dist/server/threads/manageThreads.js.map +1 -1
- package/dist/server/threads/threadServer.d.ts +3 -0
- package/dist/server/threads/threadServer.js +24 -6
- package/dist/server/threads/threadServer.js.map +1 -1
- package/dist/upgrade/directives/5-3-0.js +9 -3
- package/dist/upgrade/directives/5-3-0.js.map +1 -1
- package/dist/utility/durableFile.d.ts +36 -0
- package/dist/utility/durableFile.js +106 -0
- package/dist/utility/durableFile.js.map +1 -0
- package/dist/utility/errors/hdbError.d.ts +4 -0
- package/dist/utility/errors/hdbError.js +10 -1
- package/dist/utility/errors/hdbError.js.map +1 -1
- package/dist/utility/globalSchema.d.ts +9 -0
- package/dist/utility/hdbTerms.d.ts +1 -0
- package/dist/utility/hdbTerms.js +1 -0
- package/dist/utility/hdbTerms.js.map +1 -1
- package/dist/validation/configValidator.js +29 -0
- package/dist/validation/configValidator.js.map +1 -1
- package/index.ts +7 -0
- package/json/systemSchema.json +14 -0
- package/npm-shrinkwrap.json +22 -22
- package/package.json +2 -2
- package/resources/DESIGN.md +57 -272
- package/resources/DatabaseTransaction.ts +708 -87
- package/resources/FULL_TEXT.md +6 -2
- package/resources/IterableEventQueue.ts +14 -7
- package/resources/LMDBTransaction.ts +212 -84
- package/resources/RecordEncoder.ts +2 -3
- package/resources/Resource.ts +5 -6
- package/resources/ResourceInterface.ts +3 -1
- package/resources/RocksIndexStore.ts +5 -0
- package/resources/Table.ts +118 -15
- package/resources/analytics/write.ts +6 -2
- package/resources/audit-retention.md +203 -0
- package/resources/auditStore.ts +306 -84
- package/resources/branchDatabase.ts +2 -0
- package/resources/databases.ts +6 -2
- package/resources/indexes/DESIGN.md +120 -177
- package/resources/indexes/fullTextNativeBinding.ts +22 -3
- package/resources/indexes/fullTextQueryIndex.ts +274 -11
- package/resources/models/DESIGN.md +11 -3
- package/resources/models/Models.ts +127 -4
- package/resources/models/backendRegistry.ts +17 -0
- package/resources/models/bootstrap.ts +9 -1
- package/resources/models/calibration.ts +298 -0
- package/resources/models/calibrationStore.ts +1167 -0
- package/resources/models/decisionStore.ts +57 -0
- package/resources/models/generativeDecision.ts +54 -16
- package/resources/models/types.ts +6 -0
- package/resources/record-locks.md +155 -141
- package/resources/recordLock.ts +12 -6
- package/resources/replayLogs.ts +9 -2
- package/resources/scheduler/DESIGN.md +4 -3
- package/resources/scheduler/engine.ts +35 -2
- package/resources/search.ts +154 -16
- package/resources/transaction.ts +50 -5
- package/resources/transactionBroadcast.ts +69 -0
- package/security/DESIGN.md +9 -30
- package/security/keys.ts +175 -127
- package/server/DESIGN.md +70 -36
- package/server/http.ts +10 -0
- package/server/serverHelpers/Request.ts +10 -2
- package/server/serverHelpers/contentTypes.ts +5 -3
- package/server/serverHelpers/uwsServer.ts +34 -7
- package/server/threads/manageThreads.js +16 -14
- package/server/threads/threadServer.js +24 -6
- package/studio/web/assets/{Chat-CNEKMllJ.js → Chat-4LMxI0yB.js} +1 -1
- package/studio/web/assets/{FloatingChat-CEnWhHeR.js → FloatingChat-kWHApEtF.js} +3 -3
- package/studio/web/assets/{SearchDialog-CwhJdEdY.js → SearchDialog-B7ymna97.js} +1 -1
- package/studio/web/assets/{apiToken-DC5vsaaO.js → apiToken-CE3AAt9f.js} +1 -1
- package/studio/web/assets/{applications-DQZxDy0x.js → applications-DdN7CqsB.js} +1 -1
- package/studio/web/assets/{cssMode-Dz2DxF4e.js → cssMode-BpySZUSt.js} +1 -1
- package/studio/web/assets/{editor-B3mjd3tz.js → editor-myLCVv9C.js} +1 -1
- package/studio/web/assets/{html-BsRGM7tp.js → html-DGNYO55O.js} +1 -1
- package/studio/web/assets/{htmlMode-tUKJaA3o.js → htmlMode-BUgpQr41.js} +1 -1
- package/studio/web/assets/{index-BuqFjN5K.js → index-FN4KC9va.js} +39 -39
- package/studio/web/assets/index-QLZw6xrU.css +1 -0
- package/studio/web/assets/{index.lazy-CcpfQFY_.js → index.lazy-DZFuaumG.js} +1 -1
- package/studio/web/assets/{javascript-BZ_uRGHl.js → javascript-DiBzh4pj.js} +1 -1
- package/studio/web/assets/{jsonMode-DgB-aFMj.js → jsonMode-Bm312nmu.js} +1 -1
- package/studio/web/assets/{languageServices-BleuBw17.js → languageServices-Dz2K9rZN.js} +1 -1
- package/studio/web/assets/{lspLanguageFeatures-ByVYLSsQ.js → lspLanguageFeatures-CNu1L5xn.js} +1 -1
- package/studio/web/assets/{notifications-TuzN0IMi.js → notifications--nwFLGmM.js} +1 -1
- package/studio/web/assets/{notifications-D1Nf-Edn.js → notifications-BelKw5bR.js} +1 -1
- package/studio/web/assets/{profile-D7C7Lupz.js → profile-AU5FjOBx.js} +1 -1
- package/studio/web/assets/{regions-nGQCm-v8.js → regions-C0sTSEHH.js} +1 -1
- package/studio/web/assets/{register-C3x9Ze6P.js → register-DyNR2rGk.js} +2 -2
- package/studio/web/assets/{setComponentFile-DpjrRqeG.js → setComponentFile-BkWx8AN3.js} +1 -1
- package/studio/web/assets/{setup-CGiKLZ9e.js → setup-D6LZS78d.js} +2 -2
- package/studio/web/assets/{status-CGJwrNPH.js → status-BCWnn70o.js} +1 -1
- package/studio/web/assets/{toggleHighContrast-C-Ne6P7T.js → toggleHighContrast-pyeGJ6W1.js} +1 -1
- package/studio/web/assets/{tsMode-CSreYTys.js → tsMode-CGV3iaWC.js} +1 -1
- package/studio/web/assets/{typescript-MnxBk89W.js → typescript-Ci7Khvwo.js} +1 -1
- package/studio/web/assets/{useEntityRestURL-TNrh77-s.js → useEntityRestURL-DNiz3aZ0.js} +1 -1
- package/studio/web/assets/{workers-BfZlUNVI.js → workers-byzxjbqy.js} +1 -1
- package/studio/web/assets/{xml-BHd6qGH7.js → xml-DGnHQ3CX.js} +1 -1
- package/studio/web/assets/{yaml-C53R8OQq.js → yaml-BUoTnPWb.js} +1 -1
- package/studio/web/index.html +2 -2
- package/upgrade/directives/5-3-0.ts +10 -3
- package/utility/durableFile.ts +96 -0
- package/utility/errors/hdbError.ts +9 -0
- package/utility/hdbTerms.ts +1 -0
- package/validation/configValidator.ts +31 -0
- package/studio/web/assets/index-72cEH474.css +0 -1
|
@@ -1,21 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
closeSync,
|
|
5
|
-
existsSync,
|
|
6
|
-
mkdirSync,
|
|
7
|
-
openSync,
|
|
8
|
-
readdirSync,
|
|
9
|
-
readFileSync,
|
|
10
|
-
renameSync,
|
|
11
|
-
fsyncSync,
|
|
12
|
-
unlinkSync,
|
|
13
|
-
writeSync,
|
|
14
|
-
} from 'node:fs';
|
|
3
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, unlinkSync } from 'node:fs';
|
|
15
4
|
import { basename, dirname, isAbsolute, join, resolve } from 'node:path';
|
|
16
5
|
import { createHash } from 'node:crypto';
|
|
17
6
|
import { tryFileLock, fileLockRelease } from '@harperfast/rocksdb-js';
|
|
18
|
-
import {
|
|
7
|
+
import { fsyncDirectory, pathPresent, writeFileDurably } from '../utility/durableFile.ts';
|
|
19
8
|
|
|
20
9
|
/**
|
|
21
10
|
* Restore lock + marker protocol for RocksDB database restores (online operation and offline CLI),
|
|
@@ -112,11 +101,11 @@ export type RestoreState = 'in-progress' | 'incomplete' | 'clear';
|
|
|
112
101
|
* distinguish debris from a crashed restore.
|
|
113
102
|
*/
|
|
114
103
|
export function restoreMarkerPresent(dbPath: string): boolean {
|
|
115
|
-
return
|
|
104
|
+
return pathPresent(restoringMarkerPath(dbPath));
|
|
116
105
|
}
|
|
117
106
|
|
|
118
107
|
export function databaseDropMarkerPresent(dbPath: string): boolean {
|
|
119
|
-
return
|
|
108
|
+
return pathPresent(droppingMarkerPath(dbPath));
|
|
120
109
|
}
|
|
121
110
|
|
|
122
111
|
/** The lock and (optional) marker held by a begin/acquire call, threaded back to complete/abandon. */
|
|
@@ -151,9 +140,9 @@ export type RestoreLock = {
|
|
|
151
140
|
* before any destructive step, so a database without a marker has nothing to protect yet.
|
|
152
141
|
*/
|
|
153
142
|
export function checkRestoreState(dbPath: string): RestoreState {
|
|
154
|
-
if (!
|
|
143
|
+
if (!pathPresent(restoringMarkerPath(dbPath))) return 'clear';
|
|
155
144
|
const lockPath = restoreLockPath(dbPath);
|
|
156
|
-
if (
|
|
145
|
+
if (pathPresent(lockPath)) {
|
|
157
146
|
const token = tryFileLock(lockPath);
|
|
158
147
|
if (token === 0) return 'in-progress';
|
|
159
148
|
fileLockRelease(token);
|
|
@@ -161,26 +150,6 @@ export function checkRestoreState(dbPath: string): RestoreState {
|
|
|
161
150
|
return 'incomplete';
|
|
162
151
|
}
|
|
163
152
|
|
|
164
|
-
/**
|
|
165
|
-
* fsync a directory so a create/unlink of an entry within it is durable. Best-effort: Windows (and
|
|
166
|
-
* some filesystems) reject opening a directory for fsync with EPERM/EISDIR/ENOTSUP — the durability
|
|
167
|
-
* flush is a POSIX nicety, so treat those as a no-op rather than failing the restore.
|
|
168
|
-
*/
|
|
169
|
-
function fsyncDir(dir: string): void {
|
|
170
|
-
let dirFd: number;
|
|
171
|
-
try {
|
|
172
|
-
dirFd = openSync(dir, 'r');
|
|
173
|
-
} catch (error: any) {
|
|
174
|
-
if (isUnsupportedSyncError(error)) return;
|
|
175
|
-
throw error;
|
|
176
|
-
}
|
|
177
|
-
try {
|
|
178
|
-
fsyncTolerantSync(dirFd);
|
|
179
|
-
} finally {
|
|
180
|
-
closeSync(dirFd);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
153
|
/**
|
|
185
154
|
* Take the per-database restore lock without writing a marker. Restore and drop build their durable
|
|
186
155
|
* protocols on this shared exclusion primitive. Throws (statusCode 409) if the lock is already held.
|
|
@@ -189,7 +158,7 @@ export function acquireRestoreLock(dbPath: string): RestoreLock {
|
|
|
189
158
|
const metaDir = restoreMetaDir(dbPath);
|
|
190
159
|
const createMetaDir = !existsSync(metaDir);
|
|
191
160
|
mkdirSync(metaDir, { recursive: true });
|
|
192
|
-
if (createMetaDir)
|
|
161
|
+
if (createMetaDir) fsyncDirectory(dirname(metaDir));
|
|
193
162
|
const token = tryFileLock(restoreLockPath(dbPath));
|
|
194
163
|
if (token === 0) {
|
|
195
164
|
const error: any = new Error(`Restore already in progress for database at ${dbPath}`);
|
|
@@ -226,28 +195,7 @@ function markerIsIntact(markerPath: string, dbPath: string): boolean {
|
|
|
226
195
|
* left by an earlier crash is this database's own debris and is simply overwritten.
|
|
227
196
|
*/
|
|
228
197
|
function publishMarker(dbPath: string, markerPath: string, content: string): void {
|
|
229
|
-
|
|
230
|
-
const tempPath = join(metaDir, restoreMetaKey(dbPath) + MARKER_TEMP_SUFFIX);
|
|
231
|
-
try {
|
|
232
|
-
const fd = openSync(tempPath, 'w');
|
|
233
|
-
try {
|
|
234
|
-
writeSync(fd, content);
|
|
235
|
-
fsyncSync(fd);
|
|
236
|
-
} finally {
|
|
237
|
-
closeSync(fd);
|
|
238
|
-
}
|
|
239
|
-
renameSync(tempPath, markerPath);
|
|
240
|
-
} catch (error) {
|
|
241
|
-
try {
|
|
242
|
-
unlinkSync(tempPath);
|
|
243
|
-
} catch {
|
|
244
|
-
// debris either way; the write failure is the error worth reporting
|
|
245
|
-
}
|
|
246
|
-
throw error;
|
|
247
|
-
}
|
|
248
|
-
// fsync the metadata directory so the marker's directory entry is durable — without this a
|
|
249
|
-
// power loss can lose the entry, and a half-purged database would load as healthy
|
|
250
|
-
fsyncDir(metaDir);
|
|
198
|
+
writeFileDurably(markerPath, content, restoreMetaKey(dbPath) + MARKER_TEMP_SUFFIX);
|
|
251
199
|
}
|
|
252
200
|
|
|
253
201
|
function publishRestoringMarker(dbPath: string): void {
|
|
@@ -263,48 +211,55 @@ function publishRestoringMarker(dbPath: string): void {
|
|
|
263
211
|
* destructive step. Returns the lock (with `preexisting` set when a marker was already present, so
|
|
264
212
|
* a failed recovery attempt knows not to clear it). Throws (statusCode 409) if another restore
|
|
265
213
|
* already holds the lock.
|
|
214
|
+
* `beforePublishMarker` runs synchronously under the lock, after admission but before publication,
|
|
215
|
+
* so a caller can durably claim its source before a crash can leave a restoring marker behind.
|
|
266
216
|
*
|
|
267
217
|
* An intact marker is left exactly as it is. A recovery attempt runs over a directory an earlier
|
|
268
218
|
* restore may have half-purged, so the marker it finds is the only thing keeping that directory
|
|
269
219
|
* from loading as healthy; rewriting it buys nothing (the content it would write is the content
|
|
270
220
|
* already there) and risks everything.
|
|
271
221
|
*/
|
|
272
|
-
export function beginRestore(dbPath: string): RestoreLock {
|
|
222
|
+
export function beginRestore(dbPath: string, beforePublishMarker?: () => void): RestoreLock {
|
|
273
223
|
const markerPath = restoringMarkerPath(dbPath);
|
|
274
224
|
const lock = acquireRestoreLock(dbPath);
|
|
275
225
|
// Sampled while holding the lock, not before it: a restore that waited out an earlier one would
|
|
276
226
|
// otherwise carry the earlier run's "no marker" reading, and on its own pre-destruction failure
|
|
277
227
|
// clear the marker protecting a directory that run had already half-purged.
|
|
278
|
-
const preexisting = existsSync(markerPath);
|
|
279
228
|
try {
|
|
229
|
+
lock.preexisting = pathPresent(markerPath);
|
|
280
230
|
if (databaseDropMarkerPresent(dbPath)) {
|
|
281
231
|
const error: any = new Error(`Database at ${dbPath} has an incomplete drop; retry drop_database first`);
|
|
282
232
|
error.statusCode = 409;
|
|
283
233
|
throw error;
|
|
284
234
|
}
|
|
285
|
-
|
|
235
|
+
beforePublishMarker?.();
|
|
236
|
+
if (!lock.preexisting || !markerIsIntact(markerPath, dbPath)) publishRestoringMarker(dbPath);
|
|
286
237
|
// An intact marker is kept, but its durability is not assumed: the publisher that wrote it may
|
|
287
238
|
// have been interrupted between the rename and this flush, which would leave the directory
|
|
288
239
|
// entry — the thing the startup scan reads — still only in the page cache.
|
|
289
|
-
else
|
|
240
|
+
else fsyncDirectory(restoreMetaDir(dbPath));
|
|
290
241
|
} catch (error) {
|
|
291
242
|
fileLockRelease(lock.token);
|
|
292
243
|
throw error;
|
|
293
244
|
}
|
|
294
|
-
return
|
|
245
|
+
return lock;
|
|
295
246
|
}
|
|
296
247
|
|
|
297
248
|
/**
|
|
298
249
|
* Mark the restore successful: delete the marker (while still holding the lock), then release
|
|
299
250
|
* the lock.
|
|
300
251
|
*/
|
|
252
|
+
export function clearRestoringMarker(lock: RestoreLock): void {
|
|
253
|
+
unlinkSync(restoringMarkerPath(lock.dbPath));
|
|
254
|
+
// fsync the metadata directory so the marker's *removal* is durable — symmetric with the
|
|
255
|
+
// creation fsync in beginRestore. Without it, a power loss could resurrect the marker's
|
|
256
|
+
// directory entry and misclassify a fully-restored database as incomplete.
|
|
257
|
+
fsyncDirectory(restoreMetaDir(lock.dbPath));
|
|
258
|
+
}
|
|
259
|
+
|
|
301
260
|
export function completeRestore(lock: RestoreLock): void {
|
|
302
261
|
try {
|
|
303
|
-
|
|
304
|
-
// fsync the metadata directory so the marker's *removal* is durable — symmetric with the
|
|
305
|
-
// creation fsync in beginRestore. Without it, a power loss could resurrect the marker's
|
|
306
|
-
// directory entry and misclassify a fully-restored database as incomplete.
|
|
307
|
-
fsyncDir(restoreMetaDir(lock.dbPath));
|
|
262
|
+
clearRestoringMarker(lock);
|
|
308
263
|
} finally {
|
|
309
264
|
fileLockRelease(lock.token);
|
|
310
265
|
}
|
|
@@ -328,7 +283,7 @@ export function clearRestoreMarker(lock: RestoreLock): void {
|
|
|
328
283
|
const markerPath = restoringMarkerPath(lock.dbPath);
|
|
329
284
|
if (existsSync(markerPath)) {
|
|
330
285
|
unlinkSync(markerPath);
|
|
331
|
-
|
|
286
|
+
fsyncDirectory(restoreMetaDir(lock.dbPath));
|
|
332
287
|
}
|
|
333
288
|
} finally {
|
|
334
289
|
fileLockRelease(lock.token);
|
|
@@ -459,7 +414,7 @@ export function beginDatabaseDrop(
|
|
|
459
414
|
}
|
|
460
415
|
blobDatabaseName = marker.blobDatabaseName;
|
|
461
416
|
blobPaths = marker.blobPaths;
|
|
462
|
-
|
|
417
|
+
fsyncDirectory(restoreMetaDir(dbPath));
|
|
463
418
|
} else {
|
|
464
419
|
const encodedBlobPaths = encodeBlobPaths(blobPaths);
|
|
465
420
|
publishMarker(
|
|
@@ -479,16 +434,16 @@ function removeDatabaseDropMarker(lock: DatabaseDropLock): void {
|
|
|
479
434
|
const markerPath = droppingMarkerPath(lock.dbPath);
|
|
480
435
|
if (existsSync(markerPath)) {
|
|
481
436
|
unlinkSync(markerPath);
|
|
482
|
-
|
|
437
|
+
fsyncDirectory(restoreMetaDir(lock.dbPath));
|
|
483
438
|
}
|
|
484
439
|
}
|
|
485
440
|
|
|
486
441
|
export function completeDatabaseDrop(lock: DatabaseDropLock): void {
|
|
487
442
|
try {
|
|
488
|
-
|
|
443
|
+
fsyncDirectory(dirname(lock.dbPath));
|
|
489
444
|
for (const blobPath of lock.blobPaths) {
|
|
490
445
|
const parent = dirname(blobPath);
|
|
491
|
-
if (existsSync(parent))
|
|
446
|
+
if (existsSync(parent)) fsyncDirectory(parent);
|
|
492
447
|
}
|
|
493
448
|
removeDatabaseDropMarker(lock);
|
|
494
449
|
} finally {
|