@ibgib/core-gib 0.1.27 → 0.1.29
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/common/meta-stone/meta-stone-helper.d.mts.map +1 -1
- package/dist/common/meta-stone/meta-stone-helper.mjs +19 -7
- package/dist/common/meta-stone/meta-stone-helper.mjs.map +1 -1
- package/dist/sync/sync-helpers.d.mts +11 -5
- package/dist/sync/sync-helpers.d.mts.map +1 -1
- package/dist/sync/sync-helpers.mjs +33 -9
- package/dist/sync/sync-helpers.mjs.map +1 -1
- package/dist/sync/sync-innerspace-constants.respec.mjs +36 -36
- package/dist/sync/sync-innerspace-constants.respec.mjs.map +1 -1
- package/dist/sync/sync-innerspace-deep-updates.respec.mjs +5 -3
- package/dist/sync/sync-innerspace-deep-updates.respec.mjs.map +1 -1
- package/dist/sync/sync-innerspace-multiple-timelines.respec.mjs +2 -2
- package/dist/sync/sync-innerspace-multiple-timelines.respec.mjs.map +1 -1
- package/dist/sync/sync-innerspace-partial-update.respec.mjs +3 -3
- package/dist/sync/sync-innerspace-partial-update.respec.mjs.map +1 -1
- package/dist/sync/sync-innerspace.respec.mjs +49 -20
- package/dist/sync/sync-innerspace.respec.mjs.map +1 -1
- package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.d.mts +0 -9
- package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.d.mts.map +1 -1
- package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs +13 -42
- package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs.map +1 -1
- package/dist/sync/sync-peer/sync-peer-v1.mjs +2 -2
- package/dist/sync/sync-peer/sync-peer-v1.mjs.map +1 -1
- package/dist/sync/sync-saga-coordinator.d.mts +23 -159
- package/dist/sync/sync-saga-coordinator.d.mts.map +1 -1
- package/dist/sync/sync-saga-coordinator.mjs +508 -172
- package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
- package/dist/sync/sync-saga-message/sync-saga-message-types.d.mts +12 -17
- package/dist/sync/sync-saga-message/sync-saga-message-types.d.mts.map +1 -1
- package/dist/sync/sync-types.d.mts +18 -23
- package/dist/sync/sync-types.d.mts.map +1 -1
- package/dist/sync/sync-types.mjs +15 -21
- package/dist/sync/sync-types.mjs.map +1 -1
- package/package.json +1 -1
- package/src/common/meta-stone/meta-stone-helper.mts +17 -7
- package/src/sync/sync-helpers.mts +36 -13
- package/src/sync/sync-innerspace-constants.respec.mts +39 -39
- package/src/sync/sync-innerspace-deep-updates.respec.mts +6 -6
- package/src/sync/sync-innerspace-multiple-timelines.respec.mts +1 -1
- package/src/sync/sync-innerspace-partial-update.respec.mts +2 -2
- package/src/sync/sync-innerspace.respec.mts +20 -19
- package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mts +11 -58
- package/src/sync/sync-peer/sync-peer-v1.mts +2 -2
- package/src/sync/sync-saga-coordinator.mts +472 -191
- package/src/sync/sync-saga-message/sync-saga-message-types.mts +13 -18
- package/src/sync/sync-types.mts +26 -33
- package/test_output.log +0 -0
- package/tmp.md +170 -62
|
@@ -2,11 +2,12 @@ import { extractErrorMsg, getUUID, // so our timestamp in ticks as a string are
|
|
|
2
2
|
pretty, delay, } from "@ibgib/helper-gib/dist/helpers/utils-helper.mjs";
|
|
3
3
|
import { getIbGibAddr } from "@ibgib/ts-gib/dist/helper.mjs";
|
|
4
4
|
import { Factory_V1 } from "@ibgib/ts-gib/dist/V1/factory.mjs";
|
|
5
|
+
import { GLOBAL_LOG_A_LOT } from "../core-constants.mjs";
|
|
5
6
|
import { putInSpace, getLatestAddrs, getFromSpace } from "../witness/space/space-helper.mjs";
|
|
6
7
|
import { SyncStage, SYNC_ATOM, SYNC_MSG_REL8N_NAME, SYNC_SAGA_PAYLOAD_ADDRS_DOMAIN, } from "./sync-constants.mjs";
|
|
7
8
|
import { appendToTimeline, createTimeline } from "../timeline/timeline-api.mjs";
|
|
8
9
|
import { SyncConflictStrategy, SyncMode, SYNC_CONFLICT_STRATEGY_VALID_VALUES, } from "./sync-types.mjs";
|
|
9
|
-
import { getSyncIb, getTempSpaceName, isPastFrame } from "./sync-helpers.mjs";
|
|
10
|
+
import { getSyncSagaFrameOrigin, getFullSyncSagaHistory, getSyncIb, getTempSpaceName, isPastFrame, putInSpace_dnasThenNonDnas, validateFullSyncSagaHistory } from "./sync-helpers.mjs";
|
|
10
11
|
import { getDeltaDependencyGraph, getDependencyGraph, toFlatGraph } from "../common/other/graph-helper.mjs";
|
|
11
12
|
import { getSyncSagaMessageIb } from "./sync-saga-message/sync-saga-message-helpers.mjs";
|
|
12
13
|
import { SYNC_SAGA_MSG_ATOM } from "./sync-saga-message/sync-saga-message-constants.mjs";
|
|
@@ -16,9 +17,8 @@ import { newupSubject, } from "../common/pubsub/subject/subject-helper.mjs";
|
|
|
16
17
|
import { mergeDivergentTimelines } from "./strategies/conflict-optimistic.mjs";
|
|
17
18
|
import { getSyncSagaMessageFromFrame } from "./sync-saga-message/sync-saga-message-helpers.mjs";
|
|
18
19
|
import { fnObs } from "../common/pubsub/observer/observer-helper.mjs";
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
const logalotControlDomain = true;
|
|
20
|
+
const logalot = GLOBAL_LOG_A_LOT;
|
|
21
|
+
const logalotControlDomain = false;
|
|
22
22
|
const lcControlDomain = '[ControlDomain]';
|
|
23
23
|
/**
|
|
24
24
|
* Orchestrates the synchronization process between two spaces (Source and Destination).
|
|
@@ -171,7 +171,12 @@ export class SyncSagaCoordinator {
|
|
|
171
171
|
if (logalot) {
|
|
172
172
|
console.log(`${lc} Handler returned null (Saga End). (I: 43da8bb6c846b1fe7766332643be0e26)`);
|
|
173
173
|
}
|
|
174
|
-
|
|
174
|
+
// does this ever hit now?
|
|
175
|
+
return null; /* <<<< returns early */
|
|
176
|
+
}
|
|
177
|
+
else if (contextResult.nextFrameInfo?.sagaComplete) {
|
|
178
|
+
// this is the current proper workflow I believe as of 01/22/2026
|
|
179
|
+
return null; /* <<<< returns early */
|
|
175
180
|
}
|
|
176
181
|
// #region error conditions throw
|
|
177
182
|
if (contextResult.errorMsg) {
|
|
@@ -180,9 +185,6 @@ export class SyncSagaCoordinator {
|
|
|
180
185
|
else if (!contextResult.nextFrameInfo) {
|
|
181
186
|
throw new Error(`(UNEXPECTED) contextResult.nextFrameInfo falsy? (E: 5740542f5eb8ccb41dfec188d87c1e26)`);
|
|
182
187
|
}
|
|
183
|
-
else if (contextResult.nextFrameInfo?.responseWasNull) {
|
|
184
|
-
throw new Error(`(UNEXPECTED) contextResult.nextFrameInfo.responseWasNull? logic flow should not have gotten here. (E: ae06748d8c0c5e70c92322c8fb0cb426)`);
|
|
185
|
-
}
|
|
186
188
|
// #endregion error conditions throw
|
|
187
189
|
// create the return context
|
|
188
190
|
const { frame, payloadIbGibsDomain } = contextResult.nextFrameInfo;
|
|
@@ -405,8 +407,13 @@ export class SyncSagaCoordinator {
|
|
|
405
407
|
metaspace,
|
|
406
408
|
});
|
|
407
409
|
if (!contextResult) {
|
|
410
|
+
// should this ever hit?
|
|
411
|
+
console.error(`${lc} NAG ERROR (DOES NOT THROW): does this ever hit now? (E: e04d02efc2a8e72a88b79f1f0f95ca26)`);
|
|
412
|
+
break;
|
|
413
|
+
}
|
|
414
|
+
else if (contextResult.nextFrameInfo?.sagaComplete) {
|
|
408
415
|
if (logalot) {
|
|
409
|
-
console.log(`${lc} Handler returned null (Saga End). (I:
|
|
416
|
+
console.log(`${lc} Handler returned null (Saga End). (I: 123bf9e7dca8886de72553a8d4f29e26)`);
|
|
410
417
|
}
|
|
411
418
|
break;
|
|
412
419
|
}
|
|
@@ -417,9 +424,6 @@ export class SyncSagaCoordinator {
|
|
|
417
424
|
else if (!contextResult.nextFrameInfo) {
|
|
418
425
|
throw new Error(`(UNEXPECTED) contextResult.nextFrameInfo falsy? (E: c287a82e823e662a77923278e2418826)`);
|
|
419
426
|
}
|
|
420
|
-
else if (contextResult.nextFrameInfo?.responseWasNull) {
|
|
421
|
-
throw new Error(`(UNEXPECTED) contextResult.nextFrameInfo.responseWasNull? logic flow should not have gotten here. (E: 104a32381db816b7183435e805b3d626)`);
|
|
422
|
-
}
|
|
423
427
|
// #endregion error conditions throw
|
|
424
428
|
// we have another frame to process and send out, with possibly
|
|
425
429
|
// payload domain ibgibs as well
|
|
@@ -728,14 +732,19 @@ export class SyncSagaCoordinator {
|
|
|
728
732
|
sagaContext,
|
|
729
733
|
sagaIbGib,
|
|
730
734
|
srcGraph,
|
|
731
|
-
metaspace,
|
|
732
|
-
mySpace,
|
|
733
|
-
myTempSpace,
|
|
735
|
+
metaspace, mySpace, myTempSpace,
|
|
734
736
|
identity,
|
|
735
737
|
});
|
|
736
738
|
break;
|
|
737
739
|
case SyncStage.commit:
|
|
738
|
-
|
|
740
|
+
if (logalot) {
|
|
741
|
+
console.log(`${lc}[${getSyncSagaFrameOrigin({ sagaFrame: sagaIbGib })}] mySpace.ib: ${mySpace.ib} (I: 5b270996d848907238d817fffa64a126)`);
|
|
742
|
+
}
|
|
743
|
+
nextFrameInfo = await this.handleCommitFrame({
|
|
744
|
+
sagaIbGib,
|
|
745
|
+
metaspace, mySpace, myTempSpace,
|
|
746
|
+
identity,
|
|
747
|
+
});
|
|
739
748
|
break;
|
|
740
749
|
default:
|
|
741
750
|
throw new Error(`${lc} (UNEXPECTED) Unknown sync stage: ${stage} (E: 9c2b4c8a6d34469f8263544710183355)`);
|
|
@@ -777,7 +786,9 @@ export class SyncSagaCoordinator {
|
|
|
777
786
|
if (logalot) {
|
|
778
787
|
console.log(`${lc} starting... (I: 9d88dcad0408c029e898a4bcf3b08426)`);
|
|
779
788
|
}
|
|
780
|
-
|
|
789
|
+
if (logalot) {
|
|
790
|
+
console.log(`${lc} [TEST DEBUG] Receiver mySpace: ${mySpace.ib}`);
|
|
791
|
+
}
|
|
781
792
|
// Extract Init Data
|
|
782
793
|
const initData = messageData; // Using renamed variable for clarity
|
|
783
794
|
if (initData.stage !== SyncStage.init) {
|
|
@@ -825,7 +836,9 @@ export class SyncSagaCoordinator {
|
|
|
825
836
|
console.log(`${lc} remoteKV: ${pretty(remoteKV)} (I: 9f957862356dfeae183c200854e86e26)`);
|
|
826
837
|
}
|
|
827
838
|
const remoteTjps = Object.keys(remoteKV);
|
|
828
|
-
|
|
839
|
+
if (logalot) {
|
|
840
|
+
console.log(`${lc} [TEST DEBUG] remoteTjps: ${JSON.stringify(remoteTjps)}`);
|
|
841
|
+
}
|
|
829
842
|
if (logalot) {
|
|
830
843
|
console.log(`${lc} remoteTjps: ${pretty(remoteTjps)} (I: 86ea4c53db0dc184c8b253386c402126)`);
|
|
831
844
|
}
|
|
@@ -844,7 +857,9 @@ export class SyncSagaCoordinator {
|
|
|
844
857
|
throw new Error(`(UNEXPECTED) resGetLatestAddrs.data.latestAddrsMap falsy? (E: 16bc386dd51d0ff53a49620b1e641826)`);
|
|
845
858
|
}
|
|
846
859
|
localLatestAddrsMap = resGetLatestAddrs.data.latestAddrsMap;
|
|
847
|
-
|
|
860
|
+
if (logalot) {
|
|
861
|
+
console.log(`${lc} [TEST DEBUG] localKV: ${JSON.stringify(localLatestAddrsMap)}`);
|
|
862
|
+
}
|
|
848
863
|
if (logalot) {
|
|
849
864
|
console.log(`${lc} localKV: ${pretty(localLatestAddrsMap)} (I: 980975642cbccd8018cf0cd808d30826)`);
|
|
850
865
|
}
|
|
@@ -855,7 +870,9 @@ export class SyncSagaCoordinator {
|
|
|
855
870
|
const localAddr = localLatestAddrsMap[tjp];
|
|
856
871
|
if (!localAddr) {
|
|
857
872
|
// We (Receiver) don't have this timeline at all. Request it.
|
|
858
|
-
|
|
873
|
+
if (logalot) {
|
|
874
|
+
console.log(`${lc} [TEST DEBUG] Missing local timeline for TJP: ${tjp}. Requesting remoteAddr: ${remoteAddr}`);
|
|
875
|
+
}
|
|
859
876
|
deltaRequestAddrInfos.push({
|
|
860
877
|
addr: remoteAddr,
|
|
861
878
|
tjpAddr: tjp,
|
|
@@ -867,10 +884,14 @@ export class SyncSagaCoordinator {
|
|
|
867
884
|
// we do have this timeline...
|
|
868
885
|
if (localAddr === remoteAddr) {
|
|
869
886
|
// ...already synced
|
|
870
|
-
|
|
887
|
+
if (logalot) {
|
|
888
|
+
console.log(`${lc} [TEST DEBUG] TJP ${tjp}: Synced (localAddr === remoteAddr)`);
|
|
889
|
+
}
|
|
871
890
|
continue;
|
|
872
891
|
}
|
|
873
|
-
|
|
892
|
+
if (logalot) {
|
|
893
|
+
console.log(`${lc} [TEST DEBUG] TJP ${tjp}: localAddr=${localAddr}, remoteAddr=${remoteAddr} - checking for divergence...`);
|
|
894
|
+
}
|
|
874
895
|
// we have this timeline but it's not synced...
|
|
875
896
|
// We're executing on receiver. Check if Remote (Sender) is in
|
|
876
897
|
// our past, and if so, we are ahead and need to push the delta
|
|
@@ -883,7 +904,9 @@ export class SyncSagaCoordinator {
|
|
|
883
904
|
if (remoteIsInPast) {
|
|
884
905
|
// we're ahead, so push the delta of what the sender doesn't
|
|
885
906
|
// have (we have full knowledge)
|
|
886
|
-
|
|
907
|
+
if (logalot) {
|
|
908
|
+
console.log(`${lc} [TEST DEBUG] TJP ${tjp}: Remote (sender) is in past - offering push`);
|
|
909
|
+
}
|
|
887
910
|
const deltaGraph = await getDeltaDependencyGraph({
|
|
888
911
|
ibGibAddr: localAddr,
|
|
889
912
|
live: false, // always live: false right?
|
|
@@ -919,7 +942,9 @@ export class SyncSagaCoordinator {
|
|
|
919
942
|
}
|
|
920
943
|
if (localIsInPast) {
|
|
921
944
|
// Fast-Forward: We update to remote's tip.
|
|
922
|
-
|
|
945
|
+
if (logalot) {
|
|
946
|
+
console.log(`${lc} [TEST DEBUG] TJP ${tjp}: Local is in past - requesting delta`);
|
|
947
|
+
}
|
|
923
948
|
deltaRequestAddrInfos.push({
|
|
924
949
|
addr: remoteAddr,
|
|
925
950
|
tjpAddr: tjp,
|
|
@@ -928,7 +953,9 @@ export class SyncSagaCoordinator {
|
|
|
928
953
|
}
|
|
929
954
|
else {
|
|
930
955
|
// DIVERGENCE: Both have changes the other doesn't know about.
|
|
931
|
-
|
|
956
|
+
if (logalot) {
|
|
957
|
+
console.log(`${lc} [TEST DEBUG] TJP ${tjp}: DIVERGENCE DETECTED! conflictStrategy=${conflictStrategy}`);
|
|
958
|
+
}
|
|
932
959
|
if (conflictStrategy === 'abort') {
|
|
933
960
|
// Abort Strategy: We will treat this as terminal.
|
|
934
961
|
// But for Unified Ack, we just mark it terminal in the list?
|
|
@@ -1132,13 +1159,17 @@ export class SyncSagaCoordinator {
|
|
|
1132
1159
|
// #region sanity/validation
|
|
1133
1160
|
// 1. Check for Conflicts
|
|
1134
1161
|
const conflicts = ackData.conflicts || [];
|
|
1135
|
-
|
|
1136
|
-
|
|
1162
|
+
if (logalot) {
|
|
1163
|
+
console.log(`${lc} [CONFLICT DEBUG] Received conflicts from Ack: ${conflicts.length}`);
|
|
1164
|
+
}
|
|
1165
|
+
if (logalot && conflicts.length > 0) {
|
|
1137
1166
|
console.log(`${lc} [CONFLICT DEBUG] Conflicts detail: ${JSON.stringify(conflicts, null, 2)}`);
|
|
1138
1167
|
}
|
|
1139
1168
|
const terminalConflicts = conflicts.filter(c => c.terminal);
|
|
1140
1169
|
if (terminalConflicts.length > 0) {
|
|
1141
|
-
|
|
1170
|
+
if (logalot) {
|
|
1171
|
+
console.warn(`${lc} Received terminal conflicts from Ack: ${JSON.stringify(terminalConflicts)}`);
|
|
1172
|
+
}
|
|
1142
1173
|
// Terminal failure. Sender should probably Commit(Fail) or just Abort.
|
|
1143
1174
|
// For now, throw to trigger abort.
|
|
1144
1175
|
throw new Error(`${lc} Peer reported terminal conflicts. (E: 23a0096ee05a2ccfa89334e8f156b426)`);
|
|
@@ -1151,7 +1182,9 @@ export class SyncSagaCoordinator {
|
|
|
1151
1182
|
*/
|
|
1152
1183
|
const outgoingDeltaAddrRequestInfos = []; // Additional requests for merging
|
|
1153
1184
|
if (conflicts.length > 0) {
|
|
1154
|
-
|
|
1185
|
+
if (logalot) {
|
|
1186
|
+
console.log(`${lc} [CONFLICT DEBUG] Processing ${conflicts.length} non-terminal conflicts`);
|
|
1187
|
+
}
|
|
1155
1188
|
// We need to resolve these.
|
|
1156
1189
|
// Strategy:
|
|
1157
1190
|
// 1. Analyze Divergence (Sender vs Receiver)
|
|
@@ -1259,10 +1292,14 @@ export class SyncSagaCoordinator {
|
|
|
1259
1292
|
// console.log(`${lc} [CONFLICT DEBUG] No receiver-only frames found for this conflict`);
|
|
1260
1293
|
// }
|
|
1261
1294
|
}
|
|
1262
|
-
|
|
1295
|
+
if (logalot) {
|
|
1296
|
+
console.log(`${lc} [CONFLICT DEBUG] Finished processing ${conflicts.length} conflicts. outgoingDeltaAddrRequestInfos: ${outgoingDeltaAddrRequestInfos.length}`);
|
|
1297
|
+
}
|
|
1263
1298
|
}
|
|
1264
1299
|
else {
|
|
1265
|
-
|
|
1300
|
+
if (logalot) {
|
|
1301
|
+
console.log(`${lc} [CONFLICT DEBUG] No optimistic conflicts to process`);
|
|
1302
|
+
}
|
|
1266
1303
|
}
|
|
1267
1304
|
// 2. Prepare Delta Payload (What Receiver Requesting + Our Conflict Logic)
|
|
1268
1305
|
/**
|
|
@@ -1333,69 +1370,6 @@ export class SyncSagaCoordinator {
|
|
|
1333
1370
|
}
|
|
1334
1371
|
}
|
|
1335
1372
|
}
|
|
1336
|
-
async getPayloadsForRequestedInfos({ deltaRequestAddrInfos, mySpace, }) {
|
|
1337
|
-
const lc = `${this.lc}[${this.getPayloadsForRequestedInfos.name}]`;
|
|
1338
|
-
try {
|
|
1339
|
-
if (logalot) {
|
|
1340
|
-
console.log(`${lc} starting... (I: 4fe13d0d80050f20a8b74ba80cee5826)`);
|
|
1341
|
-
}
|
|
1342
|
-
/**
|
|
1343
|
-
* graph of ibgibs we will send to the receiver. addr-based, so will
|
|
1344
|
-
* already be unique (no need to call `unique` on the domains
|
|
1345
|
-
* ibgibs)
|
|
1346
|
-
*/
|
|
1347
|
-
const outgoingPayloadIbGibsDomainGraph = {};
|
|
1348
|
-
for (const { addr, latestAddrAlreadyHave } of deltaRequestAddrInfos) {
|
|
1349
|
-
let deltaDepGraph;
|
|
1350
|
-
if (latestAddrAlreadyHave) {
|
|
1351
|
-
// already has some, so only get the delta
|
|
1352
|
-
// remember: if we didn't have the other's latest addr, then
|
|
1353
|
-
// this would be in the conflicts not requested addrs
|
|
1354
|
-
deltaDepGraph = await getDeltaDependencyGraph({
|
|
1355
|
-
ibGibAddr: addr,
|
|
1356
|
-
latestCommonFrameAddr: latestAddrAlreadyHave,
|
|
1357
|
-
space: mySpace,
|
|
1358
|
-
live: true,
|
|
1359
|
-
});
|
|
1360
|
-
}
|
|
1361
|
-
else {
|
|
1362
|
-
// doesn't have anything, so get the entire dependency graph
|
|
1363
|
-
// INEFFICIENT: we've already gotten all of the domain
|
|
1364
|
-
// dependencies in initDomainGraph, but getDependencyGraph
|
|
1365
|
-
// only works against a space so we are going to rerun this.
|
|
1366
|
-
// an optimization would be to adapt/create a new
|
|
1367
|
-
// getDependencyGraph to work against an existing flat ibgib
|
|
1368
|
-
// map.
|
|
1369
|
-
deltaDepGraph = await getDependencyGraph({
|
|
1370
|
-
ibGibAddr: addr,
|
|
1371
|
-
space: mySpace,
|
|
1372
|
-
live: true,
|
|
1373
|
-
});
|
|
1374
|
-
}
|
|
1375
|
-
const depGraphSize = Object.keys(deltaDepGraph).length;
|
|
1376
|
-
if (depGraphSize === 0) {
|
|
1377
|
-
throw new Error(`(UNEXPECTED) couldn't get requested addrs in mySpace (${mySpace.ib})? How did the receiver know to ask for these addrs if they weren't in our original graph? (E: 281eaebcdf77dd73e8245b2872100826)`);
|
|
1378
|
-
}
|
|
1379
|
-
else {
|
|
1380
|
-
// we have dependencies!
|
|
1381
|
-
Object.values(deltaDepGraph).forEach(x => {
|
|
1382
|
-
outgoingPayloadIbGibsDomainGraph[getIbGibAddr({ ibGib: x })] = x;
|
|
1383
|
-
});
|
|
1384
|
-
}
|
|
1385
|
-
}
|
|
1386
|
-
const result = Object.values(outgoingPayloadIbGibsDomainGraph);
|
|
1387
|
-
return result;
|
|
1388
|
-
}
|
|
1389
|
-
catch (error) {
|
|
1390
|
-
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
1391
|
-
throw error;
|
|
1392
|
-
}
|
|
1393
|
-
finally {
|
|
1394
|
-
if (logalot) {
|
|
1395
|
-
console.log(`${lc} complete.`);
|
|
1396
|
-
}
|
|
1397
|
-
}
|
|
1398
|
-
}
|
|
1399
1373
|
/**
|
|
1400
1374
|
* Handles the `Delta` frame.
|
|
1401
1375
|
*
|
|
@@ -1425,51 +1399,71 @@ export class SyncSagaCoordinator {
|
|
|
1425
1399
|
console.log(`${lc} deltaData: ${pretty(deltaData)} (I: a76008681df458cfbcdc4848f825a826)`);
|
|
1426
1400
|
}
|
|
1427
1401
|
// #endregion validate/sanity
|
|
1428
|
-
|
|
1402
|
+
if (logalot) {
|
|
1403
|
+
console.log(`${lc} [CONFLICT DEBUG] deltaData.payloadAddrs count: ${deltaData.payloadAddrs?.length || 0}`);
|
|
1404
|
+
}
|
|
1429
1405
|
const peerProposesCommit = deltaData.proposeCommit || false;
|
|
1430
1406
|
/**
|
|
1431
1407
|
* these are already in the local temp space
|
|
1432
1408
|
*/
|
|
1433
1409
|
const receivedPayloadIbGibs = sagaContext.payloadIbGibsDomain ?? [];
|
|
1434
1410
|
// 2. Fulfill Peer Requests (Outgoing Payload with Delta Dependencies)
|
|
1435
|
-
|
|
1411
|
+
if (logalot) {
|
|
1412
|
+
console.log(`${lc} [CONFLICT DEBUG] Fulfilling ${(deltaData.deltaRequestAddrInfos || []).length} peer requests`);
|
|
1413
|
+
}
|
|
1436
1414
|
const outgoingPayload = await this.getPayloadsForRequestedInfos({
|
|
1437
1415
|
deltaRequestAddrInfos: deltaData.deltaRequestAddrInfos || [],
|
|
1438
1416
|
mySpace,
|
|
1439
1417
|
});
|
|
1440
|
-
|
|
1418
|
+
if (logalot) {
|
|
1419
|
+
console.log(`${lc} [CONFLICT DEBUG] Outgoing payload size (with deps): ${outgoingPayload.length}`);
|
|
1420
|
+
}
|
|
1441
1421
|
// 3. Execute Merges (If applicable)
|
|
1442
1422
|
// Check if we have pending conflicts that we CAN resolve now that we have data.
|
|
1443
1423
|
// We look at the Saga History (Ack Frame) to find conflicts.
|
|
1444
1424
|
// Optimization: Do this only if we received payloads.
|
|
1445
1425
|
const mergeResultIbGibs = [];
|
|
1446
|
-
|
|
1426
|
+
if (logalot) {
|
|
1427
|
+
console.log(`${lc} [CONFLICT DEBUG] Checking for merge. receivedPayloadIbGibs.length: ${receivedPayloadIbGibs.length}`);
|
|
1428
|
+
}
|
|
1447
1429
|
if (receivedPayloadIbGibs.length > 0) {
|
|
1448
|
-
|
|
1430
|
+
if (logalot) {
|
|
1431
|
+
console.log(`${lc} [TEST DEBUG] Received Payloads (${receivedPayloadIbGibs.length}). Checking for conflicts/merges...`);
|
|
1432
|
+
}
|
|
1449
1433
|
// Find the Ack frame in history to get conflicts
|
|
1450
1434
|
// Optimization: Batch fetch history from `sagaIbGib.rel8ns.past`
|
|
1451
1435
|
// V1 timelines carry full history in `past`.
|
|
1452
1436
|
const pastAddrs = sagaIbGib.rel8ns?.past || [];
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1437
|
+
if (logalot) {
|
|
1438
|
+
console.log(`${lc} [TEST DEBUG] pastAddrs count: ${pastAddrs.length}`);
|
|
1439
|
+
}
|
|
1440
|
+
const sagaHistory = await getFullSyncSagaHistory({
|
|
1441
|
+
sagaIbGib,
|
|
1442
|
+
space: mySpace,
|
|
1443
|
+
});
|
|
1444
|
+
// #region validate/sanity sagaHistory
|
|
1445
|
+
if (sagaHistory.length === 0) {
|
|
1446
|
+
throw new Error(`(UNEXPECTED) sagaHistory.length is 0? We're in handleDeltaFrame. So we should have at least init and ack. (E: 815735c9cf756b275719bf434f180826)`);
|
|
1447
|
+
}
|
|
1448
|
+
if (sagaHistory.length === 1) {
|
|
1449
|
+
throw new Error(`(UNEXPECTED) sagaHistory.length is 1? We're in handleDeltaFrame. So we should have at least init and ack. (E: 0e4ef8e3ed088e83b2cdcd18ecea9826)`);
|
|
1450
|
+
}
|
|
1451
|
+
// #endregion validate/sanity sagaHistory
|
|
1452
|
+
const ackGraphs = sagaHistory.filter(x => x.msgStones.at(0).data.stage === SyncStage.ack);
|
|
1453
|
+
// #region validate/sanity ackGraphs
|
|
1454
|
+
if (ackGraphs.length > 1) {
|
|
1455
|
+
throw new Error(`(UNEXPECTED) more than one ack stage found in sagaHistory? we're expecting exactly one. (E: 7150983bb3a841caf8acd60826ba4f26)`);
|
|
1456
|
+
}
|
|
1457
|
+
else if (ackGraphs.length === 0) {
|
|
1458
|
+
throw new Error(`(UNEXPECTED) couldn't find ack stage in sagaHistory? (E: 7d2da859196b86de28e7c8183af1e826)`);
|
|
1459
|
+
}
|
|
1460
|
+
if (ackGraphs[0].msgStones.length !== 1) {
|
|
1461
|
+
throw new Error(`(UNEXPECTED) ackGraph has more than one msg stone? only one expected right now. (E: f07d388abff8d26f98cbf6e8d3932826)`);
|
|
1462
|
+
}
|
|
1463
|
+
// #endregion validate/sanity ackGraphs
|
|
1464
|
+
const ackData = ackGraphs[0].msgStones[0].data;
|
|
1465
|
+
if (!ackData) {
|
|
1466
|
+
throw new Error(`(UNEXPECTED) ackData falsy? (E: f9af88427f66a8db1ba868b810e8b826)`);
|
|
1473
1467
|
}
|
|
1474
1468
|
if (ackData && ackData.conflicts) {
|
|
1475
1469
|
const optimisticConflicts = ackData.conflicts.filter(c => !c.terminal);
|
|
@@ -1481,9 +1475,13 @@ export class SyncSagaCoordinator {
|
|
|
1481
1475
|
// We blindly attempt merge if we have both tips accessible?
|
|
1482
1476
|
// We need `receiverTip` (localAddr in Ack) and `senderTip` (remoteAddr).
|
|
1483
1477
|
// Check if we have receiverTip in space
|
|
1484
|
-
|
|
1478
|
+
if (logalot) {
|
|
1479
|
+
console.log(`${lc} [CONFLICT DEBUG] Attempting merge for conflict. ReceiverTip: ${receiverTip}, SenderTip: ${senderTip}`);
|
|
1480
|
+
}
|
|
1485
1481
|
const resRecTip = await getFromSpace({ addr: receiverTip, space: myTempSpace }); // Check myTempSpace for incoming data
|
|
1486
|
-
|
|
1482
|
+
if (logalot) {
|
|
1483
|
+
console.log(`${lc} [CONFLICT DEBUG] ReceiverTip found in myTempSpace: ${!!resRecTip.ibGibs?.[0]}`);
|
|
1484
|
+
}
|
|
1487
1485
|
if (resRecTip.success && resRecTip.ibGibs?.[0]) {
|
|
1488
1486
|
// We have the tip!
|
|
1489
1487
|
// Do we have the full history?
|
|
@@ -1498,7 +1496,9 @@ export class SyncSagaCoordinator {
|
|
|
1498
1496
|
metaspace,
|
|
1499
1497
|
});
|
|
1500
1498
|
if (mergeResult) {
|
|
1501
|
-
|
|
1499
|
+
if (logalot) {
|
|
1500
|
+
console.log(`${lc} [TEST DEBUG] Merge success! New Tip: ${getIbGibAddr({ ibGib: mergeResult })}`);
|
|
1501
|
+
}
|
|
1502
1502
|
if (logalot) {
|
|
1503
1503
|
console.log(`${lc} Merge success! New Tip: ${getIbGibAddr({ ibGib: mergeResult })}`);
|
|
1504
1504
|
}
|
|
@@ -1507,7 +1507,7 @@ export class SyncSagaCoordinator {
|
|
|
1507
1507
|
}
|
|
1508
1508
|
}
|
|
1509
1509
|
catch (e) {
|
|
1510
|
-
console.error(`${lc} Merge failed: ${e}`);
|
|
1510
|
+
console.error(`${lc} (NOT THROWN) Merge failed: ${e} (E: 491b464fc6f4857f52ff3df213105826)`);
|
|
1511
1511
|
// If merge fails, we might Abort or just continue?
|
|
1512
1512
|
}
|
|
1513
1513
|
}
|
|
@@ -1529,17 +1529,7 @@ export class SyncSagaCoordinator {
|
|
|
1529
1529
|
stage: SyncStage.delta,
|
|
1530
1530
|
payloadAddrs: outgoingPayload.map(p => getIbGibAddr({ ibGib: p })),
|
|
1531
1531
|
requests: hasMyRequests ? myRequests : undefined,
|
|
1532
|
-
proposeCommit: !hasMyRequests // If we are sending data but have no requests, we VALIDATE PROPOSAL?
|
|
1533
|
-
// Wait. If we send data, we are NOT committing yet.
|
|
1534
|
-
// We are sending data. The OTHER side must ingest it.
|
|
1535
|
-
// So proposeCommit = true?
|
|
1536
|
-
// "Here is the data. I'm done. If you are good, let's commit."
|
|
1537
|
-
// Yes.
|
|
1538
1532
|
};
|
|
1539
|
-
// BUT if `peerProposesCommit` was true, and we are sending data, we are effectively rejecting/delaying it.
|
|
1540
|
-
// We just send the Delta. Peer receives it, ingests, sees ProposeCommit=True (from us), and then Commits.
|
|
1541
|
-
// So yes, proposeCommit = true.
|
|
1542
|
-
responseDeltaData.proposeCommit = true;
|
|
1543
1533
|
const deltaStone = await this.createSyncMsgStone({
|
|
1544
1534
|
data: responseDeltaData,
|
|
1545
1535
|
localSpace: mySpace,
|
|
@@ -1552,41 +1542,43 @@ export class SyncSagaCoordinator {
|
|
|
1552
1542
|
localSpace: mySpace,
|
|
1553
1543
|
metaspace,
|
|
1554
1544
|
});
|
|
1555
|
-
// Build control payloads: frame + its dependencies (msg stone, identity)
|
|
1556
|
-
const payloadIbGibsControl = [deltaFrame, deltaStone];
|
|
1557
|
-
if (identity) {
|
|
1558
|
-
payloadIbGibsControl.push(identity);
|
|
1559
|
-
}
|
|
1560
|
-
// return { frame: deltaFrame, payloadIbGibsControl, payloadIbGibsDomain: outgoingPayload };
|
|
1561
1545
|
return { frame: deltaFrame, payloadIbGibsDomain: outgoingPayload };
|
|
1562
|
-
// throw new Error(`not implemented (E: 2b38a8afb6d84efcee5ab51673387826)`);
|
|
1563
1546
|
}
|
|
1564
1547
|
else {
|
|
1565
1548
|
// We have nothing to send.
|
|
1566
1549
|
if (peerProposesCommit) {
|
|
1567
1550
|
// Peer is done. We are done. -> Commit.
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
};
|
|
1573
|
-
const commitStone = await this.createSyncMsgStone({
|
|
1574
|
-
data: commitData,
|
|
1575
|
-
localSpace: mySpace,
|
|
1576
|
-
metaspace
|
|
1551
|
+
// one last validate entire history?
|
|
1552
|
+
const history = await getFullSyncSagaHistory({
|
|
1553
|
+
sagaIbGib,
|
|
1554
|
+
space: mySpace,
|
|
1577
1555
|
});
|
|
1578
|
-
const
|
|
1579
|
-
|
|
1580
|
-
msgStones: [commitStone],
|
|
1581
|
-
sessionIdentity: identity,
|
|
1582
|
-
localSpace: mySpace,
|
|
1583
|
-
metaspace
|
|
1556
|
+
const validationErrors = await validateFullSyncSagaHistory({
|
|
1557
|
+
history,
|
|
1584
1558
|
});
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1559
|
+
if (validationErrors.length > 0) {
|
|
1560
|
+
const errorCommitFrame = await this.createCommitFrame({
|
|
1561
|
+
sagaIbGib,
|
|
1562
|
+
errors: validationErrors,
|
|
1563
|
+
metaspace, mySpace,
|
|
1564
|
+
identity,
|
|
1565
|
+
});
|
|
1566
|
+
return { frame: errorCommitFrame, }; /* <<<< returns early */
|
|
1589
1567
|
}
|
|
1568
|
+
await this.executeLocalCommit({
|
|
1569
|
+
sagaHistory: history,
|
|
1570
|
+
deltaFrame: sagaIbGib,
|
|
1571
|
+
localTempSpace: myTempSpace,
|
|
1572
|
+
localSpace: mySpace,
|
|
1573
|
+
metaspace,
|
|
1574
|
+
});
|
|
1575
|
+
const commitFrame = await this.createCommitFrame({
|
|
1576
|
+
sagaIbGib,
|
|
1577
|
+
errors: undefined,
|
|
1578
|
+
metaspace,
|
|
1579
|
+
mySpace,
|
|
1580
|
+
identity,
|
|
1581
|
+
});
|
|
1590
1582
|
return { frame: commitFrame, };
|
|
1591
1583
|
}
|
|
1592
1584
|
else {
|
|
@@ -1660,24 +1652,187 @@ export class SyncSagaCoordinator {
|
|
|
1660
1652
|
}
|
|
1661
1653
|
}
|
|
1662
1654
|
}
|
|
1663
|
-
|
|
1664
|
-
|
|
1655
|
+
/**
|
|
1656
|
+
* should throw if fails
|
|
1657
|
+
*/
|
|
1658
|
+
async executeLocalCommit({ deltaFrame, commitFrame, sagaHistory, metaspace, localSpace, localTempSpace, identity, }) {
|
|
1659
|
+
const lc = `${this.lc}[${this.executeLocalCommit.name}]`;
|
|
1665
1660
|
try {
|
|
1666
1661
|
if (logalot) {
|
|
1667
|
-
console.log(`${lc} starting... (I:
|
|
1662
|
+
console.log(`${lc} starting... (I: 6734980446b86a63c1af6e2e206de826)`);
|
|
1663
|
+
}
|
|
1664
|
+
if (!deltaFrame && !commitFrame) {
|
|
1665
|
+
throw new Error(`(UNEXPECTED) !deltaFrame && !commitFrame? we're expecting to execute the commit based off of EITHER a delta OR a commit frame. (E: 10cae319a2685a672866f5583514e326)`);
|
|
1666
|
+
}
|
|
1667
|
+
else if (deltaFrame && commitFrame) {
|
|
1668
|
+
throw new Error(`(UNEXPECTED) deltaFrame && commitFrame? we're expecting to execute the commit based off of EITHER a delta OR a commit frame. (E: b9037b1ed6d8684ac8a5d01328bad826)`);
|
|
1669
|
+
}
|
|
1670
|
+
/**
|
|
1671
|
+
* Sync has a two-stage commit. The first is from a delta frame with
|
|
1672
|
+
* `proposeCommit: true`. That produces a commit frame, which on the
|
|
1673
|
+
* other end triggers the second leg.
|
|
1674
|
+
*/
|
|
1675
|
+
const isFirstCommitLeg = !!deltaFrame;
|
|
1676
|
+
const currentFrame = isFirstCommitLeg ? deltaFrame : commitFrame;
|
|
1677
|
+
if (!currentFrame) {
|
|
1678
|
+
throw new Error(`(UNEXPECTED) !currentFrame? something wrong with my logic. (E: 4ec0ce6625cc1d677bc902c839ca1a26)`);
|
|
1679
|
+
}
|
|
1680
|
+
/**
|
|
1681
|
+
* we only want to register new ibgibs from the other end, so we
|
|
1682
|
+
* will compare the history payloads/push offers with the context
|
|
1683
|
+
* that provided those payloads.
|
|
1684
|
+
*
|
|
1685
|
+
* So we will filter out the history that we produced, which should
|
|
1686
|
+
* leave us only with externally created payload addrs.
|
|
1687
|
+
*
|
|
1688
|
+
* NOTE: I have this at the beginning of the function PURELY to get
|
|
1689
|
+
* a log value in to understand the context of this function's
|
|
1690
|
+
* output.
|
|
1691
|
+
*/
|
|
1692
|
+
const currentFrameOrigin = getSyncSagaFrameOrigin({ sagaFrame: currentFrame });
|
|
1693
|
+
if (logalot) {
|
|
1694
|
+
console.log(`${lc} currentFrameOrigin: ${currentFrameOrigin} (I: 3add8f8390c89743ae554bd3cc60b826)`);
|
|
1695
|
+
}
|
|
1696
|
+
// #region validate/sanity
|
|
1697
|
+
if (!currentFrame.data) {
|
|
1698
|
+
throw new Error(`(UNEXPECTED) currentFrame.data falsy? (E: a8be68d48668d93d992d793834823826)`);
|
|
1668
1699
|
}
|
|
1669
|
-
//
|
|
1670
|
-
//
|
|
1671
|
-
//
|
|
1672
|
-
//
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1700
|
+
// #endregion validate/sanity
|
|
1701
|
+
// * move all payload addrs from temp space to local space
|
|
1702
|
+
// * register each and every iteration of each timeline (including
|
|
1703
|
+
// stones, which are like their own sealed timeline of length 1)
|
|
1704
|
+
const allPayloadAddrsDomainTransferred = [];
|
|
1705
|
+
const fnAddPayloadAddr = (addr) => {
|
|
1706
|
+
if (!allPayloadAddrsDomainTransferred.includes(addr)) {
|
|
1707
|
+
allPayloadAddrsDomainTransferred.push(addr);
|
|
1708
|
+
}
|
|
1709
|
+
};
|
|
1710
|
+
sagaHistory.filter(x => {
|
|
1711
|
+
const frameExecutionContext = getSyncSagaFrameOrigin({ sagaFrame: x.sagaIbGib });
|
|
1712
|
+
return currentFrameOrigin === frameExecutionContext;
|
|
1713
|
+
}).forEach(x => {
|
|
1714
|
+
if (!x.sagaIbGib.data) {
|
|
1715
|
+
throw new Error(`(UNEXPECTED) sagaIbGib.data falsy? (E: 34d7f8cdee14717ce828878d98f89826)`);
|
|
1716
|
+
}
|
|
1717
|
+
if (logalot) {
|
|
1718
|
+
console.log(`${lc}[${currentFrameOrigin}] history slice: ${pretty(x)} (I: e5a9436fb66b0df3183bd6d81be2ca26)`);
|
|
1719
|
+
}
|
|
1720
|
+
x.msgStones.forEach(msgStone => {
|
|
1721
|
+
if (!msgStone.data) {
|
|
1722
|
+
throw new Error(`(UNEXPECTED) msgStone.data falsy? (E: 21406101f91847514cc759c8a7382f26)`);
|
|
1723
|
+
}
|
|
1724
|
+
if (msgStone.data.stage === SyncStage.ack) {
|
|
1725
|
+
const ackData = msgStone.data;
|
|
1726
|
+
if (ackData.pushOfferInfos && ackData.pushOfferInfos.length > 0) {
|
|
1727
|
+
ackData.pushOfferInfos.forEach(info => {
|
|
1728
|
+
info.addrs.forEach(addr => fnAddPayloadAddr(addr));
|
|
1729
|
+
});
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
else if (msgStone.data.stage === SyncStage.delta) {
|
|
1733
|
+
const deltaData = msgStone.data;
|
|
1734
|
+
if (deltaData.payloadAddrsDomain && deltaData.payloadAddrsDomain.length > 0) {
|
|
1735
|
+
deltaData.payloadAddrsDomain.forEach(addr => fnAddPayloadAddr(addr));
|
|
1736
|
+
}
|
|
1737
|
+
}
|
|
1738
|
+
});
|
|
1739
|
+
});
|
|
1677
1740
|
if (logalot) {
|
|
1678
|
-
console.log(`${lc}
|
|
1741
|
+
console.log(`${lc}[${currentFrameOrigin}] allPayloadAddrsDomainTransferred: ${allPayloadAddrsDomainTransferred.length > 0 ? allPayloadAddrsDomainTransferred.join(', ') : 'none'} (I: a1950eb3ca95bdc9ec18a4b8823e9826)`);
|
|
1742
|
+
}
|
|
1743
|
+
// at this point, we have a list of ALL payload addrs retrieved.
|
|
1744
|
+
let allPayloadIbGibsDomainTransferred = [];
|
|
1745
|
+
if (allPayloadAddrsDomainTransferred.length > 0) {
|
|
1746
|
+
const resGetAllTransferred = await getFromSpace({ addrs: allPayloadAddrsDomainTransferred, space: localTempSpace });
|
|
1747
|
+
if (resGetAllTransferred.success && resGetAllTransferred.ibGibs && resGetAllTransferred.ibGibs.length === allPayloadAddrsDomainTransferred.length) {
|
|
1748
|
+
allPayloadIbGibsDomainTransferred = resGetAllTransferred.ibGibs.concat();
|
|
1749
|
+
}
|
|
1750
|
+
else {
|
|
1751
|
+
// errored out, gather info
|
|
1752
|
+
if (!resGetAllTransferred.rawResultIbGib) {
|
|
1753
|
+
throw new Error(`(UNEXPECTED) !resGetAllTransferred.rawResultIbGib falsy? (E: dc6cf8729668f4fbe8c024f887d97a26)`);
|
|
1754
|
+
}
|
|
1755
|
+
const { addrsNotFound, addrsErrored, errors } = resGetAllTransferred.rawResultIbGib.data;
|
|
1756
|
+
throw new Error(`(UNEXPECTED) we couldn't get all addrs transferred throughout the saga from the tempspace (${localTempSpace.ib})? addrsNotFound: ${addrsNotFound ?? []}. addrsErrored: ${addrsErrored ?? []}. errors: ${errors ?? []}(E: 222e341e634862b4d88ae7282584d826)`);
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
// now we have all ibgibs transferred, first put them all the local space
|
|
1760
|
+
if (allPayloadIbGibsDomainTransferred.length === 0) {
|
|
1761
|
+
// nothing was synced
|
|
1762
|
+
if (logalot) {
|
|
1763
|
+
console.log(`${lc}[${currentFrameOrigin}] no changes on this end (I: fa30d18e83a87ee9e8487fbb5d632b26)`);
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
else {
|
|
1767
|
+
if (logalot) {
|
|
1768
|
+
console.log(`${lc}[${currentFrameOrigin}] ${allPayloadIbGibsDomainTransferred.length} changes detected (I: fa30d18e83a87ee9e8487fbb5d632b26)`);
|
|
1769
|
+
}
|
|
1770
|
+
if (logalot) {
|
|
1771
|
+
console.log(`${lc} put all into localSpace (${localSpace.ib}) starting... (I: d5e0d9870e380b61e80c729660058826)`);
|
|
1772
|
+
}
|
|
1773
|
+
const { payload_Dnas, payload_NonDnas } = await putInSpace_dnasThenNonDnas({
|
|
1774
|
+
ibGibs: allPayloadIbGibsDomainTransferred,
|
|
1775
|
+
space: localSpace
|
|
1776
|
+
});
|
|
1777
|
+
if (logalot) {
|
|
1778
|
+
console.log(`${lc} put all into localSpace (${localSpace.ib}) complete. (I: d5e0d9870e380b61e80c729660058826)`);
|
|
1779
|
+
}
|
|
1780
|
+
const { mapWithTjp_NoDna, mapWithTjp_YesDna, mapWithoutTjps } = splitPerTjpAndOrDna({ ibGibs: payload_NonDnas, filterPrimitives: true });
|
|
1781
|
+
// first register all non-tjp stones
|
|
1782
|
+
if (logalot) {
|
|
1783
|
+
console.log(`${lc} register mapWithoutTjps starting... (I: 2b84d8f8dda85adde88696d8419bf726)`);
|
|
1784
|
+
}
|
|
1785
|
+
const nontjps = Object.values(mapWithoutTjps);
|
|
1786
|
+
for (const nontjp of nontjps) {
|
|
1787
|
+
if (logalot) {
|
|
1788
|
+
console.log(`${lc} registering ${getIbGibAddr({ ibGib: nontjp })} (I: 4647b4f42d27cffe0fbfce8846755826)`);
|
|
1789
|
+
}
|
|
1790
|
+
await metaspace.registerNewIbGib({
|
|
1791
|
+
ibGib: nontjp,
|
|
1792
|
+
space: localSpace,
|
|
1793
|
+
});
|
|
1794
|
+
}
|
|
1795
|
+
if (logalot) {
|
|
1796
|
+
console.log(`${lc} mapWithoutTjps complete. (I: 2b84d8f8dda85adde88696d8419bf726)`);
|
|
1797
|
+
}
|
|
1798
|
+
// next register each timeline in order...
|
|
1799
|
+
// ...first the ones without dna...
|
|
1800
|
+
if (logalot) {
|
|
1801
|
+
console.log(`${lc} register mapWithTjp_NoDna starting... (I: 96e648e4db382499b8bfaa1b37c24826)`);
|
|
1802
|
+
}
|
|
1803
|
+
const timelinesByTjpAddr_NoDna = getTimelinesGroupedByTjp({ ibGibs: Object.values(mapWithTjp_NoDna) });
|
|
1804
|
+
const tjpAddrs_NoDna = Object.keys(timelinesByTjpAddr_NoDna);
|
|
1805
|
+
for (const tjpAddr_NoDna of tjpAddrs_NoDna) {
|
|
1806
|
+
const timelineIbGibs = timelinesByTjpAddr_NoDna[tjpAddr_NoDna];
|
|
1807
|
+
for (const ibGib of timelineIbGibs) {
|
|
1808
|
+
await metaspace.registerNewIbGib({
|
|
1809
|
+
ibGib,
|
|
1810
|
+
space: localSpace,
|
|
1811
|
+
});
|
|
1812
|
+
}
|
|
1813
|
+
}
|
|
1814
|
+
if (logalot) {
|
|
1815
|
+
console.log(`${lc} register mapWithTjp_NoDna complete. (I: 96e648e4db382499b8bfaa1b37c24826)`);
|
|
1816
|
+
}
|
|
1817
|
+
// ...then the ones WITH dna.
|
|
1818
|
+
if (logalot) {
|
|
1819
|
+
console.log(`${lc} register mapWithTjp_YesDna starting... (I: d54a820e9442dee4681f6228a6795926)`);
|
|
1820
|
+
}
|
|
1821
|
+
const timelinesByTjpAddr_YesDna = getTimelinesGroupedByTjp({ ibGibs: Object.values(mapWithTjp_YesDna) });
|
|
1822
|
+
const tjpAddrs_YesDna = Object.keys(timelinesByTjpAddr_YesDna);
|
|
1823
|
+
for (const tjpAddr_YesDna of tjpAddrs_YesDna) {
|
|
1824
|
+
const timelineIbGibs = timelinesByTjpAddr_YesDna[tjpAddr_YesDna];
|
|
1825
|
+
for (const ibGib of timelineIbGibs) {
|
|
1826
|
+
await metaspace.registerNewIbGib({
|
|
1827
|
+
ibGib,
|
|
1828
|
+
space: localSpace,
|
|
1829
|
+
});
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
if (logalot) {
|
|
1833
|
+
console.log(`${lc} register mapWithTjp_YesDna complete. (I: d54a820e9442dee4681f6228a6795926)`);
|
|
1834
|
+
}
|
|
1679
1835
|
}
|
|
1680
|
-
return { responseWasNull: true };
|
|
1681
1836
|
}
|
|
1682
1837
|
catch (error) {
|
|
1683
1838
|
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
@@ -1689,6 +1844,124 @@ export class SyncSagaCoordinator {
|
|
|
1689
1844
|
}
|
|
1690
1845
|
}
|
|
1691
1846
|
}
|
|
1847
|
+
async createCommitFrame({ sagaIbGib, errors, metaspace, mySpace, identity, }) {
|
|
1848
|
+
const lc = `[${this.createCommitFrame.name}]`;
|
|
1849
|
+
try {
|
|
1850
|
+
if (logalot) {
|
|
1851
|
+
console.log(`${lc} starting... (I: 48fc57c023f80122135a284855757526)`);
|
|
1852
|
+
}
|
|
1853
|
+
const commitData = errors && errors.length > 0 ?
|
|
1854
|
+
{
|
|
1855
|
+
// errored
|
|
1856
|
+
sagaId: sagaIbGib.data.uuid,
|
|
1857
|
+
stage: SyncStage.commit,
|
|
1858
|
+
success: false,
|
|
1859
|
+
errors,
|
|
1860
|
+
} :
|
|
1861
|
+
{
|
|
1862
|
+
// not errored
|
|
1863
|
+
sagaId: sagaIbGib.data.uuid,
|
|
1864
|
+
stage: SyncStage.commit,
|
|
1865
|
+
success: true,
|
|
1866
|
+
};
|
|
1867
|
+
const commitStone = await this.createSyncMsgStone({
|
|
1868
|
+
data: commitData,
|
|
1869
|
+
localSpace: mySpace,
|
|
1870
|
+
metaspace
|
|
1871
|
+
});
|
|
1872
|
+
const commitFrame = await this.evolveSyncSagaIbGib({
|
|
1873
|
+
prevSagaIbGib: sagaIbGib,
|
|
1874
|
+
msgStones: [commitStone],
|
|
1875
|
+
sessionIdentity: identity,
|
|
1876
|
+
localSpace: mySpace,
|
|
1877
|
+
metaspace,
|
|
1878
|
+
});
|
|
1879
|
+
return commitFrame;
|
|
1880
|
+
}
|
|
1881
|
+
catch (error) {
|
|
1882
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
1883
|
+
throw error;
|
|
1884
|
+
}
|
|
1885
|
+
finally {
|
|
1886
|
+
if (logalot) {
|
|
1887
|
+
console.log(`${lc} complete.`);
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1891
|
+
async handleCommitFrame({ sagaIbGib, mySpace, myTempSpace, metaspace, identity, }) {
|
|
1892
|
+
const lc = `${this.lc}[${this.handleCommitFrame.name}]`;
|
|
1893
|
+
try {
|
|
1894
|
+
if (logalot) {
|
|
1895
|
+
console.log(`${lc} starting... (I: e179573bdd881202f8ba3168da1c3826)`);
|
|
1896
|
+
}
|
|
1897
|
+
if (!sagaIbGib.data) {
|
|
1898
|
+
throw new Error(`(UNEXPECTED) sagaIbGib.data falsy? (E: cbc31dbb7d28b5b8c8cddb510d7d2826)`);
|
|
1899
|
+
}
|
|
1900
|
+
if (sagaIbGib.data.errors && sagaIbGib.data.errors.length > 0) {
|
|
1901
|
+
// our saga errored out but we already committed the darn
|
|
1902
|
+
// changes previously
|
|
1903
|
+
throw new Error(`not implemented...saga errored out on other end but we've already committed our changes. we need to implement undoing our changes, i.e., rollback commit, which basically is deleting all the payloads that we already put in in our previous commit. (E: e8eb789e0c08f0b3cf93607cb73e9f26)`);
|
|
1904
|
+
}
|
|
1905
|
+
else {
|
|
1906
|
+
// Sender Logic (Finalizing):
|
|
1907
|
+
// If we are here, we received a Commit frame from the Peer.
|
|
1908
|
+
// This implies the Peer has successfully committed.
|
|
1909
|
+
// We should now:
|
|
1910
|
+
// 1. Validate (implicitly done by receiving valid frame)
|
|
1911
|
+
// 2. Perform our own cleanup (Temp -> Dest, if applicable)
|
|
1912
|
+
// 3. Return saga completion.
|
|
1913
|
+
// one last validate entire history ?
|
|
1914
|
+
const history = await getFullSyncSagaHistory({
|
|
1915
|
+
sagaIbGib,
|
|
1916
|
+
space: mySpace,
|
|
1917
|
+
});
|
|
1918
|
+
const validationErrors = await validateFullSyncSagaHistory({
|
|
1919
|
+
history,
|
|
1920
|
+
});
|
|
1921
|
+
if (validationErrors.length > 0) {
|
|
1922
|
+
const errorCommitFrame = await this.createCommitFrame({
|
|
1923
|
+
sagaIbGib,
|
|
1924
|
+
metaspace,
|
|
1925
|
+
mySpace,
|
|
1926
|
+
identity,
|
|
1927
|
+
errors: validationErrors,
|
|
1928
|
+
});
|
|
1929
|
+
return { frame: errorCommitFrame, }; /* <<<< returns early */
|
|
1930
|
+
}
|
|
1931
|
+
await this.executeLocalCommit({
|
|
1932
|
+
commitFrame: sagaIbGib,
|
|
1933
|
+
sagaHistory: history,
|
|
1934
|
+
localSpace: mySpace,
|
|
1935
|
+
localTempSpace: myTempSpace,
|
|
1936
|
+
metaspace,
|
|
1937
|
+
});
|
|
1938
|
+
// todo: implement explicit cleanup logic here and in peer
|
|
1939
|
+
console.error(`${lc} NAG ERROR (NOT THROWN): implement cleanup logic, including add a cleanup method to the peer (E: 3a9a24befb98a981a88fbdbf52920e26)`);
|
|
1940
|
+
if (logalot) {
|
|
1941
|
+
console.log(`${lc} Peer committed. Finalizing saga locally. Saga Complete.`);
|
|
1942
|
+
}
|
|
1943
|
+
// the holy grail!
|
|
1944
|
+
return { sagaComplete: true };
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
catch (error) {
|
|
1948
|
+
const emsg = `${lc} ${extractErrorMsg(error)}`;
|
|
1949
|
+
console.error(emsg);
|
|
1950
|
+
const errorCommitFrame = await this.createCommitFrame({
|
|
1951
|
+
sagaIbGib,
|
|
1952
|
+
errors: [emsg],
|
|
1953
|
+
metaspace,
|
|
1954
|
+
mySpace,
|
|
1955
|
+
identity,
|
|
1956
|
+
});
|
|
1957
|
+
return { frame: errorCommitFrame };
|
|
1958
|
+
}
|
|
1959
|
+
finally {
|
|
1960
|
+
if (logalot) {
|
|
1961
|
+
console.log(`${lc} complete.`);
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1692
1965
|
// #endregion Handlers
|
|
1693
1966
|
async createSyncMsgStone({ data, localSpace, metaspace, }) {
|
|
1694
1967
|
const lc = `${this.lc}[${this.createSyncMsgStone.name}]`;
|
|
@@ -1720,6 +1993,69 @@ export class SyncSagaCoordinator {
|
|
|
1720
1993
|
}
|
|
1721
1994
|
}
|
|
1722
1995
|
}
|
|
1996
|
+
async getPayloadsForRequestedInfos({ deltaRequestAddrInfos, mySpace, }) {
|
|
1997
|
+
const lc = `${this.lc}[${this.getPayloadsForRequestedInfos.name}]`;
|
|
1998
|
+
try {
|
|
1999
|
+
if (logalot) {
|
|
2000
|
+
console.log(`${lc} starting... (I: 4fe13d0d80050f20a8b74ba80cee5826)`);
|
|
2001
|
+
}
|
|
2002
|
+
/**
|
|
2003
|
+
* graph of ibgibs we will send to the receiver. addr-based, so will
|
|
2004
|
+
* already be unique (no need to call `unique` on the domains
|
|
2005
|
+
* ibgibs)
|
|
2006
|
+
*/
|
|
2007
|
+
const outgoingPayloadIbGibsDomainGraph = {};
|
|
2008
|
+
for (const { addr, latestAddrAlreadyHave } of deltaRequestAddrInfos) {
|
|
2009
|
+
let deltaDepGraph;
|
|
2010
|
+
if (latestAddrAlreadyHave) {
|
|
2011
|
+
// already has some, so only get the delta
|
|
2012
|
+
// remember: if we didn't have the other's latest addr, then
|
|
2013
|
+
// this would be in the conflicts not requested addrs
|
|
2014
|
+
deltaDepGraph = await getDeltaDependencyGraph({
|
|
2015
|
+
ibGibAddr: addr,
|
|
2016
|
+
latestCommonFrameAddr: latestAddrAlreadyHave,
|
|
2017
|
+
space: mySpace,
|
|
2018
|
+
live: true,
|
|
2019
|
+
});
|
|
2020
|
+
}
|
|
2021
|
+
else {
|
|
2022
|
+
// doesn't have anything, so get the entire dependency graph
|
|
2023
|
+
// INEFFICIENT: we've already gotten all of the domain
|
|
2024
|
+
// dependencies in initDomainGraph, but getDependencyGraph
|
|
2025
|
+
// only works against a space so we are going to rerun this.
|
|
2026
|
+
// an optimization would be to adapt/create a new
|
|
2027
|
+
// getDependencyGraph to work against an existing flat ibgib
|
|
2028
|
+
// map.
|
|
2029
|
+
deltaDepGraph = await getDependencyGraph({
|
|
2030
|
+
ibGibAddr: addr,
|
|
2031
|
+
space: mySpace,
|
|
2032
|
+
live: true,
|
|
2033
|
+
});
|
|
2034
|
+
}
|
|
2035
|
+
const depGraphSize = Object.keys(deltaDepGraph).length;
|
|
2036
|
+
if (depGraphSize === 0) {
|
|
2037
|
+
throw new Error(`(UNEXPECTED) couldn't get requested addrs in mySpace (${mySpace.ib})? How did the receiver know to ask for these addrs if they weren't in our original graph? (E: 281eaebcdf77dd73e8245b2872100826)`);
|
|
2038
|
+
}
|
|
2039
|
+
else {
|
|
2040
|
+
// we have dependencies!
|
|
2041
|
+
Object.values(deltaDepGraph).forEach(x => {
|
|
2042
|
+
outgoingPayloadIbGibsDomainGraph[getIbGibAddr({ ibGib: x })] = x;
|
|
2043
|
+
});
|
|
2044
|
+
}
|
|
2045
|
+
}
|
|
2046
|
+
const result = Object.values(outgoingPayloadIbGibsDomainGraph);
|
|
2047
|
+
return result;
|
|
2048
|
+
}
|
|
2049
|
+
catch (error) {
|
|
2050
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
2051
|
+
throw error;
|
|
2052
|
+
}
|
|
2053
|
+
finally {
|
|
2054
|
+
if (logalot) {
|
|
2055
|
+
console.log(`${lc} complete.`);
|
|
2056
|
+
}
|
|
2057
|
+
}
|
|
2058
|
+
}
|
|
1723
2059
|
/**
|
|
1724
2060
|
* Evolves the saga timeline with a new frame.
|
|
1725
2061
|
*/
|