@peerbit/shared-log 13.2.24 → 13.2.26
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/dist/src/checked-prune.d.ts +12 -0
- package/dist/src/checked-prune.d.ts.map +1 -1
- package/dist/src/checked-prune.js +33 -0
- package/dist/src/checked-prune.js.map +1 -1
- package/dist/src/coordinate-persistence.d.ts +211 -0
- package/dist/src/coordinate-persistence.d.ts.map +1 -0
- package/dist/src/coordinate-persistence.js +1133 -0
- package/dist/src/coordinate-persistence.js.map +1 -0
- package/dist/src/errors.d.ts +1 -0
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/errors.js +19 -0
- package/dist/src/errors.js.map +1 -1
- package/dist/src/index.d.ts +127 -133
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1400 -4269
- package/dist/src/index.js.map +1 -1
- package/dist/src/instance-lifecycle.d.ts +117 -0
- package/dist/src/instance-lifecycle.d.ts.map +1 -0
- package/dist/src/instance-lifecycle.js +254 -0
- package/dist/src/instance-lifecycle.js.map +1 -0
- package/dist/src/join-warmup.d.ts +86 -0
- package/dist/src/join-warmup.d.ts.map +1 -0
- package/dist/src/join-warmup.js +351 -0
- package/dist/src/join-warmup.js.map +1 -0
- package/dist/src/native-write-through-block-store.d.ts +123 -0
- package/dist/src/native-write-through-block-store.d.ts.map +1 -0
- package/dist/src/native-write-through-block-store.js +989 -0
- package/dist/src/native-write-through-block-store.js.map +1 -0
- package/dist/src/peer-session.d.ts +117 -0
- package/dist/src/peer-session.d.ts.map +1 -0
- package/dist/src/peer-session.js +259 -0
- package/dist/src/peer-session.js.map +1 -0
- package/dist/src/replication-announcement.d.ts +116 -0
- package/dist/src/replication-announcement.d.ts.map +1 -0
- package/dist/src/replication-announcement.js +515 -0
- package/dist/src/replication-announcement.js.map +1 -0
- package/dist/src/replicator-liveness.d.ts +59 -0
- package/dist/src/replicator-liveness.d.ts.map +1 -0
- package/dist/src/replicator-liveness.js +304 -0
- package/dist/src/replicator-liveness.js.map +1 -0
- package/dist/src/sync/dispatch-lifecycle.d.ts +48 -0
- package/dist/src/sync/dispatch-lifecycle.d.ts.map +1 -0
- package/dist/src/sync/dispatch-lifecycle.js +141 -0
- package/dist/src/sync/dispatch-lifecycle.js.map +1 -0
- package/dist/src/sync/factory.d.ts +29 -0
- package/dist/src/sync/factory.d.ts.map +1 -0
- package/dist/src/sync/factory.js +87 -0
- package/dist/src/sync/factory.js.map +1 -0
- package/dist/src/sync/pending-sync-store.d.ts +105 -0
- package/dist/src/sync/pending-sync-store.d.ts.map +1 -0
- package/dist/src/sync/pending-sync-store.js +877 -0
- package/dist/src/sync/pending-sync-store.js.map +1 -0
- package/dist/src/sync/rateless-iblt.d.ts +4 -1
- package/dist/src/sync/rateless-iblt.d.ts.map +1 -1
- package/dist/src/sync/rateless-iblt.js +102 -106
- package/dist/src/sync/rateless-iblt.js.map +1 -1
- package/dist/src/sync/simple.d.ts +10 -41
- package/dist/src/sync/simple.d.ts.map +1 -1
- package/dist/src/sync/simple.js +259 -952
- package/dist/src/sync/simple.js.map +1 -1
- package/dist/src/sync/sync-peer-state.d.ts +16 -0
- package/dist/src/sync/sync-peer-state.d.ts.map +1 -0
- package/dist/src/sync/sync-peer-state.js +82 -0
- package/dist/src/sync/sync-peer-state.js.map +1 -0
- package/package.json +12 -12
- package/src/checked-prune.ts +35 -0
- package/src/coordinate-persistence.ts +1796 -0
- package/src/errors.ts +21 -0
- package/src/index.ts +4014 -7858
- package/src/instance-lifecycle.ts +351 -0
- package/src/join-warmup.ts +507 -0
- package/src/native-write-through-block-store.ts +1170 -0
- package/src/peer-session.ts +336 -0
- package/src/replication-announcement.ts +744 -0
- package/src/replicator-liveness.ts +439 -0
- package/src/sync/dispatch-lifecycle.ts +230 -0
- package/src/sync/factory.ts +154 -0
- package/src/sync/pending-sync-store.ts +1085 -0
- package/src/sync/rateless-iblt.ts +122 -132
- package/src/sync/simple.ts +334 -1144
- package/src/sync/sync-peer-state.ts +107 -0
|
@@ -0,0 +1,1133 @@
|
|
|
1
|
+
import { Or, StringMatch, toId, } from "@peerbit/indexer-interface";
|
|
2
|
+
import { Entry, EntryType, } from "@peerbit/log";
|
|
3
|
+
import { getPreparedRawExchangeTimestamp } from "./exchange-heads.js";
|
|
4
|
+
import { isEntryReplicated, shouldAssigneToRangeBoundary as shouldAssignToRangeBoundary, } from "./ranges.js";
|
|
5
|
+
import { decodeReplicas } from "./replication.js";
|
|
6
|
+
import { emitSyncProfileDuration, emitSyncProfileEvent, syncProfileStart, } from "./sync/profile.js";
|
|
7
|
+
export const isPromiseLike = (value) => !!value && typeof value.then === "function";
|
|
8
|
+
export const mapMaybePromise = (value, fn) => (isPromiseLike(value) ? value.then(fn) : fn(value));
|
|
9
|
+
const EMPTY_HASHES = [];
|
|
10
|
+
export const normalizedHashValues = (hashes) => {
|
|
11
|
+
if (Array.isArray(hashes)) {
|
|
12
|
+
if (hashes.length === 0) {
|
|
13
|
+
return EMPTY_HASHES;
|
|
14
|
+
}
|
|
15
|
+
if (hashes.length === 1) {
|
|
16
|
+
return hashes[0] ? hashes : EMPTY_HASHES;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
const values = [];
|
|
20
|
+
const seen = new Set();
|
|
21
|
+
for (const hash of hashes) {
|
|
22
|
+
if (!hash || seen.has(hash)) {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
seen.add(hash);
|
|
26
|
+
values.push(hash);
|
|
27
|
+
}
|
|
28
|
+
return values;
|
|
29
|
+
};
|
|
30
|
+
export const combineCoordinateDeleteHashes = (nextHashes, deleteHashes) => {
|
|
31
|
+
if (!deleteHashes || deleteHashes.length === 0) {
|
|
32
|
+
return nextHashes;
|
|
33
|
+
}
|
|
34
|
+
if (nextHashes.length === 0) {
|
|
35
|
+
return deleteHashes;
|
|
36
|
+
}
|
|
37
|
+
const combined = [];
|
|
38
|
+
const seen = new Set();
|
|
39
|
+
for (const hash of nextHashes) {
|
|
40
|
+
if (!seen.has(hash)) {
|
|
41
|
+
seen.add(hash);
|
|
42
|
+
combined.push(hash);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
for (const hash of deleteHashes) {
|
|
46
|
+
if (!seen.has(hash)) {
|
|
47
|
+
seen.add(hash);
|
|
48
|
+
combined.push(hash);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return combined;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Stage 4.5 (PR-1): the coordinate-persistence module.
|
|
55
|
+
*
|
|
56
|
+
* The four coordinate state fields moved here in the state-ownership commit;
|
|
57
|
+
* this commit moves the 39 persistence methods (34 main-cluster + 5 early
|
|
58
|
+
* helpers) with byte-identical bodies — the only edits are the mechanical
|
|
59
|
+
* glue `this._coordinates.<field>` -> `this.<field>` for the owned state and
|
|
60
|
+
* `this.<hostDep>` -> `this.deps.<hostDep>()` for host state (plus the single
|
|
61
|
+
* `_nativeDurableRecoveryReadyForReopen = true` write, which becomes
|
|
62
|
+
* `deps.setDurableRecoveryReadyForReopen(true)`). SharedLog callers now use
|
|
63
|
+
* the coordinator directly; only the three compatibility state accessors
|
|
64
|
+
* remain on the host.
|
|
65
|
+
*
|
|
66
|
+
* Reset discipline is unchanged from the legacy host fields: each open/close
|
|
67
|
+
* site resets exactly the subset of fields it always reset (the resident
|
|
68
|
+
* mirror survives openNativeBackbone, the persistence adapter does not, and
|
|
69
|
+
* the mutation-generation ratchet deliberately survives everything but a
|
|
70
|
+
* fresh instance).
|
|
71
|
+
*/
|
|
72
|
+
export class CoordinatePersistenceCoordinator {
|
|
73
|
+
deps;
|
|
74
|
+
/**
|
|
75
|
+
* Resident mirror of the coordinate rows (hash -> entry or native
|
|
76
|
+
* fields). Established by the native hydration paths; `undefined` means
|
|
77
|
+
* the resident fast path is unavailable.
|
|
78
|
+
*/
|
|
79
|
+
_residentEntryCoordinatesByHash;
|
|
80
|
+
/** The (optional) durable native-backbone coordinate journal adapter. */
|
|
81
|
+
_nativeBackboneCoordinatePersistence;
|
|
82
|
+
// Moved from SharedLog src/index.ts (same name — the sanctioned
|
|
83
|
+
// file-to-file ratchet move; see scripts/ci/check-fence-ratchet.mjs
|
|
84
|
+
// TARGETS). Per-hash mutation-generation ratchet baseline: rollback
|
|
85
|
+
// snapshots capture the generation current at snapshot time and later
|
|
86
|
+
// roll back only while that generation is still current, so a rollback
|
|
87
|
+
// superseded by a newer mutation is a strict no-op. The map deliberately
|
|
88
|
+
// survives open/close cycles of the same instance.
|
|
89
|
+
_nativeCoordinateMutationGenerations;
|
|
90
|
+
/**
|
|
91
|
+
* Wall-clock watermark of the last settled native coordinate journal
|
|
92
|
+
* flush; drives the `flushIntervalMs` on-append flush threshold.
|
|
93
|
+
*/
|
|
94
|
+
_nativeBackboneCoordinateJournalLastFlushMs = 0;
|
|
95
|
+
constructor(deps) {
|
|
96
|
+
this.deps = deps;
|
|
97
|
+
}
|
|
98
|
+
deleteCoordinatesForHashes(hashes, ownershipLifecycleController) {
|
|
99
|
+
if (ownershipLifecycleController) {
|
|
100
|
+
this.deps.throwIfReplicationOwnershipLifecycleInactive(ownershipLifecycleController);
|
|
101
|
+
}
|
|
102
|
+
const values = normalizedHashValues(hashes);
|
|
103
|
+
if (values.length === 0) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
this.forgetCoordinateStateForHashValues(values);
|
|
107
|
+
const coordinateIndex = this.deps.entryCoordinatesIndex();
|
|
108
|
+
if (coordinateIndex.delIdsNoReturn) {
|
|
109
|
+
return mapMaybePromise(coordinateIndex.delIdsNoReturn(values), () => {
|
|
110
|
+
if (ownershipLifecycleController) {
|
|
111
|
+
this.deps.throwIfReplicationOwnershipLifecycleInactive(ownershipLifecycleController);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
if (coordinateIndex.delIds) {
|
|
116
|
+
return mapMaybePromise(coordinateIndex.delIds(values), () => {
|
|
117
|
+
if (ownershipLifecycleController) {
|
|
118
|
+
this.deps.throwIfReplicationOwnershipLifecycleInactive(ownershipLifecycleController);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
return mapMaybePromise(this.deps.entryCoordinatesIndex().del({
|
|
123
|
+
query: values.length === 1
|
|
124
|
+
? { hash: values[0] }
|
|
125
|
+
: new Or(values.map((hash) => new StringMatch({ key: "hash", value: hash }))),
|
|
126
|
+
}), () => {
|
|
127
|
+
if (ownershipLifecycleController) {
|
|
128
|
+
this.deps.throwIfReplicationOwnershipLifecycleInactive(ownershipLifecycleController);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
forgetCoordinateStateForHashes(hashes) {
|
|
133
|
+
const values = normalizedHashValues(hashes);
|
|
134
|
+
if (values.length === 0) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
this.forgetCoordinateStateForHashValues(values);
|
|
138
|
+
}
|
|
139
|
+
forgetCoordinateStateForHashValues(values) {
|
|
140
|
+
this.deps.nativeSharedLogState()?.deleteEntryCoordinatesBatch(values);
|
|
141
|
+
this.deps.nativeBackbone()?.deleteEntryCoordinatesBatch(values);
|
|
142
|
+
this.forgetResidentCoordinateStateForHashValues(values);
|
|
143
|
+
}
|
|
144
|
+
forgetResidentCoordinateStateForHashes(hashes) {
|
|
145
|
+
const values = normalizedHashValues(hashes);
|
|
146
|
+
if (values.length === 0) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
this.forgetResidentCoordinateStateForHashValues(values);
|
|
150
|
+
}
|
|
151
|
+
forgetResidentCoordinateStateForHashValues(values) {
|
|
152
|
+
if (this._residentEntryCoordinatesByHash) {
|
|
153
|
+
for (const hash of values) {
|
|
154
|
+
this._residentEntryCoordinatesByHash.delete(hash);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
async createCoordinates(entry, minReplicas) {
|
|
159
|
+
if (typeof entry !== "number" &&
|
|
160
|
+
typeof entry !== "bigint" &&
|
|
161
|
+
this.deps.canPlanNativeHashGid(entry)) {
|
|
162
|
+
const nativeCoordinates = (this.deps.nativeBackbone() ?? this.deps.nativeRangePlanner())?.getGidCoordinates(entry.meta.gid, minReplicas);
|
|
163
|
+
if (nativeCoordinates) {
|
|
164
|
+
return nativeCoordinates;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
const cursor = typeof entry === "number" || typeof entry === "bigint"
|
|
168
|
+
? entry
|
|
169
|
+
: await this.deps.domain().fromEntry(entry);
|
|
170
|
+
const nativeGrid = (this.deps.nativeBackbone() ?? this.deps.nativeRangePlanner())?.getGrid(cursor, minReplicas);
|
|
171
|
+
return (nativeGrid ?? this.deps.indexableDomain().numbers.getGrid(cursor, minReplicas));
|
|
172
|
+
}
|
|
173
|
+
async getCoordinates(entry) {
|
|
174
|
+
const nativeCoordinates = (this.deps.nativeBackbone() ?? this.deps.nativeSharedLogState())?.getEntryCoordinates(entry.hash);
|
|
175
|
+
if (nativeCoordinates) {
|
|
176
|
+
return nativeCoordinates;
|
|
177
|
+
}
|
|
178
|
+
const result = await this.deps.entryCoordinatesIndex()
|
|
179
|
+
.iterate({ query: { hash: entry.hash } })
|
|
180
|
+
.all();
|
|
181
|
+
return result[0].value.coordinates;
|
|
182
|
+
}
|
|
183
|
+
getNativeLogEntryMetadataBatch(hashes) {
|
|
184
|
+
const normalized = [...hashes];
|
|
185
|
+
if (normalized.length === 0) {
|
|
186
|
+
return [];
|
|
187
|
+
}
|
|
188
|
+
const backboneMetadata = this.deps.nativeBackbone()?.graph.entryMetadataHintsBatch(normalized) ??
|
|
189
|
+
this.deps.nativeBackbone()?.graph.entryMetadataBatch(normalized);
|
|
190
|
+
if (backboneMetadata?.every((entry) => entry != null)) {
|
|
191
|
+
return backboneMetadata;
|
|
192
|
+
}
|
|
193
|
+
const indexMetadata = this.deps.log().entryIndex.getNativeEntryMetadataHintsBatch(normalized) ??
|
|
194
|
+
this.deps.log().entryIndex.getNativeEntryMetadataBatch(normalized);
|
|
195
|
+
if (!backboneMetadata) {
|
|
196
|
+
return indexMetadata;
|
|
197
|
+
}
|
|
198
|
+
if (!indexMetadata) {
|
|
199
|
+
return backboneMetadata;
|
|
200
|
+
}
|
|
201
|
+
return backboneMetadata.map((entry, index) => entry ?? indexMetadata[index]);
|
|
202
|
+
}
|
|
203
|
+
createReusableReceiveCoordinatePlans(receiveGroups, options) {
|
|
204
|
+
const reusablePlans = new Map();
|
|
205
|
+
if (this.deps.timeUntilRoleMaturity() > 0 && !options?.allowRoleAgeZeroPlans) {
|
|
206
|
+
return reusablePlans;
|
|
207
|
+
}
|
|
208
|
+
for (const group of receiveGroups) {
|
|
209
|
+
const plan = group.leaderPlan;
|
|
210
|
+
if (!plan) {
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
const replicas = options?.decodedReplicaCounts?.get(group.latestEntry.hash) ??
|
|
214
|
+
decodeReplicas(group.latestEntry).getValue(this.deps.host());
|
|
215
|
+
if (replicas !== group.maxMaxReplicas) {
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
const prepared = this.createCoordinatePersistenceEntryFromLeaderPlan({
|
|
219
|
+
entry: group.latestEntry,
|
|
220
|
+
plan,
|
|
221
|
+
replicas,
|
|
222
|
+
});
|
|
223
|
+
if (!prepared) {
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
reusablePlans.set(group.latestEntry.hash, {
|
|
227
|
+
plan,
|
|
228
|
+
replicas,
|
|
229
|
+
prepared,
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
return reusablePlans;
|
|
233
|
+
}
|
|
234
|
+
createBackboneOnlyReceiveCoordinateBatch(items) {
|
|
235
|
+
if (!this.deps.nativeBackbone() ||
|
|
236
|
+
items.length === 0 ||
|
|
237
|
+
!this.canUseBackboneOnlyCoordinatePersistence()) {
|
|
238
|
+
return undefined;
|
|
239
|
+
}
|
|
240
|
+
const rows = items
|
|
241
|
+
.filter((item) => item.prepared)
|
|
242
|
+
.map((item) => {
|
|
243
|
+
const prepared = item.prepared;
|
|
244
|
+
const deleteHashes = this.deps.getEntryNext(item.entry);
|
|
245
|
+
return {
|
|
246
|
+
item,
|
|
247
|
+
prepared,
|
|
248
|
+
fields: prepared.fields,
|
|
249
|
+
deleteHashes,
|
|
250
|
+
};
|
|
251
|
+
});
|
|
252
|
+
if (rows.length === 0) {
|
|
253
|
+
return undefined;
|
|
254
|
+
}
|
|
255
|
+
return {
|
|
256
|
+
rows,
|
|
257
|
+
rollbackCoordinateEntries: this.snapshotResidentCoordinateEntries(rows.flatMap((row) => [row.item.entry.hash, ...row.deleteHashes])),
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
nativeBackboneReceiveCoordinateRowsToColumns(rows) {
|
|
261
|
+
const hashes = new Array(rows.length);
|
|
262
|
+
const gids = new Array(rows.length);
|
|
263
|
+
const hashNumberValues = new BigUint64Array(rows.length);
|
|
264
|
+
const coordinateCounts = new Uint32Array(rows.length);
|
|
265
|
+
const coordinateValues = new BigUint64Array(rows.reduce((sum, row) => sum + row.fields.coordinates.length, 0));
|
|
266
|
+
const nextHashBatches = new Array(rows.length);
|
|
267
|
+
const assignedToRangeBoundaries = new Uint8Array(rows.length);
|
|
268
|
+
const requestedReplicaValues = new Uint32Array(rows.length);
|
|
269
|
+
let coordinateOffset = 0;
|
|
270
|
+
for (let i = 0; i < rows.length; i++) {
|
|
271
|
+
const { item, prepared, fields, deleteHashes } = rows[i];
|
|
272
|
+
hashes[i] = item.entry.hash;
|
|
273
|
+
gids[i] = fields.gid;
|
|
274
|
+
hashNumberValues[i] =
|
|
275
|
+
typeof fields.hashNumber === "bigint"
|
|
276
|
+
? fields.hashNumber
|
|
277
|
+
: BigInt(fields.hashNumberString ?? fields.hashNumber);
|
|
278
|
+
coordinateCounts[i] = fields.coordinates.length;
|
|
279
|
+
for (const coordinate of fields.coordinates) {
|
|
280
|
+
coordinateValues[coordinateOffset++] =
|
|
281
|
+
typeof coordinate === "bigint" ? coordinate : BigInt(coordinate);
|
|
282
|
+
}
|
|
283
|
+
nextHashBatches[i] = deleteHashes;
|
|
284
|
+
assignedToRangeBoundaries[i] =
|
|
285
|
+
prepared.assignedToRangeBoundary === true ? 1 : 0;
|
|
286
|
+
requestedReplicaValues[i] = item.replicas;
|
|
287
|
+
}
|
|
288
|
+
return {
|
|
289
|
+
hashes,
|
|
290
|
+
gids,
|
|
291
|
+
hashNumberValues,
|
|
292
|
+
coordinateCounts,
|
|
293
|
+
coordinateValues,
|
|
294
|
+
nextHashBatches,
|
|
295
|
+
assignedToRangeBoundaries,
|
|
296
|
+
requestedReplicaValues,
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
async finishBackboneOnlyReceiveCoordinateBatch(batch, profile) {
|
|
300
|
+
const mirrorStartedAt = syncProfileStart(profile);
|
|
301
|
+
const persistedHashes = new Set();
|
|
302
|
+
const coordinateToHashRows = [];
|
|
303
|
+
let deleteCount = 0;
|
|
304
|
+
for (const { item, prepared, fields, deleteHashes } of batch.rows) {
|
|
305
|
+
persistedHashes.add(item.entry.hash);
|
|
306
|
+
this._residentEntryCoordinatesByHash?.set(item.entry.hash, prepared.coordinateEntry ?? fields);
|
|
307
|
+
for (const deletedHash of deleteHashes) {
|
|
308
|
+
this._residentEntryCoordinatesByHash?.delete(deletedHash);
|
|
309
|
+
deleteCount++;
|
|
310
|
+
}
|
|
311
|
+
for (const coordinate of item.coordinates) {
|
|
312
|
+
coordinateToHashRows.push([coordinate, item.entry.hash]);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
this.deps.coordinateToHash().addMany(coordinateToHashRows);
|
|
316
|
+
emitSyncProfileDuration(profile, mirrorStartedAt, {
|
|
317
|
+
name: "sharedLog.receive.coordinateResidentMirror",
|
|
318
|
+
component: "shared-log",
|
|
319
|
+
entries: batch.rows.length,
|
|
320
|
+
count: coordinateToHashRows.length,
|
|
321
|
+
messages: 1,
|
|
322
|
+
details: { deletes: deleteCount },
|
|
323
|
+
});
|
|
324
|
+
const flushStartedAt = syncProfileStart(profile);
|
|
325
|
+
const flushed = this.flushNativeBackboneCoordinateJournalOnAppend();
|
|
326
|
+
if (isPromiseLike(flushed)) {
|
|
327
|
+
await flushed;
|
|
328
|
+
}
|
|
329
|
+
emitSyncProfileDuration(profile, flushStartedAt, {
|
|
330
|
+
name: "sharedLog.receive.coordinateJournalFlush",
|
|
331
|
+
component: "shared-log",
|
|
332
|
+
entries: batch.rows.length,
|
|
333
|
+
messages: 1,
|
|
334
|
+
});
|
|
335
|
+
return persistedHashes;
|
|
336
|
+
}
|
|
337
|
+
rollbackBackboneOnlyReceiveCoordinateBatch(batch) {
|
|
338
|
+
for (const { item } of batch.rows) {
|
|
339
|
+
this.rollbackNativeBackboneCoordinateAppend(item.entry.hash, batch.rollbackCoordinateEntries);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
async persistBackboneOnlyReceiveCoordinateBatch(items) {
|
|
343
|
+
const backbone = this.deps.nativeBackbone();
|
|
344
|
+
const batch = this.createBackboneOnlyReceiveCoordinateBatch(items);
|
|
345
|
+
if (!backbone || !batch) {
|
|
346
|
+
return undefined;
|
|
347
|
+
}
|
|
348
|
+
try {
|
|
349
|
+
backbone.commitEntryCoordinatesColumnsBatch(this.nativeBackboneReceiveCoordinateRowsToColumns(batch.rows));
|
|
350
|
+
return await this.finishBackboneOnlyReceiveCoordinateBatch(batch);
|
|
351
|
+
}
|
|
352
|
+
catch (error) {
|
|
353
|
+
this.rollbackBackboneOnlyReceiveCoordinateBatch(batch);
|
|
354
|
+
throw error;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
emitNativeBackboneRawCommitProfile(profile, nativeProfile, entries, verifyCount) {
|
|
358
|
+
if (!profile || !nativeProfile) {
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
const events = [
|
|
362
|
+
[
|
|
363
|
+
"sharedLog.receive.nativeRawCommit.pendingCheck",
|
|
364
|
+
nativeProfile.nativeBackboneRawReceivePendingCheckMs,
|
|
365
|
+
],
|
|
366
|
+
[
|
|
367
|
+
"sharedLog.receive.nativeRawCommit.verify",
|
|
368
|
+
nativeProfile.nativeBackboneRawReceiveVerifyMs,
|
|
369
|
+
verifyCount,
|
|
370
|
+
],
|
|
371
|
+
[
|
|
372
|
+
"sharedLog.receive.nativeRawCommit.verifyStatus",
|
|
373
|
+
nativeProfile.nativeBackboneRawReceiveVerifyStatusMs,
|
|
374
|
+
],
|
|
375
|
+
[
|
|
376
|
+
"sharedLog.receive.nativeRawCommit.joinPlan",
|
|
377
|
+
nativeProfile.nativeBackboneRawReceiveJoinPlanMs,
|
|
378
|
+
],
|
|
379
|
+
[
|
|
380
|
+
"sharedLog.receive.nativeRawCommit.removePending",
|
|
381
|
+
nativeProfile.nativeBackboneRawReceiveRemoveMs,
|
|
382
|
+
],
|
|
383
|
+
[
|
|
384
|
+
"sharedLog.receive.nativeRawCommit.blockPut",
|
|
385
|
+
nativeProfile.nativeBackboneRawReceiveBlockPutMs,
|
|
386
|
+
],
|
|
387
|
+
[
|
|
388
|
+
"sharedLog.receive.nativeRawCommit.graphPut",
|
|
389
|
+
nativeProfile.nativeBackboneRawReceiveGraphPutMs,
|
|
390
|
+
],
|
|
391
|
+
[
|
|
392
|
+
"sharedLog.receive.nativeRawCommit.coordinateCommit",
|
|
393
|
+
nativeProfile.nativeBackboneRawReceiveCoordinateCommitMs,
|
|
394
|
+
],
|
|
395
|
+
];
|
|
396
|
+
for (const [name, durationMs, count] of events) {
|
|
397
|
+
if (durationMs > 0) {
|
|
398
|
+
emitSyncProfileEvent(profile, {
|
|
399
|
+
name,
|
|
400
|
+
component: "shared-log",
|
|
401
|
+
durationMs,
|
|
402
|
+
entries,
|
|
403
|
+
count,
|
|
404
|
+
messages: 1,
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
createNativeBackbonePreparedJoinCommit(coordinateBatch, onCoordinatesCommitted, verifyHashes, verifyAllHashes = false, profile, onPreparedEntriesCommitted) {
|
|
410
|
+
const backbone = this.deps.nativeBackbone();
|
|
411
|
+
if (!backbone ||
|
|
412
|
+
this.deps.remoteBlocks()?.localStore !== backbone.blocks ||
|
|
413
|
+
(verifyHashes &&
|
|
414
|
+
verifyHashes.length > 0 &&
|
|
415
|
+
!backbone.graph.commitVerifiedPreparedRawReceiveJoinBatch)) {
|
|
416
|
+
return undefined;
|
|
417
|
+
}
|
|
418
|
+
return ({ entries, hashes, headFlags, headFlagsBytes, trustedMissing, validatePlan, }) => {
|
|
419
|
+
this.deps.throwIfReplicationOwnershipPoisoned();
|
|
420
|
+
if (!trustedMissing || entries.length === 0) {
|
|
421
|
+
return false;
|
|
422
|
+
}
|
|
423
|
+
const coordinateColumns = coordinateBatch && coordinateBatch.rows.length > 0
|
|
424
|
+
? this.nativeBackboneReceiveCoordinateRowsToColumns(coordinateBatch.rows)
|
|
425
|
+
: undefined;
|
|
426
|
+
if (validatePlan) {
|
|
427
|
+
const verifiedCommitStartedAt = syncProfileStart(profile);
|
|
428
|
+
const profileNativeBackbone = !!profile &&
|
|
429
|
+
!!backbone.resetAppendProfile &&
|
|
430
|
+
!!backbone.setAppendProfileEnabled &&
|
|
431
|
+
!!backbone.appendProfile;
|
|
432
|
+
if (profileNativeBackbone) {
|
|
433
|
+
backbone.resetAppendProfile();
|
|
434
|
+
backbone.setAppendProfileEnabled(true);
|
|
435
|
+
}
|
|
436
|
+
let committed;
|
|
437
|
+
try {
|
|
438
|
+
if (verifyHashes && verifyHashes.length > 0) {
|
|
439
|
+
if (verifyAllHashes) {
|
|
440
|
+
committed =
|
|
441
|
+
backbone.graph.commitVerifiedAllPreparedRawReceiveJoinBatch?.(hashes, headFlagsBytes, coordinateColumns);
|
|
442
|
+
}
|
|
443
|
+
committed ??=
|
|
444
|
+
backbone.graph.commitVerifiedPreparedRawReceiveJoinBatch?.(hashes, headFlagsBytes, verifyHashes, coordinateColumns);
|
|
445
|
+
}
|
|
446
|
+
else {
|
|
447
|
+
committed = backbone.graph.commitPreparedRawReceiveJoinBatch?.(hashes, headFlagsBytes, coordinateColumns);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
finally {
|
|
451
|
+
if (profileNativeBackbone) {
|
|
452
|
+
backbone.setAppendProfileEnabled(false);
|
|
453
|
+
this.emitNativeBackboneRawCommitProfile(profile, backbone.appendProfile(), entries.length, verifyHashes?.length ?? 0);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
if (verifyHashes && verifyHashes.length > 0 && profile) {
|
|
457
|
+
emitSyncProfileDuration(profile, verifiedCommitStartedAt, {
|
|
458
|
+
name: "sharedLog.receive.nativeVerifiedCommit",
|
|
459
|
+
component: "shared-log",
|
|
460
|
+
entries: entries.length,
|
|
461
|
+
count: verifyHashes.length,
|
|
462
|
+
messages: 1,
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
if (committed === true) {
|
|
466
|
+
onPreparedEntriesCommitted?.(hashes);
|
|
467
|
+
if (coordinateBatch) {
|
|
468
|
+
onCoordinatesCommitted?.(coordinateBatch);
|
|
469
|
+
}
|
|
470
|
+
return true;
|
|
471
|
+
}
|
|
472
|
+
if (committed === false) {
|
|
473
|
+
backbone.graph.clearPreparedRawReceiveEntries?.(hashes);
|
|
474
|
+
return false;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
if (backbone.graph.commitPreparedRawReceiveBatch(hashes, headFlagsBytes, coordinateColumns)) {
|
|
478
|
+
onPreparedEntriesCommitted?.(hashes);
|
|
479
|
+
if (coordinateBatch) {
|
|
480
|
+
onCoordinatesCommitted?.(coordinateBatch);
|
|
481
|
+
}
|
|
482
|
+
return true;
|
|
483
|
+
}
|
|
484
|
+
const commitEntries = new Array(entries.length);
|
|
485
|
+
for (let i = 0; i < entries.length; i++) {
|
|
486
|
+
const entry = entries[i];
|
|
487
|
+
if (!entry.bytes ||
|
|
488
|
+
!entry.nativeEntry ||
|
|
489
|
+
entry.meta.type !== EntryType.APPEND) {
|
|
490
|
+
return false;
|
|
491
|
+
}
|
|
492
|
+
commitEntries[i] = {
|
|
493
|
+
...entry.nativeEntry,
|
|
494
|
+
head: headFlags[i] ?? true,
|
|
495
|
+
bytes: entry.bytes,
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
if (coordinateBatch && coordinateBatch.rows.length > 0) {
|
|
499
|
+
backbone.graph.commitBlocksGraphAndCoordinatesBatch(commitEntries, coordinateColumns);
|
|
500
|
+
onCoordinatesCommitted?.(coordinateBatch);
|
|
501
|
+
}
|
|
502
|
+
else {
|
|
503
|
+
backbone.graph.commitBlocksAndGraphBatch(commitEntries);
|
|
504
|
+
}
|
|
505
|
+
onPreparedEntriesCommitted?.(hashes);
|
|
506
|
+
return true;
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
createCoordinatePersistenceEntryFromLeaderPlan(properties) {
|
|
510
|
+
const assignedToRangeBoundary = properties.plan.assignedToRangeBoundary ??
|
|
511
|
+
shouldAssignToRangeBoundary(properties.plan.leaders, properties.replicas);
|
|
512
|
+
const hashNumber = this.deps.getEntryHashNumber(properties.entry);
|
|
513
|
+
const metaBytes = properties.entry.getMetaBytes?.();
|
|
514
|
+
if (metaBytes) {
|
|
515
|
+
const rawTimestamp = properties.entry instanceof Entry
|
|
516
|
+
? getPreparedRawExchangeTimestamp(properties.entry)
|
|
517
|
+
: undefined;
|
|
518
|
+
const wallTime = rawTimestamp?.wallTime ??
|
|
519
|
+
properties.entry.meta.clock.timestamp.wallTime;
|
|
520
|
+
return {
|
|
521
|
+
assignedToRangeBoundary,
|
|
522
|
+
fields: {
|
|
523
|
+
hash: properties.entry.hash,
|
|
524
|
+
hashNumber,
|
|
525
|
+
hashNumberString: hashNumber.toString(),
|
|
526
|
+
gid: this.deps.getEntryGid(properties.entry),
|
|
527
|
+
coordinates: properties.plan.coordinates,
|
|
528
|
+
coordinateStrings: properties.plan.coordinateStrings ??
|
|
529
|
+
properties.plan.coordinates.map((coordinate) => coordinate.toString()),
|
|
530
|
+
wallTime,
|
|
531
|
+
wallTimeString: wallTime.toString(),
|
|
532
|
+
assignedToRangeBoundary,
|
|
533
|
+
metaBytes,
|
|
534
|
+
},
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
return this.createCoordinatePersistenceEntry({
|
|
538
|
+
coordinates: properties.plan.coordinates,
|
|
539
|
+
entry: properties.entry,
|
|
540
|
+
leaders: properties.plan.leaders,
|
|
541
|
+
replicas: properties.replicas,
|
|
542
|
+
assignedToRangeBoundary,
|
|
543
|
+
hashNumber,
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
createCoordinatePersistenceEntry(properties) {
|
|
547
|
+
const assignedToRangeBoundary = properties.assignedToRangeBoundary ??
|
|
548
|
+
shouldAssignToRangeBoundary(properties.leaders, properties.replicas);
|
|
549
|
+
if (properties.prev &&
|
|
550
|
+
properties.prev.assignedToRangeBoundary === assignedToRangeBoundary) {
|
|
551
|
+
return false;
|
|
552
|
+
}
|
|
553
|
+
const metaBytes = properties.entry.getMetaBytes?.();
|
|
554
|
+
const coordinateEntry = new (this.deps.indexableDomain().constructorEntry)({
|
|
555
|
+
assignedToRangeBoundary,
|
|
556
|
+
coordinates: properties.coordinates,
|
|
557
|
+
meta: properties.entry.meta,
|
|
558
|
+
metaBytes,
|
|
559
|
+
hash: properties.entry.hash,
|
|
560
|
+
hashNumber: properties.hashNumber ?? this.deps.getEntryHashNumber(properties.entry),
|
|
561
|
+
});
|
|
562
|
+
return {
|
|
563
|
+
coordinateEntry,
|
|
564
|
+
assignedToRangeBoundary,
|
|
565
|
+
fields: {
|
|
566
|
+
hash: coordinateEntry.hash,
|
|
567
|
+
hashNumber: coordinateEntry.hashNumber,
|
|
568
|
+
gid: coordinateEntry.gid,
|
|
569
|
+
coordinates: coordinateEntry.coordinates,
|
|
570
|
+
wallTime: coordinateEntry.wallTime,
|
|
571
|
+
assignedToRangeBoundary: coordinateEntry.assignedToRangeBoundary,
|
|
572
|
+
metaBytes: coordinateEntry.getMetaBytes(),
|
|
573
|
+
},
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
createCoordinatePersistenceEntryFromNativePlan(properties) {
|
|
577
|
+
if (properties.plan.hash !== properties.entry.hash ||
|
|
578
|
+
properties.plan.gid !== this.deps.getEntryGid(properties.entry)) {
|
|
579
|
+
return false;
|
|
580
|
+
}
|
|
581
|
+
const assignedToRangeBoundary = properties.plan.assignedToRangeBoundary;
|
|
582
|
+
if (properties.prev &&
|
|
583
|
+
properties.prev.assignedToRangeBoundary === assignedToRangeBoundary) {
|
|
584
|
+
return false;
|
|
585
|
+
}
|
|
586
|
+
const coordinates = properties.plan.coordinates;
|
|
587
|
+
const hashNumber = properties.plan.hashNumber;
|
|
588
|
+
const metaBytes = properties.entry.getMetaBytes?.();
|
|
589
|
+
if (metaBytes) {
|
|
590
|
+
const rawTimestamp = properties.entry instanceof Entry
|
|
591
|
+
? getPreparedRawExchangeTimestamp(properties.entry)
|
|
592
|
+
: undefined;
|
|
593
|
+
const wallTime = rawTimestamp?.wallTime ??
|
|
594
|
+
properties.entry.meta.clock.timestamp.wallTime;
|
|
595
|
+
return {
|
|
596
|
+
assignedToRangeBoundary,
|
|
597
|
+
fields: {
|
|
598
|
+
hash: properties.plan.hash,
|
|
599
|
+
hashNumber,
|
|
600
|
+
hashNumberString: properties.plan.hashNumberString,
|
|
601
|
+
gid: properties.plan.gid,
|
|
602
|
+
coordinates,
|
|
603
|
+
coordinateStrings: properties.plan.coordinateStrings,
|
|
604
|
+
wallTime,
|
|
605
|
+
wallTimeString: wallTime.toString(),
|
|
606
|
+
assignedToRangeBoundary,
|
|
607
|
+
metaBytes,
|
|
608
|
+
},
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
const entryMeta = properties.entry.meta;
|
|
612
|
+
const coordinateEntry = new (this.deps.indexableDomain().constructorEntry)({
|
|
613
|
+
assignedToRangeBoundary,
|
|
614
|
+
coordinates,
|
|
615
|
+
meta: entryMeta,
|
|
616
|
+
hash: properties.plan.hash,
|
|
617
|
+
hashNumber,
|
|
618
|
+
});
|
|
619
|
+
return {
|
|
620
|
+
coordinateEntry,
|
|
621
|
+
assignedToRangeBoundary,
|
|
622
|
+
fields: {
|
|
623
|
+
hash: properties.plan.hash,
|
|
624
|
+
hashNumber,
|
|
625
|
+
hashNumberString: properties.plan.hashNumberString,
|
|
626
|
+
gid: properties.plan.gid,
|
|
627
|
+
coordinates,
|
|
628
|
+
coordinateStrings: properties.plan.coordinateStrings,
|
|
629
|
+
wallTime: coordinateEntry.wallTime,
|
|
630
|
+
wallTimeString: coordinateEntry.wallTime.toString(),
|
|
631
|
+
assignedToRangeBoundary,
|
|
632
|
+
metaBytes: coordinateEntry.getMetaBytes(),
|
|
633
|
+
},
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
createCoordinateEntryFromNativeFields(fields) {
|
|
637
|
+
return new (this.deps.indexableDomain().constructorEntry)({
|
|
638
|
+
assignedToRangeBoundary: fields.assignedToRangeBoundary,
|
|
639
|
+
coordinates: fields.coordinates,
|
|
640
|
+
metaBytes: fields.metaBytes,
|
|
641
|
+
gid: fields.gid,
|
|
642
|
+
wallTime: fields.wallTime,
|
|
643
|
+
hash: fields.hash,
|
|
644
|
+
hashNumber: fields.hashNumber,
|
|
645
|
+
});
|
|
646
|
+
}
|
|
647
|
+
materializePreparedCoordinateEntry(prepared) {
|
|
648
|
+
return (prepared.coordinateEntry ??=
|
|
649
|
+
this.createCoordinateEntryFromNativeFields(prepared.fields));
|
|
650
|
+
}
|
|
651
|
+
materializeResidentCoordinateEntry(entry) {
|
|
652
|
+
return isEntryReplicated(entry)
|
|
653
|
+
? entry
|
|
654
|
+
: this.createCoordinateEntryFromNativeFields(entry);
|
|
655
|
+
}
|
|
656
|
+
materializeRepairDispatchEntries(entries) {
|
|
657
|
+
const materialized = new Map();
|
|
658
|
+
for (const [hash, entry] of entries) {
|
|
659
|
+
materialized.set(hash, this.materializeResidentCoordinateEntry(entry));
|
|
660
|
+
}
|
|
661
|
+
return materialized;
|
|
662
|
+
}
|
|
663
|
+
snapshotResidentCoordinateEntries(hashes) {
|
|
664
|
+
const uniqueHashes = new Set([...hashes].filter(Boolean));
|
|
665
|
+
if (uniqueHashes.size === 0) {
|
|
666
|
+
return undefined;
|
|
667
|
+
}
|
|
668
|
+
const entries = new Map();
|
|
669
|
+
const generations = new Map();
|
|
670
|
+
const mutationGenerations = (this._nativeCoordinateMutationGenerations ??=
|
|
671
|
+
new Map());
|
|
672
|
+
for (const hash of uniqueHashes) {
|
|
673
|
+
const generation = (mutationGenerations.get(hash) ?? 0) + 1;
|
|
674
|
+
mutationGenerations.set(hash, generation);
|
|
675
|
+
generations.set(hash, generation);
|
|
676
|
+
const entry = this._residentEntryCoordinatesByHash?.get(hash);
|
|
677
|
+
if (entry) {
|
|
678
|
+
entries.set(hash, entry);
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
return { hashes: uniqueHashes, entries, generations };
|
|
682
|
+
}
|
|
683
|
+
rollbackNativeBackboneCoordinateAppend(appendHash, rollback) {
|
|
684
|
+
const backbone = this.deps.nativeBackbone();
|
|
685
|
+
if (!backbone) {
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
const hashes = rollback?.hashes ?? new Set([appendHash]);
|
|
689
|
+
const mutationGenerations = (this._nativeCoordinateMutationGenerations ??=
|
|
690
|
+
new Map());
|
|
691
|
+
for (const hash of hashes) {
|
|
692
|
+
const expectedGeneration = rollback?.generations.get(hash);
|
|
693
|
+
if (expectedGeneration !== undefined &&
|
|
694
|
+
mutationGenerations.get(hash) !== expectedGeneration) {
|
|
695
|
+
continue;
|
|
696
|
+
}
|
|
697
|
+
backbone.deleteEntryCoordinates(hash);
|
|
698
|
+
this.deps.nativeSharedLogState()?.deleteEntryCoordinates(hash);
|
|
699
|
+
this._residentEntryCoordinatesByHash?.delete(hash);
|
|
700
|
+
const entry = rollback?.entries.get(hash);
|
|
701
|
+
if (!entry) {
|
|
702
|
+
continue;
|
|
703
|
+
}
|
|
704
|
+
const fields = isEntryReplicated(entry)
|
|
705
|
+
? {
|
|
706
|
+
hash: entry.hash,
|
|
707
|
+
gid: entry.gid,
|
|
708
|
+
coordinates: entry.coordinates,
|
|
709
|
+
assignedToRangeBoundary: entry.assignedToRangeBoundary,
|
|
710
|
+
hashNumber: entry.hashNumber,
|
|
711
|
+
}
|
|
712
|
+
: entry;
|
|
713
|
+
const requestedReplicas = isEntryReplicated(entry)
|
|
714
|
+
? decodeReplicas(entry).getValue(this.deps.host())
|
|
715
|
+
: fields.coordinates.length;
|
|
716
|
+
backbone.putEntryCoordinates(fields.hash, fields.gid, fields.coordinates, fields.assignedToRangeBoundary, requestedReplicas, fields.hashNumber);
|
|
717
|
+
this.deps.nativeSharedLogState()?.putEntryCoordinates(fields.hash, fields.gid, fields.coordinates, fields.assignedToRangeBoundary, requestedReplicas, fields.hashNumber);
|
|
718
|
+
this._residentEntryCoordinatesByHash?.set(hash, entry);
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
async rollbackNativeBackboneCoordinateAppendDurably(appendHash, rollback) {
|
|
722
|
+
this.rollbackNativeBackboneCoordinateAppend(appendHash, rollback);
|
|
723
|
+
const coordinateIndex = this.deps.entryCoordinatesIndex();
|
|
724
|
+
const hashes = rollback?.hashes ?? new Set([appendHash]);
|
|
725
|
+
const mutationGenerations = (this._nativeCoordinateMutationGenerations ??=
|
|
726
|
+
new Map());
|
|
727
|
+
for (const hash of hashes) {
|
|
728
|
+
const expectedGeneration = rollback?.generations.get(hash);
|
|
729
|
+
if (expectedGeneration !== undefined &&
|
|
730
|
+
mutationGenerations.get(hash) !== expectedGeneration) {
|
|
731
|
+
continue;
|
|
732
|
+
}
|
|
733
|
+
const previous = rollback?.entries.get(hash);
|
|
734
|
+
if (previous) {
|
|
735
|
+
await coordinateIndex.put(this.materializeResidentCoordinateEntry(previous));
|
|
736
|
+
}
|
|
737
|
+
else if (coordinateIndex.delIds) {
|
|
738
|
+
await coordinateIndex.delIds([hash]);
|
|
739
|
+
}
|
|
740
|
+
else if (coordinateIndex.delIdsNoReturn) {
|
|
741
|
+
await coordinateIndex.delIdsNoReturn([hash]);
|
|
742
|
+
}
|
|
743
|
+
else {
|
|
744
|
+
await coordinateIndex.del({ query: { hash } });
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
const flushed = this.flushNativeBackboneCoordinateJournal();
|
|
748
|
+
if (isPromiseLike(flushed)) {
|
|
749
|
+
await flushed;
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
persistPreparedCoordinate(properties, ownershipLifecycleController = this.deps.captureReplicationOwnershipLifecycle()) {
|
|
753
|
+
this.deps.throwIfReplicationOwnershipLifecycleInactive(ownershipLifecycleController);
|
|
754
|
+
const { assignedToRangeBoundary, fields } = properties.prepared;
|
|
755
|
+
const deleteHashes = combineCoordinateDeleteHashes(properties.nextHashes, properties.deleteHashes);
|
|
756
|
+
const coordinateIndex = this.deps.entryCoordinatesIndex();
|
|
757
|
+
let deleteNextOptions;
|
|
758
|
+
let putResult;
|
|
759
|
+
if (coordinateIndex.putSharedLogCoordinateFieldsAndDeleteHashesNoReturn) {
|
|
760
|
+
putResult =
|
|
761
|
+
coordinateIndex.putSharedLogCoordinateFieldsAndDeleteHashesNoReturn(fields, deleteHashes);
|
|
762
|
+
}
|
|
763
|
+
else if (coordinateIndex.putSharedLogCoordinateFieldsAndDeleteHashes) {
|
|
764
|
+
putResult = coordinateIndex.putSharedLogCoordinateFieldsAndDeleteHashes(fields, deleteHashes);
|
|
765
|
+
}
|
|
766
|
+
else if (coordinateIndex.putSharedLogCoordinateFieldsAndDeleteIds) {
|
|
767
|
+
putResult = coordinateIndex.putSharedLogCoordinateFieldsAndDeleteIds(fields, deleteHashes, toId(fields.hash));
|
|
768
|
+
}
|
|
769
|
+
else if (coordinateIndex.putSharedLogCoordinateAndDeleteIds) {
|
|
770
|
+
const coordinateEntry = this.materializePreparedCoordinateEntry(properties.prepared);
|
|
771
|
+
putResult = coordinateIndex.putSharedLogCoordinateAndDeleteIds(coordinateEntry, fields, deleteHashes, toId(fields.hash));
|
|
772
|
+
}
|
|
773
|
+
else if (deleteHashes.length > 0 && coordinateIndex.putAndDeleteIds) {
|
|
774
|
+
const coordinateEntry = this.materializePreparedCoordinateEntry(properties.prepared);
|
|
775
|
+
putResult = coordinateIndex.putAndDeleteIds(coordinateEntry, deleteHashes);
|
|
776
|
+
}
|
|
777
|
+
else {
|
|
778
|
+
const coordinateEntry = this.materializePreparedCoordinateEntry(properties.prepared);
|
|
779
|
+
deleteNextOptions =
|
|
780
|
+
deleteHashes.length === 0
|
|
781
|
+
? undefined
|
|
782
|
+
: deleteHashes.length === 1
|
|
783
|
+
? { query: { hash: deleteHashes[0] } }
|
|
784
|
+
: {
|
|
785
|
+
query: new Or(deleteHashes.map((x) => new StringMatch({ key: "hash", value: x }))),
|
|
786
|
+
};
|
|
787
|
+
if (deleteNextOptions && coordinateIndex.putAndDelete) {
|
|
788
|
+
putResult = coordinateIndex.putAndDelete(coordinateEntry, deleteNextOptions);
|
|
789
|
+
}
|
|
790
|
+
else {
|
|
791
|
+
putResult = this.deps.entryCoordinatesIndex().put(coordinateEntry);
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
const finish = () => {
|
|
795
|
+
this.deps.throwIfReplicationOwnershipLifecycleInactive(ownershipLifecycleController);
|
|
796
|
+
const nativeDeleteHashes = combineCoordinateDeleteHashes(properties.nextHashes, properties.deleteHashes);
|
|
797
|
+
if (properties.commitNative !== false) {
|
|
798
|
+
this.deps.nativeSharedLogState()?.commitEntryCoordinates(properties.hash, fields.gid, properties.coordinates, nativeDeleteHashes, assignedToRangeBoundary, properties.replicas, fields.hashNumber);
|
|
799
|
+
}
|
|
800
|
+
if (properties.commitNativeBackbone !== false) {
|
|
801
|
+
this.deps.nativeBackbone()?.commitEntryCoordinates(properties.hash, fields.gid, properties.coordinates, nativeDeleteHashes, assignedToRangeBoundary, properties.replicas, fields.hashNumber);
|
|
802
|
+
}
|
|
803
|
+
if (this._residentEntryCoordinatesByHash) {
|
|
804
|
+
this._residentEntryCoordinatesByHash.set(properties.hash, properties.prepared.coordinateEntry ?? fields);
|
|
805
|
+
for (const nextHash of nativeDeleteHashes) {
|
|
806
|
+
this._residentEntryCoordinatesByHash.delete(nextHash);
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
for (const coordinate of properties.coordinates) {
|
|
810
|
+
this.deps.coordinateToHash().add(coordinate, properties.hash);
|
|
811
|
+
}
|
|
812
|
+
if (deleteNextOptions && !coordinateIndex.putAndDelete) {
|
|
813
|
+
return mapMaybePromise(this.deps.entryCoordinatesIndex().del(deleteNextOptions), () => true);
|
|
814
|
+
}
|
|
815
|
+
return true;
|
|
816
|
+
};
|
|
817
|
+
return mapMaybePromise(putResult, finish);
|
|
818
|
+
}
|
|
819
|
+
persistPreparedCoordinateNativeTransaction(properties, ownershipLifecycleController = this.deps.captureReplicationOwnershipLifecycle()) {
|
|
820
|
+
this.deps.throwIfReplicationOwnershipLifecycleInactive(ownershipLifecycleController);
|
|
821
|
+
const { fields } = properties.prepared;
|
|
822
|
+
const putNative = properties.coordinateIndex
|
|
823
|
+
.putSharedLogCoordinateFieldsEncodedAndDeleteHashesNoReturn ??
|
|
824
|
+
properties.coordinateIndex
|
|
825
|
+
.putSharedLogCoordinateFieldsAndDeleteHashesNoReturn;
|
|
826
|
+
if (!putNative) {
|
|
827
|
+
return false;
|
|
828
|
+
}
|
|
829
|
+
const putResult = putNative.call(properties.coordinateIndex, fields, combineCoordinateDeleteHashes(properties.nextHashes, properties.deleteHashes));
|
|
830
|
+
const finish = () => {
|
|
831
|
+
this.deps.throwIfReplicationOwnershipLifecycleInactive(ownershipLifecycleController);
|
|
832
|
+
const nativeDeleteHashes = combineCoordinateDeleteHashes(properties.nextHashes, properties.deleteHashes);
|
|
833
|
+
if (properties.commitNative !== false) {
|
|
834
|
+
this.deps.nativeSharedLogState()?.commitEntryCoordinates(properties.hash, fields.gid, properties.coordinates, nativeDeleteHashes, properties.prepared.assignedToRangeBoundary, properties.coordinates.length, fields.hashNumber);
|
|
835
|
+
}
|
|
836
|
+
if (properties.commitNativeBackbone !== false) {
|
|
837
|
+
this.deps.nativeBackbone()?.commitEntryCoordinates(properties.hash, fields.gid, properties.coordinates, nativeDeleteHashes, properties.prepared.assignedToRangeBoundary, properties.coordinates.length, fields.hashNumber);
|
|
838
|
+
}
|
|
839
|
+
if (this._residentEntryCoordinatesByHash) {
|
|
840
|
+
this._residentEntryCoordinatesByHash.set(properties.hash, properties.prepared.coordinateEntry ?? fields);
|
|
841
|
+
for (const nextHash of nativeDeleteHashes) {
|
|
842
|
+
this._residentEntryCoordinatesByHash.delete(nextHash);
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
for (const coordinate of properties.coordinates) {
|
|
846
|
+
this.deps.coordinateToHash().add(coordinate, properties.hash);
|
|
847
|
+
}
|
|
848
|
+
return true;
|
|
849
|
+
};
|
|
850
|
+
return mapMaybePromise(putResult, finish);
|
|
851
|
+
}
|
|
852
|
+
persistBackboneCoordinateFieldsNativeTransaction(properties, ownershipLifecycleController = this.deps.captureReplicationOwnershipLifecycle()) {
|
|
853
|
+
this.deps.throwIfReplicationOwnershipLifecycleInactive(ownershipLifecycleController);
|
|
854
|
+
const { fields } = properties;
|
|
855
|
+
const useBackboneOnlyCoordinatePersistence = this.canUseBackboneOnlyCoordinatePersistence();
|
|
856
|
+
const finish = () => {
|
|
857
|
+
this.deps.throwIfReplicationOwnershipLifecycleInactive(ownershipLifecycleController);
|
|
858
|
+
this.deps.nativeSharedLogState()?.commitEntryCoordinates(properties.hash, fields.gid, properties.coordinates, properties.deleteHashes, fields.assignedToRangeBoundary, properties.coordinates.length, fields.hashNumber);
|
|
859
|
+
if (this._residentEntryCoordinatesByHash) {
|
|
860
|
+
this._residentEntryCoordinatesByHash.set(properties.hash, fields);
|
|
861
|
+
for (const deletedHash of properties.deleteHashes) {
|
|
862
|
+
this._residentEntryCoordinatesByHash.delete(deletedHash);
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
for (const coordinate of properties.coordinates) {
|
|
866
|
+
this.deps.coordinateToHash().add(coordinate, properties.hash);
|
|
867
|
+
}
|
|
868
|
+
if (this._nativeBackboneCoordinatePersistence) {
|
|
869
|
+
const flushed = this.flushNativeBackboneCoordinateJournalOnAppend();
|
|
870
|
+
if (isPromiseLike(flushed)) {
|
|
871
|
+
return mapMaybePromise(flushed, () => true);
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
return true;
|
|
875
|
+
};
|
|
876
|
+
if ((properties.skipGenericTransientCoordinateIndex &&
|
|
877
|
+
this.canUseRuntimeOnlyNativeBackboneCoordinates(properties.coordinateIndex)) ||
|
|
878
|
+
useBackboneOnlyCoordinatePersistence) {
|
|
879
|
+
return finish();
|
|
880
|
+
}
|
|
881
|
+
const putNative = properties.coordinateIndex
|
|
882
|
+
.putSharedLogCoordinateFieldsEncodedAndDeleteHashesNoReturn ??
|
|
883
|
+
properties.coordinateIndex
|
|
884
|
+
.putSharedLogCoordinateFieldsAndDeleteHashesNoReturn;
|
|
885
|
+
if (!putNative) {
|
|
886
|
+
return false;
|
|
887
|
+
}
|
|
888
|
+
const putResult = putNative.call(properties.coordinateIndex, fields, properties.deleteHashes);
|
|
889
|
+
return mapMaybePromise(putResult, finish);
|
|
890
|
+
}
|
|
891
|
+
flushNativeBackboneCoordinateJournal() {
|
|
892
|
+
const backbone = this.deps.nativeBackbone();
|
|
893
|
+
const persistence = this._nativeBackboneCoordinatePersistence;
|
|
894
|
+
if (!backbone || !persistence || this.deps.isDropStarted()) {
|
|
895
|
+
return undefined;
|
|
896
|
+
}
|
|
897
|
+
if (backbone.coordinatePendingJournalLength === 0 &&
|
|
898
|
+
backbone.documentPendingJournalLength === 0 &&
|
|
899
|
+
backbone.documentSignerPendingJournalLength === 0) {
|
|
900
|
+
return undefined;
|
|
901
|
+
}
|
|
902
|
+
return mapMaybePromise(persistence.flushJournal(backbone), () => {
|
|
903
|
+
this._nativeBackboneCoordinateJournalLastFlushMs = Date.now();
|
|
904
|
+
return undefined;
|
|
905
|
+
});
|
|
906
|
+
}
|
|
907
|
+
flushNativeBackboneCoordinateJournalOnAppend() {
|
|
908
|
+
const backbone = this.deps.nativeBackbone();
|
|
909
|
+
const persistence = this._nativeBackboneCoordinatePersistence;
|
|
910
|
+
if (!backbone || !persistence || this.deps.isDropStarted()) {
|
|
911
|
+
return undefined;
|
|
912
|
+
}
|
|
913
|
+
if (persistence.flushJournalOnAppend) {
|
|
914
|
+
const flushed = persistence.flushJournalOnAppend(backbone);
|
|
915
|
+
if (!isPromiseLike(flushed)) {
|
|
916
|
+
return undefined;
|
|
917
|
+
}
|
|
918
|
+
return mapMaybePromise(flushed, () => {
|
|
919
|
+
return undefined;
|
|
920
|
+
});
|
|
921
|
+
}
|
|
922
|
+
if (!this.shouldFlushNativeBackboneCoordinateJournalOnAppend()) {
|
|
923
|
+
return undefined;
|
|
924
|
+
}
|
|
925
|
+
return this.flushNativeBackboneCoordinateJournal();
|
|
926
|
+
}
|
|
927
|
+
shouldFlushNativeBackboneCoordinateJournalOnAppend() {
|
|
928
|
+
const persistence = this._nativeBackboneCoordinatePersistence;
|
|
929
|
+
if (!persistence || persistence.flushOnAppend !== false) {
|
|
930
|
+
return true;
|
|
931
|
+
}
|
|
932
|
+
const backbone = this.deps.nativeBackbone();
|
|
933
|
+
if (!backbone || backbone.coordinatePendingJournalLength === 0) {
|
|
934
|
+
return false;
|
|
935
|
+
}
|
|
936
|
+
if (persistence.flushMaxPendingBytes != null &&
|
|
937
|
+
backbone.coordinatePendingJournalByteLength >=
|
|
938
|
+
persistence.flushMaxPendingBytes) {
|
|
939
|
+
return true;
|
|
940
|
+
}
|
|
941
|
+
return (persistence.flushIntervalMs != null &&
|
|
942
|
+
Date.now() - this._nativeBackboneCoordinateJournalLastFlushMs >=
|
|
943
|
+
persistence.flushIntervalMs);
|
|
944
|
+
}
|
|
945
|
+
async closeNativeBackboneCoordinatePersistence() {
|
|
946
|
+
const persistence = this._nativeBackboneCoordinatePersistence;
|
|
947
|
+
if (!persistence) {
|
|
948
|
+
return;
|
|
949
|
+
}
|
|
950
|
+
if (this.deps.isDropStarted()) {
|
|
951
|
+
// `drop()` owns the durable namespace lifecycle. Never flush the live wasm
|
|
952
|
+
// journals or invoke an ordinary custom close after its tombstone/erase has
|
|
953
|
+
// started: a close implementation that rewrites cached state could resurrect
|
|
954
|
+
// files after a successful terminal drop.
|
|
955
|
+
return;
|
|
956
|
+
}
|
|
957
|
+
if (this.deps.getDurableCommitFailure() &&
|
|
958
|
+
!this.deps.isDurableRecoveryReadyForReopen()) {
|
|
959
|
+
// The failed native transaction was never published by the lower log.
|
|
960
|
+
// Its coordinate/document/signer records are still only in the wasm
|
|
961
|
+
// pending journals. Closing without flushing discards that generation;
|
|
962
|
+
// the next backbone hydrates the last acknowledged checkpoint.
|
|
963
|
+
await persistence.close?.();
|
|
964
|
+
this.deps.setDurableRecoveryReadyForReopen(true);
|
|
965
|
+
return;
|
|
966
|
+
}
|
|
967
|
+
await this.flushNativeBackboneCoordinateJournal();
|
|
968
|
+
await persistence.close?.();
|
|
969
|
+
}
|
|
970
|
+
canUseBackboneOnlyCoordinatePersistence() {
|
|
971
|
+
return (!!this._nativeBackboneCoordinatePersistence &&
|
|
972
|
+
this.deps.canUseNativeBackboneResidentCoordinateState());
|
|
973
|
+
}
|
|
974
|
+
canUseNativeBackboneResidentCoordinateState() {
|
|
975
|
+
return (!!this.deps.nativeBackbone() &&
|
|
976
|
+
!!this._residentEntryCoordinatesByHash &&
|
|
977
|
+
!this.deps.hasCustomFindLeaders());
|
|
978
|
+
}
|
|
979
|
+
canUseRuntimeOnlyNativeBackboneCoordinates(coordinateIndex) {
|
|
980
|
+
if (!this.deps.canUseNativeBackboneResidentCoordinateState() ||
|
|
981
|
+
Object.prototype.hasOwnProperty.call(coordinateIndex, "putSharedLogCoordinateFieldsEncodedAndDeleteHashesNoReturn") ||
|
|
982
|
+
Object.prototype.hasOwnProperty.call(coordinateIndex, "putSharedLogCoordinateFieldsAndDeleteHashesNoReturn")) {
|
|
983
|
+
return false;
|
|
984
|
+
}
|
|
985
|
+
const persisted = coordinateIndex.persisted?.();
|
|
986
|
+
return persisted === false;
|
|
987
|
+
}
|
|
988
|
+
async persistCoordinate(properties, ownershipLifecycleController = this.deps.captureReplicationOwnershipLifecycle()) {
|
|
989
|
+
this.deps.throwIfReplicationOwnershipLifecycleInactive(ownershipLifecycleController);
|
|
990
|
+
const prepared = properties.prepared ?? this.createCoordinatePersistenceEntry(properties);
|
|
991
|
+
if (!prepared) {
|
|
992
|
+
return false;
|
|
993
|
+
}
|
|
994
|
+
return this.persistPreparedCoordinate({
|
|
995
|
+
prepared,
|
|
996
|
+
hash: properties.entry.hash,
|
|
997
|
+
nextHashes: properties.nextHashes ?? properties.entry.meta.next,
|
|
998
|
+
coordinates: properties.coordinates,
|
|
999
|
+
replicas: properties.replicas,
|
|
1000
|
+
commitNative: properties.commitNative,
|
|
1001
|
+
commitNativeBackbone: properties.commitNativeBackbone,
|
|
1002
|
+
deleteHashes: properties.deleteHashes,
|
|
1003
|
+
}, ownershipLifecycleController);
|
|
1004
|
+
}
|
|
1005
|
+
async persistCoordinatesBatch(items, ownershipLifecycleController = this.deps.captureReplicationOwnershipLifecycle()) {
|
|
1006
|
+
this.deps.throwIfReplicationOwnershipLifecycleInactive(ownershipLifecycleController);
|
|
1007
|
+
if (items.length === 0) {
|
|
1008
|
+
return [];
|
|
1009
|
+
}
|
|
1010
|
+
const prepared = items.map((item) => ({
|
|
1011
|
+
item,
|
|
1012
|
+
prepared: item.prepared ?? this.createCoordinatePersistenceEntry(item),
|
|
1013
|
+
}));
|
|
1014
|
+
const changed = prepared.filter((entry) => entry.prepared !== false);
|
|
1015
|
+
if (changed.length === 0) {
|
|
1016
|
+
return items.map(() => false);
|
|
1017
|
+
}
|
|
1018
|
+
const coordinateIndex = this.deps.entryCoordinatesIndex();
|
|
1019
|
+
const canUseGenericPutBatch = typeof coordinateIndex.putBatch === "function" &&
|
|
1020
|
+
changed.every(({ item }) => item.entry.meta.next.length === 0);
|
|
1021
|
+
if (coordinateIndex.putSharedLogCoordinateFieldsAndDeleteHashesBatchNoReturn) {
|
|
1022
|
+
await coordinateIndex.putSharedLogCoordinateFieldsAndDeleteHashesBatchNoReturn(changed.map(({ item, prepared }) => ({
|
|
1023
|
+
fields: prepared.fields,
|
|
1024
|
+
deleteHashes: item.entry.meta.next,
|
|
1025
|
+
})));
|
|
1026
|
+
}
|
|
1027
|
+
else if (coordinateIndex.putSharedLogCoordinateFieldsAndDeleteHashesBatch) {
|
|
1028
|
+
await coordinateIndex.putSharedLogCoordinateFieldsAndDeleteHashesBatch(changed.map(({ item, prepared }) => ({
|
|
1029
|
+
fields: prepared.fields,
|
|
1030
|
+
deleteHashes: item.entry.meta.next,
|
|
1031
|
+
})));
|
|
1032
|
+
}
|
|
1033
|
+
else if (coordinateIndex.putSharedLogCoordinateFieldsAndDeleteIdsBatch) {
|
|
1034
|
+
await coordinateIndex.putSharedLogCoordinateFieldsAndDeleteIdsBatch(changed.map(({ item, prepared }) => ({
|
|
1035
|
+
fields: prepared.fields,
|
|
1036
|
+
deleteIds: item.entry.meta.next,
|
|
1037
|
+
id: toId(prepared.fields.hash),
|
|
1038
|
+
})));
|
|
1039
|
+
}
|
|
1040
|
+
else if (coordinateIndex.putSharedLogCoordinatesAndDeleteIdsBatch) {
|
|
1041
|
+
await coordinateIndex.putSharedLogCoordinatesAndDeleteIdsBatch(changed.map(({ item, prepared }) => ({
|
|
1042
|
+
value: this.materializePreparedCoordinateEntry(prepared),
|
|
1043
|
+
fields: prepared.fields,
|
|
1044
|
+
deleteIds: item.entry.meta.next,
|
|
1045
|
+
id: toId(prepared.fields.hash),
|
|
1046
|
+
})));
|
|
1047
|
+
}
|
|
1048
|
+
else if (canUseGenericPutBatch) {
|
|
1049
|
+
await coordinateIndex.putBatch(changed.map(({ prepared }) => this.materializePreparedCoordinateEntry(prepared)));
|
|
1050
|
+
}
|
|
1051
|
+
else {
|
|
1052
|
+
const results = [];
|
|
1053
|
+
for (const item of items) {
|
|
1054
|
+
results.push(await this.persistCoordinate(item, ownershipLifecycleController));
|
|
1055
|
+
this.deps.throwIfReplicationOwnershipLifecycleInactive(ownershipLifecycleController);
|
|
1056
|
+
}
|
|
1057
|
+
return results;
|
|
1058
|
+
}
|
|
1059
|
+
this.deps.throwIfReplicationOwnershipLifecycleInactive(ownershipLifecycleController);
|
|
1060
|
+
const nativeCoordinateCommits = changed.filter(({ item }) => item.commitNative !== false);
|
|
1061
|
+
const nativeSharedLogState = this.deps.nativeSharedLogState();
|
|
1062
|
+
if (nativeCoordinateCommits.length > 0 && nativeSharedLogState) {
|
|
1063
|
+
if (nativeSharedLogState.commitEntryCoordinatesBatch) {
|
|
1064
|
+
nativeSharedLogState.commitEntryCoordinatesBatch(nativeCoordinateCommits.map(({ item, prepared }) => ({
|
|
1065
|
+
hash: item.entry.hash,
|
|
1066
|
+
gid: prepared.fields.gid,
|
|
1067
|
+
coordinates: item.coordinates,
|
|
1068
|
+
nextHashes: item.entry.meta.next,
|
|
1069
|
+
assignedToRangeBoundary: prepared.assignedToRangeBoundary,
|
|
1070
|
+
requestedReplicas: item.replicas,
|
|
1071
|
+
hashNumber: prepared.fields.hashNumber,
|
|
1072
|
+
})));
|
|
1073
|
+
}
|
|
1074
|
+
else {
|
|
1075
|
+
for (const { item, prepared } of nativeCoordinateCommits) {
|
|
1076
|
+
nativeSharedLogState.commitEntryCoordinates(item.entry.hash, prepared.fields.gid, item.coordinates, item.entry.meta.next, prepared.assignedToRangeBoundary, item.replicas, prepared.fields.hashNumber);
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
const nativeBackboneCoordinateCommits = changed.filter(({ item }) => item.commitNativeBackbone !== false);
|
|
1081
|
+
const nativeBackboneForBatch = this.deps.nativeBackbone();
|
|
1082
|
+
if (nativeBackboneCoordinateCommits.length > 0 && nativeBackboneForBatch) {
|
|
1083
|
+
if (nativeBackboneForBatch.commitEntryCoordinatesBatch) {
|
|
1084
|
+
nativeBackboneForBatch.commitEntryCoordinatesBatch(nativeBackboneCoordinateCommits.map(({ item, prepared }) => ({
|
|
1085
|
+
hash: item.entry.hash,
|
|
1086
|
+
gid: prepared.fields.gid,
|
|
1087
|
+
coordinates: item.coordinates,
|
|
1088
|
+
nextHashes: item.entry.meta.next,
|
|
1089
|
+
assignedToRangeBoundary: prepared.assignedToRangeBoundary,
|
|
1090
|
+
requestedReplicas: item.replicas,
|
|
1091
|
+
hashNumber: prepared.fields.hashNumber,
|
|
1092
|
+
})));
|
|
1093
|
+
}
|
|
1094
|
+
else {
|
|
1095
|
+
for (const { item, prepared } of nativeBackboneCoordinateCommits) {
|
|
1096
|
+
nativeBackboneForBatch.commitEntryCoordinates(item.entry.hash, prepared.fields.gid, item.coordinates, item.entry.meta.next, prepared.assignedToRangeBoundary, item.replicas, prepared.fields.hashNumber);
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
for (const { item, prepared } of changed) {
|
|
1101
|
+
if (this._residentEntryCoordinatesByHash) {
|
|
1102
|
+
this._residentEntryCoordinatesByHash.set(item.entry.hash, prepared.coordinateEntry ?? prepared.fields);
|
|
1103
|
+
for (const nextHash of item.entry.meta.next) {
|
|
1104
|
+
this._residentEntryCoordinatesByHash.delete(nextHash);
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
for (const coordinate of item.coordinates) {
|
|
1108
|
+
this.deps.coordinateToHash().add(coordinate, item.entry.hash);
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
const changedHashes = new Set(changed.map(({ prepared }) => prepared.fields.hash));
|
|
1112
|
+
return items.map((item) => changedHashes.has(item.entry.hash));
|
|
1113
|
+
}
|
|
1114
|
+
async deleteCoordinates(properties, ownershipLifecycleController) {
|
|
1115
|
+
if (ownershipLifecycleController) {
|
|
1116
|
+
this.deps.throwIfReplicationOwnershipLifecycleInactive(ownershipLifecycleController);
|
|
1117
|
+
}
|
|
1118
|
+
this.deps.nativeSharedLogState()?.deleteEntryCoordinates(properties.hash);
|
|
1119
|
+
this.deps.nativeBackbone()?.deleteEntryCoordinates(properties.hash);
|
|
1120
|
+
this._residentEntryCoordinatesByHash?.delete(properties.hash);
|
|
1121
|
+
const coordinateIndex = this.deps.entryCoordinatesIndex();
|
|
1122
|
+
if (coordinateIndex.delIds) {
|
|
1123
|
+
await coordinateIndex.delIds([properties.hash]);
|
|
1124
|
+
}
|
|
1125
|
+
else {
|
|
1126
|
+
await this.deps.entryCoordinatesIndex().del({ query: properties });
|
|
1127
|
+
}
|
|
1128
|
+
if (ownershipLifecycleController) {
|
|
1129
|
+
this.deps.throwIfReplicationOwnershipLifecycleInactive(ownershipLifecycleController);
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
//# sourceMappingURL=coordinate-persistence.js.map
|