amalgm 0.1.208 → 0.1.209
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.
|
@@ -17,7 +17,7 @@ const CLAIM_LIMIT = 16;
|
|
|
17
17
|
const CLAIM_LEASE_MS = 30_000;
|
|
18
18
|
const RETRY_MS = 1_000;
|
|
19
19
|
const REAUTHORIZE_MS = 30_000;
|
|
20
|
-
const REPO_OBJECT_REQUEST_TIMEOUT_MS =
|
|
20
|
+
const REPO_OBJECT_REQUEST_TIMEOUT_MS = 15_000;
|
|
21
21
|
|
|
22
22
|
function createSharedRealtimeTunnel({
|
|
23
23
|
send,
|
|
@@ -475,35 +475,45 @@ function createSharedRealtimeTunnel({
|
|
|
475
475
|
}
|
|
476
476
|
|
|
477
477
|
function handleRepoObjectStored(frame) {
|
|
478
|
-
const object = repoUploadInflight.get(frame.request_id)
|
|
478
|
+
const object = repoUploadInflight.get(frame.request_id)
|
|
479
|
+
|| [...repoUploadInflight.values()].find((entry) => entry.sha256 === frame.sha256);
|
|
479
480
|
if (!object || object.sha256 !== frame.sha256) return;
|
|
480
481
|
void localStateJson('POST', '/state/repo-objects/uploads/ack', {
|
|
481
482
|
resourceId: object.resourceId,
|
|
482
483
|
sha256: object.sha256,
|
|
483
484
|
})
|
|
484
485
|
.then(() => {
|
|
485
|
-
repoUploadInflight
|
|
486
|
+
for (const [requestId, entry] of repoUploadInflight) {
|
|
487
|
+
if (entry.sha256 === object.sha256) repoUploadInflight.delete(requestId);
|
|
488
|
+
}
|
|
486
489
|
scheduleRepoObjects();
|
|
487
490
|
})
|
|
488
491
|
.catch(() => {
|
|
489
|
-
repoUploadInflight
|
|
492
|
+
for (const [requestId, entry] of repoUploadInflight) {
|
|
493
|
+
if (entry.sha256 === object.sha256) repoUploadInflight.delete(requestId);
|
|
494
|
+
}
|
|
490
495
|
scheduleRepoObjects(RETRY_MS);
|
|
491
496
|
});
|
|
492
497
|
}
|
|
493
498
|
|
|
494
499
|
function handleRepoObjectData(frame) {
|
|
495
|
-
const object = repoDownloadInflight.get(frame.request_id)
|
|
500
|
+
const object = repoDownloadInflight.get(frame.request_id)
|
|
501
|
+
|| [...repoDownloadInflight.values()].find((entry) => entry.sha256 === frame.sha256);
|
|
496
502
|
if (!object || object.sha256 !== frame.sha256) return;
|
|
497
503
|
void localStateJson('POST', '/state/repo-objects/downloads/receive', {
|
|
498
504
|
resourceId: object.resourceId,
|
|
499
505
|
sha256: object.sha256,
|
|
500
506
|
dataBase64: frame.data_b64,
|
|
501
507
|
}).then(() => {
|
|
502
|
-
repoDownloadInflight
|
|
508
|
+
for (const [requestId, entry] of repoDownloadInflight) {
|
|
509
|
+
if (entry.sha256 === object.sha256) repoDownloadInflight.delete(requestId);
|
|
510
|
+
}
|
|
503
511
|
scheduleRepoObjects();
|
|
504
512
|
}).catch((error) => {
|
|
505
513
|
warn(`repo object ${object.sha256} was not stored locally: ${error?.message || error}`);
|
|
506
|
-
repoDownloadInflight
|
|
514
|
+
for (const [requestId, entry] of repoDownloadInflight) {
|
|
515
|
+
if (entry.sha256 === object.sha256) repoDownloadInflight.delete(requestId);
|
|
516
|
+
}
|
|
507
517
|
scheduleRepoObjects(RETRY_MS);
|
|
508
518
|
});
|
|
509
519
|
}
|
package/package.json
CHANGED
|
@@ -127,6 +127,7 @@ test('repo object chunks retry when an acknowledgement is lost', async () => {
|
|
|
127
127
|
const uploadBytes = Buffer.from('retry this content-addressed chunk');
|
|
128
128
|
const uploadSha = crypto.createHash('sha256').update(uploadBytes).digest('hex');
|
|
129
129
|
const resourceId = 'shr_cp1abcdefghijklmnopqrstuvwx';
|
|
130
|
+
let acknowledgements = 0;
|
|
130
131
|
const server = http.createServer((req, res) => {
|
|
131
132
|
req.resume();
|
|
132
133
|
req.on('end', () => {
|
|
@@ -147,6 +148,9 @@ test('repo object chunks retry when an acknowledgement is lost', async () => {
|
|
|
147
148
|
}));
|
|
148
149
|
} else if (req.url === '/state/repo-objects/downloads/claim') {
|
|
149
150
|
res.end('{"download":null}');
|
|
151
|
+
} else if (req.url === '/state/repo-objects/uploads/ack') {
|
|
152
|
+
acknowledgements += 1;
|
|
153
|
+
res.end('{"changed":true,"completed":true}');
|
|
150
154
|
} else {
|
|
151
155
|
res.end('{}');
|
|
152
156
|
}
|
|
@@ -173,6 +177,13 @@ test('repo object chunks retry when an acknowledgement is lost', async () => {
|
|
|
173
177
|
const puts = frames.filter((frame) => frame.type === 'repo.object.put');
|
|
174
178
|
assert.notEqual(puts[0].request_id, puts[1].request_id);
|
|
175
179
|
assert.equal(puts[0].sha256, puts[1].sha256);
|
|
180
|
+
tunnel.handleFrame({
|
|
181
|
+
type: 'repo.object.stored',
|
|
182
|
+
request_id: puts[0].request_id,
|
|
183
|
+
sha256: uploadSha,
|
|
184
|
+
bytes: uploadBytes.length,
|
|
185
|
+
});
|
|
186
|
+
await until(() => acknowledgements === 1, 'the late upload acknowledgement');
|
|
176
187
|
} finally {
|
|
177
188
|
tunnel.stop();
|
|
178
189
|
server.close();
|
|
@@ -137,6 +137,19 @@ test('only a value different from both the materialized baseline and the rail is
|
|
|
137
137
|
branches: [{ name: 'main', oid: oidA }],
|
|
138
138
|
},
|
|
139
139
|
), false);
|
|
140
|
+
assert.equal(hasLocalContribution(
|
|
141
|
+
{
|
|
142
|
+
head: { branch: 'main', oid: oidB, detached: false },
|
|
143
|
+
refs: [{ name: 'main', oid: oidB }],
|
|
144
|
+
},
|
|
145
|
+
remoteAdvance,
|
|
146
|
+
baseline,
|
|
147
|
+
null,
|
|
148
|
+
{
|
|
149
|
+
head: { branch: 'main', oid: oidB, detached: false },
|
|
150
|
+
branches: [{ name: 'main', oid: oidB }],
|
|
151
|
+
},
|
|
152
|
+
), false);
|
|
140
153
|
assert.equal(hasLocalContribution(
|
|
141
154
|
local,
|
|
142
155
|
plan,
|
|
@@ -231,7 +231,11 @@ function hasLocalContribution(card, plan, baseline, checkpoint = null, previousC
|
|
|
231
231
|
const atBaseline = baseline
|
|
232
232
|
&& card.head?.branch === baseline.branch
|
|
233
233
|
&& card.head?.oid === baseline.baseOid;
|
|
234
|
-
|
|
234
|
+
const alreadyPublished = previousCard && samePosition(card, previousCard);
|
|
235
|
+
const reversesPublishedSharedPosition = previousCard
|
|
236
|
+
&& samePosition(previousCard, plan.card)
|
|
237
|
+
&& !alreadyPublished;
|
|
238
|
+
if ((!onRail && !atBaseline && !alreadyPublished) || reversesPublishedSharedPosition) return true;
|
|
235
239
|
|
|
236
240
|
const currentRefs = oidMap(card.refs);
|
|
237
241
|
const railRefs = oidMap(plan.branches);
|
|
@@ -246,12 +250,14 @@ function hasLocalContribution(card, plan, baseline, checkpoint = null, previousC
|
|
|
246
250
|
const shared = railRefs.get(name) ?? null;
|
|
247
251
|
const previous = baselineRefs.get(name) ?? null;
|
|
248
252
|
const published = previousRefs.get(name) ?? null;
|
|
253
|
+
const matchesBaseline = baselineRefs.has(name) && current === previous;
|
|
254
|
+
const matchesPublished = previousRefs.has(name) && current === published;
|
|
249
255
|
const reversesPublishedSharedValue = previousRefs.has(name)
|
|
250
256
|
&& published === shared
|
|
251
257
|
&& current !== published;
|
|
252
258
|
if (
|
|
253
259
|
current !== shared
|
|
254
|
-
&& (!
|
|
260
|
+
&& ((!matchesBaseline && !matchesPublished) || reversesPublishedSharedValue)
|
|
255
261
|
) return true;
|
|
256
262
|
}
|
|
257
263
|
|