@substrat-run/kernel 0.146.0 → 0.148.0
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/audit-outcome.d.ts +1 -1
- package/dist/audit-outcome.d.ts.map +1 -1
- package/dist/audit-outcome.js +4 -2
- package/dist/audit-outcome.js.map +1 -1
- package/dist/export-break.d.ts +137 -0
- package/dist/export-break.d.ts.map +1 -0
- package/dist/export-break.js +219 -0
- package/dist/export-break.js.map +1 -0
- package/dist/index.d.ts +17 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -5
- package/dist/index.js.map +1 -1
- package/dist/install-receipts.d.ts +116 -0
- package/dist/install-receipts.d.ts.map +1 -0
- package/dist/install-receipts.js +162 -0
- package/dist/install-receipts.js.map +1 -0
- package/dist/invocation-line.d.ts +63 -0
- package/dist/invocation-line.d.ts.map +1 -1
- package/dist/invocation-line.js +44 -0
- package/dist/invocation-line.js.map +1 -1
- package/dist/map-bounded.d.ts +8 -0
- package/dist/map-bounded.d.ts.map +1 -0
- package/dist/map-bounded.js +16 -0
- package/dist/map-bounded.js.map +1 -0
- package/dist/meters.d.ts +5 -0
- package/dist/meters.d.ts.map +1 -1
- package/dist/meters.js +0 -0
- package/dist/meters.js.map +1 -1
- package/dist/peer.js +1 -1
- package/dist/platform-sweep.d.ts +52 -363
- package/dist/platform-sweep.d.ts.map +1 -1
- package/dist/platform-sweep.js +49 -564
- package/dist/platform-sweep.js.map +1 -1
- package/dist/schedule-state.d.ts +91 -0
- package/dist/schedule-state.d.ts.map +1 -0
- package/dist/schedule-state.js +118 -0
- package/dist/schedule-state.js.map +1 -0
- package/dist/scope-copy-ledger.d.ts +29 -0
- package/dist/scope-copy-ledger.d.ts.map +1 -1
- package/dist/scope-copy-ledger.js +23 -0
- package/dist/scope-copy-ledger.js.map +1 -1
- package/dist/scope-copy.d.ts.map +1 -1
- package/dist/scope-copy.js +3 -2
- package/dist/scope-copy.js.map +1 -1
- package/dist/scope-host.d.ts +199 -14
- package/dist/scope-host.d.ts.map +1 -1
- package/dist/scope-host.js.map +1 -1
- package/dist/scope-identity.d.ts +68 -0
- package/dist/scope-identity.d.ts.map +1 -0
- package/dist/scope-identity.js +75 -0
- package/dist/scope-identity.js.map +1 -0
- package/dist/scope-store.d.ts +139 -0
- package/dist/scope-store.d.ts.map +1 -0
- package/dist/scope-store.js +237 -0
- package/dist/scope-store.js.map +1 -0
- package/dist/spine-restore.js +1 -1
- package/dist/sql-limits.d.ts.map +1 -1
- package/dist/sql-limits.js +10 -1
- package/dist/sql-limits.js.map +1 -1
- package/dist/storage-gauge.d.ts +21 -2
- package/dist/storage-gauge.d.ts.map +1 -1
- package/dist/storage-gauge.js +73 -6
- package/dist/storage-gauge.js.map +1 -1
- package/dist/store-kind-releases.d.ts +137 -0
- package/dist/store-kind-releases.d.ts.map +1 -0
- package/dist/store-kind-releases.js +252 -0
- package/dist/store-kind-releases.js.map +1 -0
- package/dist/upload-link.d.ts +89 -0
- package/dist/upload-link.d.ts.map +1 -0
- package/dist/upload-link.js +277 -0
- package/dist/upload-link.js.map +1 -0
- package/dist/vertical-scope-stores.d.ts +43 -0
- package/dist/vertical-scope-stores.d.ts.map +1 -0
- package/dist/vertical-scope-stores.js +195 -0
- package/dist/vertical-scope-stores.js.map +1 -0
- package/package.json +2 -2
package/dist/storage-gauge.js
CHANGED
|
@@ -38,6 +38,16 @@ export const SCOPE_STORAGE_DDL = `
|
|
|
38
38
|
attempted_at TEXT NOT NULL,
|
|
39
39
|
error TEXT
|
|
40
40
|
);
|
|
41
|
+
CREATE TABLE IF NOT EXISTS _substrat_scope_store_storage (
|
|
42
|
+
scope_id TEXT NOT NULL,
|
|
43
|
+
binding TEXT NOT NULL,
|
|
44
|
+
day TEXT NOT NULL,
|
|
45
|
+
tenant_id TEXT NOT NULL,
|
|
46
|
+
bytes INTEGER NOT NULL,
|
|
47
|
+
read_at TEXT NOT NULL,
|
|
48
|
+
PRIMARY KEY (scope_id, binding, day)
|
|
49
|
+
);
|
|
50
|
+
CREATE INDEX IF NOT EXISTS _substrat_scope_store_storage_tenant ON _substrat_scope_store_storage (tenant_id, day);
|
|
41
51
|
`;
|
|
42
52
|
/**
|
|
43
53
|
* The statuses a scope that holds a store can be in: every status but `provisioning` (no
|
|
@@ -113,9 +123,43 @@ export function recordScopeStorageRows(sql, readings) {
|
|
|
113
123
|
ON CONFLICT (scope_id, day) DO UPDATE SET bytes = excluded.bytes, read_at = excluded.read_at
|
|
114
124
|
WHERE excluded.read_at >= _substrat_scope_storage.read_at
|
|
115
125
|
RETURNING 1`, [storageGaugeDay(readAt), r.bytes, readAt, r.scopeId, r.tenantId]).length;
|
|
126
|
+
if (r.stores)
|
|
127
|
+
recordScopeStoreRows(sql, r, readAt);
|
|
116
128
|
}
|
|
117
129
|
return recorded;
|
|
118
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* The row that says a day's stores were measured (#2212), whatever they held. Its binding is one
|
|
133
|
+
* no declaration can name (a binding is `[A-Z][A-Z0-9_]*`), and the read skips it. Without it a
|
|
134
|
+
* day that measured no store at all leaves no row, and the latest day with one, older, is billed.
|
|
135
|
+
*/
|
|
136
|
+
const MEASURED_DAY = '';
|
|
137
|
+
/**
|
|
138
|
+
* Replace one scope's store samples for the day. A binding that is gone leaves no row, and an
|
|
139
|
+
* empty list leaves only the measured-day marker. A reading older than the day's recorded one
|
|
140
|
+
* changes nothing, as the database sample's upsert keeps the newer reading.
|
|
141
|
+
*/
|
|
142
|
+
function recordScopeStoreRows(sql, reading, readAt) {
|
|
143
|
+
const day = storageGaugeDay(readAt);
|
|
144
|
+
const newer = sql(`SELECT 1 FROM _substrat_scope_store_storage
|
|
145
|
+
WHERE scope_id = ? AND tenant_id = ? AND day = ? AND read_at > ? LIMIT 1`, [reading.scopeId, reading.tenantId, day, readAt]);
|
|
146
|
+
if (newer.length > 0)
|
|
147
|
+
return;
|
|
148
|
+
sql(`DELETE FROM _substrat_scope_store_storage
|
|
149
|
+
WHERE scope_id = ? AND tenant_id = ? AND day = ?
|
|
150
|
+
AND EXISTS (
|
|
151
|
+
SELECT 1 FROM scopes
|
|
152
|
+
WHERE scope_id = ? AND tenant_id = ? AND ${holdsStoreSql()}
|
|
153
|
+
)`, [reading.scopeId, reading.tenantId, day, reading.scopeId, reading.tenantId]);
|
|
154
|
+
const rows = (reading.stores ?? []).filter((store) => Number.isInteger(store.bytes) && store.bytes >= 0 && store.binding.length > 0);
|
|
155
|
+
for (const store of [{ binding: MEASURED_DAY, bytes: 0 }, ...rows]) {
|
|
156
|
+
sql(`INSERT INTO _substrat_scope_store_storage (scope_id, binding, day, tenant_id, bytes, read_at)
|
|
157
|
+
SELECT scope_id, ?, ?, tenant_id, ?, ? FROM scopes
|
|
158
|
+
WHERE scope_id = ? AND tenant_id = ? AND ${holdsStoreSql()}
|
|
159
|
+
ON CONFLICT (scope_id, binding, day) DO UPDATE SET bytes = excluded.bytes, read_at = excluded.read_at
|
|
160
|
+
WHERE excluded.read_at >= _substrat_scope_store_storage.read_at`, [store.binding, day, store.bytes, readAt, reading.scopeId, reading.tenantId]);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
119
163
|
/** Read samples — see `ScopeStorageFilter`. Every row is parsed on the way out. */
|
|
120
164
|
export function listScopeStorageRows(sql, filter = {}) {
|
|
121
165
|
const where = [holdsStoreSql('s.')];
|
|
@@ -181,17 +225,38 @@ export function listScopeStorageAttemptRows(sql, tenantId) {
|
|
|
181
225
|
error: r.error,
|
|
182
226
|
}));
|
|
183
227
|
}
|
|
184
|
-
/** Delete at most `limit` samples older than retention, oldest first. Returns how many went. */
|
|
228
|
+
/** Delete at most `limit` samples older than retention, oldest first, across both tables. Returns how many went. */
|
|
185
229
|
export function pruneScopeStorageRows(sql, nowMs, limit) {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
230
|
+
const horizon = storageRetentionHorizon(nowMs);
|
|
231
|
+
const capped = assertRowLimit('limit', limit);
|
|
232
|
+
const databases = sql(boundedRetentionDelete('_substrat_scope_storage', 'day'), [horizon, capped]).length;
|
|
233
|
+
const remaining = capped - databases;
|
|
234
|
+
const stores = remaining > 0
|
|
235
|
+
? sql(boundedRetentionDelete('_substrat_scope_store_storage', 'day'), [horizon, remaining]).length
|
|
236
|
+
: 0;
|
|
237
|
+
return databases + stores;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Bindings on the latest day that measured stores for the scope. A binding absent that day has
|
|
241
|
+
* stopped, and a day that measured none leaves only its marker, which is not a binding.
|
|
242
|
+
*/
|
|
243
|
+
export function listScopeStoreStorageRows(sql, tenantId) {
|
|
244
|
+
const rows = sql(`SELECT g.tenant_id, g.bytes, g.read_at
|
|
245
|
+
FROM scopes s
|
|
246
|
+
JOIN _substrat_scope_store_storage g ON g.scope_id = s.scope_id AND g.tenant_id = s.tenant_id
|
|
247
|
+
AND g.day = (
|
|
248
|
+
SELECT MAX(m.day) FROM _substrat_scope_store_storage m
|
|
249
|
+
WHERE m.scope_id = g.scope_id AND m.tenant_id = g.tenant_id
|
|
250
|
+
)
|
|
251
|
+
WHERE g.binding <> '' AND ${holdsStoreSql('s.')}${tenantId ? ' AND s.tenant_id = ?' : ''}
|
|
252
|
+
ORDER BY g.scope_id, g.binding`, tenantId ? [tenantId] : []);
|
|
253
|
+
return rows.map((r) => ({ tenantId: r.tenant_id, bytes: r.bytes, readAt: r.read_at }));
|
|
190
254
|
}
|
|
191
255
|
/** Drop a scope's samples and attempt: its storage is gone, so its history describes nothing billable. */
|
|
192
256
|
export function forgetScopeStorage(sql, scopeId) {
|
|
193
257
|
sql('DELETE FROM _substrat_scope_storage WHERE scope_id = ?', [scopeId]);
|
|
194
258
|
sql('DELETE FROM _substrat_scope_storage_attempts WHERE scope_id = ?', [scopeId]);
|
|
259
|
+
sql('DELETE FROM _substrat_scope_store_storage WHERE scope_id = ?', [scopeId]);
|
|
195
260
|
}
|
|
196
261
|
/**
|
|
197
262
|
* Fold latest samples into one gauge. `total` is the caller's count of stored scopes
|
|
@@ -199,7 +264,7 @@ export function forgetScopeStorage(sql, scopeId) {
|
|
|
199
264
|
* (`listScopeStorage({ latest })`), and attempts the latest per stored scope
|
|
200
265
|
* (`listScopeStorageAttempts`).
|
|
201
266
|
*/
|
|
202
|
-
export function foldStorageGauge(samples, total, attempts = []) {
|
|
267
|
+
export function foldStorageGauge(samples, total, attempts = [], stores) {
|
|
203
268
|
let failing = 0;
|
|
204
269
|
let lastFailed = null;
|
|
205
270
|
for (const a of attempts) {
|
|
@@ -219,6 +284,7 @@ export function foldStorageGauge(samples, total, attempts = []) {
|
|
|
219
284
|
if (newest === null || s.readAt > newest)
|
|
220
285
|
newest = s.readAt;
|
|
221
286
|
}
|
|
287
|
+
const storeBytes = stores?.reduce((sum, row) => sum + row.bytes, 0);
|
|
222
288
|
return {
|
|
223
289
|
basis: 'scope-databases',
|
|
224
290
|
excluded: [...STORAGE_EXCLUSIONS],
|
|
@@ -229,6 +295,7 @@ export function foldStorageGauge(samples, total, attempts = []) {
|
|
|
229
295
|
newestReadAt: newest,
|
|
230
296
|
failing,
|
|
231
297
|
lastFailedAt: lastFailed,
|
|
298
|
+
...(stores && stores.length > 0 ? { stores: { bytes: storeBytes ?? 0, sampled: stores.length } } : {}),
|
|
232
299
|
};
|
|
233
300
|
}
|
|
234
301
|
//# sourceMappingURL=storage-gauge.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage-gauge.js","sourceRoot":"","sources":["../src/storage-gauge.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,kBAAkB,GAKnB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAEzE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG
|
|
1
|
+
{"version":3,"file":"storage-gauge.js","sourceRoot":"","sources":["../src/storage-gauge.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,kBAAkB,GAKnB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAEzE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BhC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,CAAU,CAAC;AAE/F;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,KAA6D;IACtF,IAAI,CAAE,qBAA2C,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;QAAE,OAAO,KAAK,CAAC;IACvF,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,UAAU,IAAI,KAAK,CAAC,MAAM,KAAK,WAAW,CAAC,IAAI,KAAK,CAAC,kBAAkB,KAAK,cAAc,CAAC,CAAC;AACzH,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,aAAa,CAAC,KAAK,GAAG,EAAE;IACtC,OAAO,CACL,GAAG,KAAK,qEAAqE;QAC7E,IAAI,KAAK,2CAA2C,KAAK,yCAAyC,CACnG,CAAC;AACJ,CAAC;AAED,0GAA0G;AAC1G,MAAM,CAAC,MAAM,8BAA8B,GAAG,EAAE,CAAC;AAEjD,yEAAyE;AACzE,MAAM,CAAC,MAAM,yBAAyB,GAAG,GAAG,CAAC;AAE7C,kFAAkF;AAClF,MAAM,CAAC,MAAM,yBAAyB,GAAG,MAAM,CAAC;AAChD,MAAM,CAAC,MAAM,6BAA6B,GAAG,KAAK,CAAC;AAyCnD,wCAAwC;AACxC,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,OAAO,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACrD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAAa;IACnD,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5B,MAAM,KAAK,GAAG,GAAG,CAAC,WAAW,EAAE,GAAG,8BAA8B,CAAC;IACjE,oEAAoE;IACpE,MAAM,OAAO,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,cAAc,EAAE,EAAE,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC;IACpF,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,cAAc,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACzH,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,sBAAsB,CAAC,GAAiB,EAAE,QAA6C;IACrG,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;QAChD,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,KAAK,IAAI,IAAI,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;QACzE,GAAG,CACD;;mDAE6C,aAAa,EAAE;;qFAEmB,EAC/E,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,IAAI,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CACjD,CAAC;QACF,IAAI,CAAC,EAAE;YAAE,SAAS;QAClB,QAAQ,IAAI,GAAG,CACb;;mDAE6C,aAAa,EAAE;;;mBAG/C,EACb,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAClE,CAAC,MAAM,CAAC;QACT,IAAI,CAAC,CAAC,MAAM;YAAE,oBAAoB,CAAC,GAAG,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;IACrD,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;GAIG;AACH,MAAM,YAAY,GAAG,EAAE,CAAC;AAExB;;;;GAIG;AACH,SAAS,oBAAoB,CAAC,GAAiB,EAAE,OAAiC,EAAE,MAAc;IAChG,MAAM,GAAG,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IACpC,MAAM,KAAK,GAAG,GAAG,CACf;+EAC2E,EAC3E,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,EAAE,GAAG,EAAE,MAAM,CAAC,CACjD,CAAC;IACF,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO;IAC7B,GAAG,CACD;;;;sDAIkD,aAAa,EAAE;UAC3D,EACN,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,EAAE,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,CAC5E,CAAC;IACF,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,MAAM,CACxC,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,IAAI,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CACzF,CAAC;IACF,KAAK,MAAM,KAAK,IAAI,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;QACnE,GAAG,CACD;;mDAE6C,aAAa,EAAE;;wEAEM,EAClE,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,CAC7E,CAAC;IACJ,CAAC;AACH,CAAC;AAUD,mFAAmF;AACnF,MAAM,UAAU,oBAAoB,CAAC,GAAiB,EAAE,MAAM,GAAuB,EAAE;IACrF,MAAM,KAAK,GAAa,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAwB,EAAE,CAAC;IACvC,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACpB,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAC9B,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC/B,CAAC;IACD,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAC7B,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IACD,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,2FAA2F;IAC3F,wFAAwF;IACxF,kFAAkF;IAClF,IAAI,SAAS,GAAG,EAAE,CAAC;IACnB,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClB,SAAS,GAAG,+FAA+F,CAAC;IAC9G,CAAC;SAAM,CAAC;QACN,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YACjB,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YACzB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;QACD,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YACjB,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YACzB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;QACD,MAAM,KAAK,GAAG,cAAc,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,IAAI,6BAA6B,CAAC,CAAC;QACrF,IAAI,GAAG,UAAU,CAAC;QAClB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,yBAAyB,CAAC,CAAC,CAAC;IAC1D,CAAC;IACD,mFAAmF;IACnF,+DAA+D;IAC/D,MAAM,IAAI,GAAG,GAAG,CACd;;gGAE4F,SAAS;cAC3F,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC;kCACC,IAAI,EAAE,EACpC,MAAM,CACQ,CAAC;IACjB,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACpB,kBAAkB,CAAC,KAAK,CAAC;QACvB,QAAQ,EAAE,CAAC,CAAC,SAAS;QACrB,OAAO,EAAE,CAAC,CAAC,QAAQ;QACnB,GAAG,EAAE,CAAC,CAAC,GAAG;QACV,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,MAAM,EAAE,CAAC,CAAC,OAAO;KAClB,CAAC,CACH,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,2BAA2B,CAAC,GAAiB,EAAE,QAAmB;IAChF,MAAM,IAAI,GAAG,GAAG,CACd;;;cAGU,aAAa,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,EAAE;0BAChD,EACtB,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAC8D,CAAC;IAC3F,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACtB,QAAQ,EAAE,CAAC,CAAC,SAAqB;QACjC,OAAO,EAAE,CAAC,CAAC,QAAmB;QAC9B,WAAW,EAAE,CAAC,CAAC,YAAY;QAC3B,KAAK,EAAE,CAAC,CAAC,KAAK;KACf,CAAC,CAAC,CAAC;AACN,CAAC;AAED,oHAAoH;AACpH,MAAM,UAAU,qBAAqB,CAAC,GAAiB,EAAE,KAAa,EAAE,KAAa;IACnF,MAAM,OAAO,GAAG,uBAAuB,CAAC,KAAK,CAAC,CAAC;IAC/C,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC9C,MAAM,SAAS,GAAG,GAAG,CAAC,sBAAsB,CAAC,yBAAyB,EAAE,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;IAC1G,MAAM,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC;IACrC,MAAM,MAAM,GAAG,SAAS,GAAG,CAAC;QAC1B,CAAC,CAAC,GAAG,CAAC,sBAAsB,CAAC,+BAA+B,EAAE,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,MAAM;QAClG,CAAC,CAAC,CAAC,CAAC;IACN,OAAO,SAAS,GAAG,MAAM,CAAC;AAC5B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CACvC,GAAiB,EACjB,QAAmB;IAEnB,MAAM,IAAI,GAAG,GAAG,CACd;;;;;;;kCAO8B,aAAa,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,EAAE;qCACzD,EACjC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CACgC,CAAC;IAC7D,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,SAAqB,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;AACrG,CAAC;AAED,0GAA0G;AAC1G,MAAM,UAAU,kBAAkB,CAAC,GAAiB,EAAE,OAAe;IACnE,GAAG,CAAC,wDAAwD,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IACzE,GAAG,CAAC,iEAAiE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAClF,GAAG,CAAC,8DAA8D,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;AACjF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAC9B,OAAqD,EACrD,KAAa,EACb,QAAQ,GAA6D,EAAE,EACvE,MAAqC;IAErC,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,IAAI,UAAU,GAAkB,IAAI,CAAC;IACrC,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAC,CAAC,KAAK,KAAK,IAAI;YAAE,SAAS;QAC/B,OAAO,IAAI,CAAC,CAAC;QACb,IAAI,UAAU,KAAK,IAAI,IAAI,CAAC,CAAC,WAAW,GAAG,UAAU;YAAE,UAAU,GAAG,CAAC,CAAC,WAAW,CAAC;IACpF,CAAC;IACD,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,MAAM,GAAkB,IAAI,CAAC;IACjC,IAAI,MAAM,GAAkB,IAAI,CAAC;IACjC,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC;QACjB,IAAI,MAAM,KAAK,IAAI,IAAI,CAAC,CAAC,MAAM,GAAG,MAAM;YAAE,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;QAC5D,IAAI,MAAM,KAAK,IAAI,IAAI,CAAC,CAAC,MAAM,GAAG,MAAM;YAAE,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9D,CAAC;IACD,MAAM,UAAU,GAAG,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACpE,OAAO;QACL,KAAK,EAAE,iBAAiB;QACxB,QAAQ,EAAE,CAAC,GAAG,kBAAkB,CAAC;QACjC,KAAK;QACL,OAAO,EAAE,OAAO,CAAC,MAAM;QACvB,KAAK;QACL,YAAY,EAAE,MAAsC;QACpD,YAAY,EAAE,MAAsC;QACpD,OAAO;QACP,YAAY,EAAE,UAA0C;QACxD,GAAG,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,UAAU,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACvG,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import type { SwitchSql } from './system-switch.js';
|
|
2
|
+
/** Interpolated into both adapters' directory DDL, so `lint:spine-ddl` sees one spelling on each side. */
|
|
3
|
+
export declare const STORE_KIND_RELEASES_DDL = "\n CREATE TABLE IF NOT EXISTS store_kind_releases (\n kind TEXT NOT NULL,\n sha256 TEXT NOT NULL,\n source_commit TEXT NOT NULL,\n uploaded_by TEXT NOT NULL,\n uploaded_at TEXT NOT NULL,\n PRIMARY KEY (kind, sha256)\n );\n CREATE TABLE IF NOT EXISTS store_kind_rollouts (\n kind TEXT NOT NULL,\n seq INTEGER NOT NULL,\n sha256 TEXT NOT NULL,\n action TEXT NOT NULL,\n from_sha256 TEXT,\n previous_good_sha256 TEXT,\n state TEXT NOT NULL,\n actor TEXT NOT NULL,\n -- The hold the rollout runs under: a rolling row whose holder holds nothing has stopped.\n holder TEXT NOT NULL,\n started_at TEXT NOT NULL,\n ended_at TEXT,\n detail TEXT,\n PRIMARY KEY (kind, seq)\n );\n CREATE TABLE IF NOT EXISTS store_kind_current (\n kind TEXT PRIMARY KEY,\n sha256 TEXT NOT NULL,\n seq INTEGER NOT NULL\n );\n CREATE TABLE IF NOT EXISTS store_kind_holds (\n kind TEXT NOT NULL,\n holder TEXT NOT NULL,\n mode TEXT NOT NULL,\n expires_at INTEGER NOT NULL,\n PRIMARY KEY (kind, holder)\n );\n";
|
|
4
|
+
/** A stored release: its bytes are kept elsewhere under `<kind>/<sha256>`. */
|
|
5
|
+
export interface StoreKindReleaseRecord {
|
|
6
|
+
readonly kind: string;
|
|
7
|
+
readonly sha256: string;
|
|
8
|
+
readonly sourceCommit: string;
|
|
9
|
+
readonly uploadedBy: string;
|
|
10
|
+
readonly uploadedAt: string;
|
|
11
|
+
}
|
|
12
|
+
export type StoreKindRolloutAction = 'rollout' | 'rollback';
|
|
13
|
+
/**
|
|
14
|
+
* `paused`: the request's batch ran out with verticals left to walk. Nothing failed; the fleet is
|
|
15
|
+
* part way, and posting the same rollout (or the same rollback) again continues it.
|
|
16
|
+
*/
|
|
17
|
+
export type StoreKindRolloutState = 'rolling' | 'good' | 'failed' | 'diverged' | 'paused';
|
|
18
|
+
export interface StoreKindRolloutRecord {
|
|
19
|
+
readonly kind: string;
|
|
20
|
+
readonly seq: number;
|
|
21
|
+
readonly sha256: string;
|
|
22
|
+
readonly action: StoreKindRolloutAction;
|
|
23
|
+
/** The current good release when the rollout began; null for a kind's first. */
|
|
24
|
+
readonly fromSha256: string | null;
|
|
25
|
+
/** Where a rollback from this release, once it is good, returns to; null when nowhere. */
|
|
26
|
+
readonly previousGoodSha256: string | null;
|
|
27
|
+
readonly state: StoreKindRolloutState;
|
|
28
|
+
readonly actor: string;
|
|
29
|
+
readonly startedAt: string;
|
|
30
|
+
readonly endedAt: string | null;
|
|
31
|
+
readonly detail: string | null;
|
|
32
|
+
}
|
|
33
|
+
export interface StoreKindState {
|
|
34
|
+
/** The release the last good rollout reached, and that rollout. Null before any. */
|
|
35
|
+
readonly current: {
|
|
36
|
+
readonly sha256: string;
|
|
37
|
+
readonly seq: number;
|
|
38
|
+
readonly previousGoodSha256: string | null;
|
|
39
|
+
} | null;
|
|
40
|
+
/** Every rollout, oldest first. */
|
|
41
|
+
readonly rollouts: StoreKindRolloutRecord[];
|
|
42
|
+
/** Where a rollback goes now (see `storeKindStateIn`); null when nowhere. */
|
|
43
|
+
readonly rollbackTarget: string | null;
|
|
44
|
+
/** The target of a rollback that paused or diverged part way, until it ends good. Unless it is the current release, it blocks rollouts. */
|
|
45
|
+
readonly unfinishedRollback: string | null;
|
|
46
|
+
}
|
|
47
|
+
export type StoreKindHoldMode = 'shared' | 'exclusive';
|
|
48
|
+
/** A stored release, or undefined. */
|
|
49
|
+
export declare function storeKindReleaseIn(db: SwitchSql, kind: string, sha256: string): StoreKindReleaseRecord | undefined;
|
|
50
|
+
/**
|
|
51
|
+
* Record that a release's bytes are stored. The same sha256 again is the same release, and the
|
|
52
|
+
* row already written is returned as it stands (`created: false`). The same sha256 from another
|
|
53
|
+
* commit is refused (`conflict`): one bundle has one source the reviewer reads.
|
|
54
|
+
*/
|
|
55
|
+
export declare function recordStoreKindReleaseIn(db: SwitchSql, input: {
|
|
56
|
+
kind: string;
|
|
57
|
+
sha256: string;
|
|
58
|
+
sourceCommit: string;
|
|
59
|
+
actor: string;
|
|
60
|
+
at: string;
|
|
61
|
+
}): {
|
|
62
|
+
record: StoreKindReleaseRecord;
|
|
63
|
+
created: boolean;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* The kind's current release, every rollout, and where a rollback goes now.
|
|
67
|
+
*
|
|
68
|
+
* With `nowMs`, a `rolling` row whose holder no longer holds the kind exclusively is reported as
|
|
69
|
+
* `diverged` (read-time only, nothing is written): its holder stopped, and its scripts may be on
|
|
70
|
+
* either release. The next rollout's begin writes that state.
|
|
71
|
+
*
|
|
72
|
+
* `rollbackTarget` is, in order:
|
|
73
|
+
* - the target of a rollback that is the newest attempt since the current release, a `failed` one
|
|
74
|
+
* aside, and ended `paused` or `diverged` (`unfinishedRollback`): posting the rollback again
|
|
75
|
+
* continues it, and never turns it around onto the release it is leaving. A failed attempt moved
|
|
76
|
+
* nothing, or returned what it moved, so it changes nothing here. No rollout may begin while a
|
|
77
|
+
* rollback to an earlier release is unfinished, `paused` or `diverged` (`beginStoreKindRolloutIn`):
|
|
78
|
+
* it is finished first, by posting it again. A rollback onto the current release (undoing a
|
|
79
|
+
* diverged rollout) does not block a rollout. A rollback to an earlier release cannot meet the
|
|
80
|
+
* schema rule (the route refuses one below the current schema), but one onto the current release
|
|
81
|
+
* can, and then it never finishes, so going forward must stay open;
|
|
82
|
+
* - the current release itself, when a rollout since it ended `diverged` or `paused`: the fleet may
|
|
83
|
+
* be mixed, and undoing that rollout means converging every script back on the release it was
|
|
84
|
+
* healthy on, never going past it;
|
|
85
|
+
* - otherwise the immediately previous good release.
|
|
86
|
+
* An unfinished attempt never changes what "previous good" means.
|
|
87
|
+
*/
|
|
88
|
+
export declare function storeKindStateIn(db: SwitchSql, kind: string, nowMs?: number): StoreKindState;
|
|
89
|
+
/**
|
|
90
|
+
* Take, or renew, a hold on a kind. Answers false when another holder's live hold excludes it: an
|
|
91
|
+
* exclusive one for any request, or any one for an exclusive request. A lapsed hold is dropped
|
|
92
|
+
* first. Asking in the other mode than the one held is refused.
|
|
93
|
+
*
|
|
94
|
+
* `renew` only extends a hold the holder still holds: a holder whose lease lapsed gets false, even
|
|
95
|
+
* when nobody took the kind since, because a lapsed holder cannot know what happened meanwhile.
|
|
96
|
+
* With `rolloutSeq` it also answers false unless that rollout is still `rolling`, so a rollout
|
|
97
|
+
* whose row another holder ended stops instead of moving scripts the state no longer describes.
|
|
98
|
+
*/
|
|
99
|
+
export declare function holdStoreKindIn(db: SwitchSql, input: {
|
|
100
|
+
kind: string;
|
|
101
|
+
holder: string;
|
|
102
|
+
mode: StoreKindHoldMode;
|
|
103
|
+
nowMs: number;
|
|
104
|
+
ttlMs: number;
|
|
105
|
+
renew?: boolean;
|
|
106
|
+
rolloutSeq?: number;
|
|
107
|
+
}): boolean;
|
|
108
|
+
/** Drop a hold. Dropping one already gone is not an error. */
|
|
109
|
+
export declare function releaseStoreKindHoldIn(db: SwitchSql, input: {
|
|
110
|
+
kind: string;
|
|
111
|
+
holder: string;
|
|
112
|
+
}): void;
|
|
113
|
+
/**
|
|
114
|
+
* Begin a rollout or a rollback of a stored release, as the exclusive holder. A rollout left
|
|
115
|
+
* `rolling` by an earlier holder ends `diverged` here: its scripts may be on either release, and
|
|
116
|
+
* this rollout reaches all of them. A rollback must name the current release's previous good one.
|
|
117
|
+
*/
|
|
118
|
+
export declare function beginStoreKindRolloutIn(db: SwitchSql, input: {
|
|
119
|
+
kind: string;
|
|
120
|
+
sha256: string;
|
|
121
|
+
action: StoreKindRolloutAction;
|
|
122
|
+
holder: string;
|
|
123
|
+
actor: string;
|
|
124
|
+
at: string;
|
|
125
|
+
nowMs: number;
|
|
126
|
+
}): StoreKindRolloutRecord;
|
|
127
|
+
/** End a rollout the caller began, as the exclusive holder. A good one makes its release current. */
|
|
128
|
+
export declare function finishStoreKindRolloutIn(db: SwitchSql, input: {
|
|
129
|
+
kind: string;
|
|
130
|
+
seq: number;
|
|
131
|
+
holder: string;
|
|
132
|
+
state: Exclude<StoreKindRolloutState, 'rolling'>;
|
|
133
|
+
detail: string | null;
|
|
134
|
+
at: string;
|
|
135
|
+
nowMs: number;
|
|
136
|
+
}): StoreKindRolloutRecord;
|
|
137
|
+
//# sourceMappingURL=store-kind-releases.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store-kind-releases.d.ts","sourceRoot":"","sources":["../src/store-kind-releases.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A store kind's releases, its rollouts and the holds that serialize them (D-63, #2300), shared by
|
|
3
|
+
* both adapters' directories.
|
|
4
|
+
*
|
|
5
|
+
* - `store_kind_releases`: a release's bytes were stored (the bytes themselves live outside the
|
|
6
|
+
* directory, keyed by kind and sha256). Insert-only: who uploaded a release, and from which
|
|
7
|
+
* commit, is never rewritten.
|
|
8
|
+
* - `store_kind_rollouts`: one row per attempt to move every script of the kind to a release, in
|
|
9
|
+
* `seq` order. A row is `rolling` until its holder ends it `good`, `failed` or `diverged`.
|
|
10
|
+
* - `store_kind_current`: the release the last `good` rollout moved every script to.
|
|
11
|
+
*
|
|
12
|
+
* "The immediately previous good release" (D-63) is recorded, never derived from an ordering:
|
|
13
|
+
* each rollout row names `previous_good_sha256`, the release a rollback from it returns to. A
|
|
14
|
+
* rollout of T from current F records F; a rollback goes to the current row's previous good X, and
|
|
15
|
+
* records X's own previous good, so after r1 → r2 → r3 one rollback reaches r2 and the next r1.
|
|
16
|
+
*
|
|
17
|
+
* A hold is a lease: `exclusive` for a rollout or a rollback, `shared` for a push or serve that
|
|
18
|
+
* rebuilds a script at the release it runs, which a rollout must not interleave with (a rebuild
|
|
19
|
+
* that read the old release and uploaded after the rollout moved the script would revert it).
|
|
20
|
+
* A begin or finish is refused unless the caller still holds the kind exclusively, so a holder
|
|
21
|
+
* whose lease lapsed cannot write over the next one; its `rolling` row reads as `diverged` to the
|
|
22
|
+
* next rollout, which converges every script again.
|
|
23
|
+
*/
|
|
24
|
+
import { substratError } from '@substrat-run/contracts';
|
|
25
|
+
/** Interpolated into both adapters' directory DDL, so `lint:spine-ddl` sees one spelling on each side. */
|
|
26
|
+
export const STORE_KIND_RELEASES_DDL = `
|
|
27
|
+
CREATE TABLE IF NOT EXISTS store_kind_releases (
|
|
28
|
+
kind TEXT NOT NULL,
|
|
29
|
+
sha256 TEXT NOT NULL,
|
|
30
|
+
source_commit TEXT NOT NULL,
|
|
31
|
+
uploaded_by TEXT NOT NULL,
|
|
32
|
+
uploaded_at TEXT NOT NULL,
|
|
33
|
+
PRIMARY KEY (kind, sha256)
|
|
34
|
+
);
|
|
35
|
+
CREATE TABLE IF NOT EXISTS store_kind_rollouts (
|
|
36
|
+
kind TEXT NOT NULL,
|
|
37
|
+
seq INTEGER NOT NULL,
|
|
38
|
+
sha256 TEXT NOT NULL,
|
|
39
|
+
action TEXT NOT NULL,
|
|
40
|
+
from_sha256 TEXT,
|
|
41
|
+
previous_good_sha256 TEXT,
|
|
42
|
+
state TEXT NOT NULL,
|
|
43
|
+
actor TEXT NOT NULL,
|
|
44
|
+
-- The hold the rollout runs under: a rolling row whose holder holds nothing has stopped.
|
|
45
|
+
holder TEXT NOT NULL,
|
|
46
|
+
started_at TEXT NOT NULL,
|
|
47
|
+
ended_at TEXT,
|
|
48
|
+
detail TEXT,
|
|
49
|
+
PRIMARY KEY (kind, seq)
|
|
50
|
+
);
|
|
51
|
+
CREATE TABLE IF NOT EXISTS store_kind_current (
|
|
52
|
+
kind TEXT PRIMARY KEY,
|
|
53
|
+
sha256 TEXT NOT NULL,
|
|
54
|
+
seq INTEGER NOT NULL
|
|
55
|
+
);
|
|
56
|
+
CREATE TABLE IF NOT EXISTS store_kind_holds (
|
|
57
|
+
kind TEXT NOT NULL,
|
|
58
|
+
holder TEXT NOT NULL,
|
|
59
|
+
mode TEXT NOT NULL,
|
|
60
|
+
expires_at INTEGER NOT NULL,
|
|
61
|
+
PRIMARY KEY (kind, holder)
|
|
62
|
+
);
|
|
63
|
+
`;
|
|
64
|
+
const rolloutOf = (r) => ({
|
|
65
|
+
kind: r.kind,
|
|
66
|
+
seq: Number(r.seq),
|
|
67
|
+
sha256: r.sha256,
|
|
68
|
+
action: r.action,
|
|
69
|
+
fromSha256: r.from_sha256,
|
|
70
|
+
previousGoodSha256: r.previous_good_sha256,
|
|
71
|
+
state: r.state,
|
|
72
|
+
actor: r.actor,
|
|
73
|
+
startedAt: r.started_at,
|
|
74
|
+
endedAt: r.ended_at,
|
|
75
|
+
detail: r.detail,
|
|
76
|
+
});
|
|
77
|
+
const ROLLOUT_COLUMNS = 'kind, seq, sha256, action, from_sha256, previous_good_sha256, state, actor, started_at, ended_at, detail';
|
|
78
|
+
function rolloutAt(db, kind, seq) {
|
|
79
|
+
const [row] = db.all(`SELECT ${ROLLOUT_COLUMNS} FROM store_kind_rollouts WHERE kind = ? AND seq = ?`, kind, seq);
|
|
80
|
+
return row ? rolloutOf(row) : undefined;
|
|
81
|
+
}
|
|
82
|
+
/** A stored release, or undefined. */
|
|
83
|
+
export function storeKindReleaseIn(db, kind, sha256) {
|
|
84
|
+
const [row] = db.all('SELECT kind, sha256, source_commit, uploaded_by, uploaded_at FROM store_kind_releases WHERE kind = ? AND sha256 = ?', kind, sha256);
|
|
85
|
+
return row
|
|
86
|
+
? { kind: row.kind, sha256: row.sha256, sourceCommit: row.source_commit, uploadedBy: row.uploaded_by, uploadedAt: row.uploaded_at }
|
|
87
|
+
: undefined;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Record that a release's bytes are stored. The same sha256 again is the same release, and the
|
|
91
|
+
* row already written is returned as it stands (`created: false`). The same sha256 from another
|
|
92
|
+
* commit is refused (`conflict`): one bundle has one source the reviewer reads.
|
|
93
|
+
*/
|
|
94
|
+
export function recordStoreKindReleaseIn(db, input) {
|
|
95
|
+
const held = storeKindReleaseIn(db, input.kind, input.sha256);
|
|
96
|
+
if (held) {
|
|
97
|
+
if (held.sourceCommit !== input.sourceCommit) {
|
|
98
|
+
throw substratError('conflict', `release ${input.sha256} of '${input.kind}' is stored as built from ${held.sourceCommit}, not ${input.sourceCommit}`);
|
|
99
|
+
}
|
|
100
|
+
return { record: held, created: false };
|
|
101
|
+
}
|
|
102
|
+
db.run('INSERT INTO store_kind_releases (kind, sha256, source_commit, uploaded_by, uploaded_at) VALUES (?, ?, ?, ?, ?)', input.kind, input.sha256, input.sourceCommit, input.actor, input.at);
|
|
103
|
+
return { record: storeKindReleaseIn(db, input.kind, input.sha256), created: true };
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* The kind's current release, every rollout, and where a rollback goes now.
|
|
107
|
+
*
|
|
108
|
+
* With `nowMs`, a `rolling` row whose holder no longer holds the kind exclusively is reported as
|
|
109
|
+
* `diverged` (read-time only, nothing is written): its holder stopped, and its scripts may be on
|
|
110
|
+
* either release. The next rollout's begin writes that state.
|
|
111
|
+
*
|
|
112
|
+
* `rollbackTarget` is, in order:
|
|
113
|
+
* - the target of a rollback that is the newest attempt since the current release, a `failed` one
|
|
114
|
+
* aside, and ended `paused` or `diverged` (`unfinishedRollback`): posting the rollback again
|
|
115
|
+
* continues it, and never turns it around onto the release it is leaving. A failed attempt moved
|
|
116
|
+
* nothing, or returned what it moved, so it changes nothing here. No rollout may begin while a
|
|
117
|
+
* rollback to an earlier release is unfinished, `paused` or `diverged` (`beginStoreKindRolloutIn`):
|
|
118
|
+
* it is finished first, by posting it again. A rollback onto the current release (undoing a
|
|
119
|
+
* diverged rollout) does not block a rollout. A rollback to an earlier release cannot meet the
|
|
120
|
+
* schema rule (the route refuses one below the current schema), but one onto the current release
|
|
121
|
+
* can, and then it never finishes, so going forward must stay open;
|
|
122
|
+
* - the current release itself, when a rollout since it ended `diverged` or `paused`: the fleet may
|
|
123
|
+
* be mixed, and undoing that rollout means converging every script back on the release it was
|
|
124
|
+
* healthy on, never going past it;
|
|
125
|
+
* - otherwise the immediately previous good release.
|
|
126
|
+
* An unfinished attempt never changes what "previous good" means.
|
|
127
|
+
*/
|
|
128
|
+
export function storeKindStateIn(db, kind, nowMs) {
|
|
129
|
+
const live = nowMs === undefined
|
|
130
|
+
? undefined
|
|
131
|
+
: new Set(db.all("SELECT holder FROM store_kind_holds WHERE kind = ? AND mode = 'exclusive' AND expires_at > ?", kind, nowMs).map((h) => h.holder));
|
|
132
|
+
const rows = db.all(`SELECT ${ROLLOUT_COLUMNS}, holder FROM store_kind_rollouts WHERE kind = ? ORDER BY seq`, kind);
|
|
133
|
+
const rollouts = rows.map((r) => live && r.state === 'rolling' && !(r.holder && live.has(r.holder))
|
|
134
|
+
? rolloutOf({ ...r, state: 'diverged', detail: 'its holder no longer holds the kind; the rollout stopped before it ended' })
|
|
135
|
+
: rolloutOf(r));
|
|
136
|
+
const [current] = db.all('SELECT sha256, seq FROM store_kind_current WHERE kind = ?', kind);
|
|
137
|
+
if (!current)
|
|
138
|
+
return { current: null, rollouts, rollbackTarget: null, unfinishedRollback: null };
|
|
139
|
+
const seq = Number(current.seq);
|
|
140
|
+
const row = rollouts.find((r) => r.seq === seq);
|
|
141
|
+
const previousGoodSha256 = row?.previousGoodSha256 ?? null;
|
|
142
|
+
const since = rollouts.filter((r) => r.seq > seq);
|
|
143
|
+
// A failed attempt moved nothing, or returned what it moved, so it never decides what comes next.
|
|
144
|
+
const newest = since.filter((r) => r.state !== 'failed').at(-1);
|
|
145
|
+
const unfinishedRollback = newest?.action === 'rollback' && (newest.state === 'paused' || newest.state === 'diverged') ? newest.sha256 : null;
|
|
146
|
+
const mixed = since.some((r) => r.state === 'diverged' || r.state === 'paused');
|
|
147
|
+
return {
|
|
148
|
+
current: { sha256: current.sha256, seq, previousGoodSha256 },
|
|
149
|
+
rollouts,
|
|
150
|
+
rollbackTarget: unfinishedRollback ?? (mixed ? current.sha256 : previousGoodSha256),
|
|
151
|
+
unfinishedRollback,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Take, or renew, a hold on a kind. Answers false when another holder's live hold excludes it: an
|
|
156
|
+
* exclusive one for any request, or any one for an exclusive request. A lapsed hold is dropped
|
|
157
|
+
* first. Asking in the other mode than the one held is refused.
|
|
158
|
+
*
|
|
159
|
+
* `renew` only extends a hold the holder still holds: a holder whose lease lapsed gets false, even
|
|
160
|
+
* when nobody took the kind since, because a lapsed holder cannot know what happened meanwhile.
|
|
161
|
+
* With `rolloutSeq` it also answers false unless that rollout is still `rolling`, so a rollout
|
|
162
|
+
* whose row another holder ended stops instead of moving scripts the state no longer describes.
|
|
163
|
+
*/
|
|
164
|
+
export function holdStoreKindIn(db, input) {
|
|
165
|
+
if (!(input.ttlMs > 0))
|
|
166
|
+
throw substratError('validation_failed', 'a store-kind hold needs a positive lifetime');
|
|
167
|
+
db.run('DELETE FROM store_kind_holds WHERE kind = ? AND expires_at <= ?', input.kind, input.nowMs);
|
|
168
|
+
const live = db.all('SELECT holder, mode FROM store_kind_holds WHERE kind = ?', input.kind);
|
|
169
|
+
const own = live.find((h) => h.holder === input.holder);
|
|
170
|
+
if (own && own.mode !== input.mode) {
|
|
171
|
+
throw substratError('conflict', `holder ${input.holder} holds '${input.kind}' ${own.mode}, not ${input.mode}`);
|
|
172
|
+
}
|
|
173
|
+
if ((input.renew || input.rolloutSeq !== undefined) && !own)
|
|
174
|
+
return false;
|
|
175
|
+
if (input.rolloutSeq !== undefined && rolloutAt(db, input.kind, input.rolloutSeq)?.state !== 'rolling')
|
|
176
|
+
return false;
|
|
177
|
+
const others = live.filter((h) => h.holder !== input.holder);
|
|
178
|
+
if (input.mode === 'exclusive' ? others.length > 0 : others.some((h) => h.mode === 'exclusive'))
|
|
179
|
+
return false;
|
|
180
|
+
db.run(`INSERT INTO store_kind_holds (kind, holder, mode, expires_at) VALUES (?, ?, ?, ?)
|
|
181
|
+
ON CONFLICT (kind, holder) DO UPDATE SET expires_at = excluded.expires_at`, input.kind, input.holder, input.mode, input.nowMs + input.ttlMs);
|
|
182
|
+
return true;
|
|
183
|
+
}
|
|
184
|
+
/** Drop a hold. Dropping one already gone is not an error. */
|
|
185
|
+
export function releaseStoreKindHoldIn(db, input) {
|
|
186
|
+
db.run('DELETE FROM store_kind_holds WHERE kind = ? AND holder = ?', input.kind, input.holder);
|
|
187
|
+
}
|
|
188
|
+
function assertExclusive(db, kind, holder, nowMs) {
|
|
189
|
+
const [row] = db.all("SELECT 1 AS held FROM store_kind_holds WHERE kind = ? AND holder = ? AND mode = 'exclusive' AND expires_at > ?", kind, holder, nowMs);
|
|
190
|
+
if (!row)
|
|
191
|
+
throw substratError('conflict', `'${kind}' is not held exclusively by ${holder}`);
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Begin a rollout or a rollback of a stored release, as the exclusive holder. A rollout left
|
|
195
|
+
* `rolling` by an earlier holder ends `diverged` here: its scripts may be on either release, and
|
|
196
|
+
* this rollout reaches all of them. A rollback must name the current release's previous good one.
|
|
197
|
+
*/
|
|
198
|
+
export function beginStoreKindRolloutIn(db, input) {
|
|
199
|
+
assertExclusive(db, input.kind, input.holder, input.nowMs);
|
|
200
|
+
if (!storeKindReleaseIn(db, input.kind, input.sha256)) {
|
|
201
|
+
throw substratError('not_found', `release ${input.sha256} of '${input.kind}' is not stored`);
|
|
202
|
+
}
|
|
203
|
+
db.run(`UPDATE store_kind_rollouts SET state = 'diverged', ended_at = ?, detail = 'its holder stopped before the rollout ended'
|
|
204
|
+
WHERE kind = ? AND state = 'rolling'`, input.at, input.kind);
|
|
205
|
+
const { current, rollbackTarget, unfinishedRollback } = storeKindStateIn(db, input.kind, input.nowMs);
|
|
206
|
+
// A rollback under way to an earlier release blocks every rollout until it ends good. One onto
|
|
207
|
+
// the current release (undoing a diverged rollout) does not: if a script refuses to go below its
|
|
208
|
+
// schema, that rollback can never finish, and going forward is the way out.
|
|
209
|
+
if (input.action === 'rollout' && unfinishedRollback && unfinishedRollback !== current?.sha256) {
|
|
210
|
+
throw substratError('conflict', `a rollback of '${input.kind}' to ${unfinishedRollback} is part way through; post the rollback again to finish it before any rollout`);
|
|
211
|
+
}
|
|
212
|
+
let previousGood;
|
|
213
|
+
if (input.action === 'rollback') {
|
|
214
|
+
if (!current || !rollbackTarget)
|
|
215
|
+
throw substratError('conflict', `'${input.kind}' has no previous good release to roll back to`);
|
|
216
|
+
if (rollbackTarget !== input.sha256) {
|
|
217
|
+
throw substratError('conflict', `a rollback of '${input.kind}' returns to ${rollbackTarget}, not ${input.sha256}`);
|
|
218
|
+
}
|
|
219
|
+
if (input.sha256 === current.sha256) {
|
|
220
|
+
// Undoing a diverged rollout: back onto the current release, whose previous good stays.
|
|
221
|
+
previousGood = current.previousGoodSha256;
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
const [made] = db.all(`SELECT previous_good_sha256 FROM store_kind_rollouts
|
|
225
|
+
WHERE kind = ? AND sha256 = ? AND state = 'good' ORDER BY seq DESC LIMIT 1`, input.kind, input.sha256);
|
|
226
|
+
previousGood = made?.previous_good_sha256 ?? null;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
// Rolling out the current release again (a resume) keeps where a rollback from it returns to.
|
|
231
|
+
previousGood = current ? (current.sha256 === input.sha256 ? current.previousGoodSha256 : current.sha256) : null;
|
|
232
|
+
}
|
|
233
|
+
const next = Number(db.all('SELECT COALESCE(MAX(seq), 0) + 1 AS next FROM store_kind_rollouts WHERE kind = ?', input.kind)[0].next);
|
|
234
|
+
db.run(`INSERT INTO store_kind_rollouts (${ROLLOUT_COLUMNS}, holder) VALUES (?, ?, ?, ?, ?, ?, 'rolling', ?, ?, NULL, NULL, ?)`, input.kind, next, input.sha256, input.action, current?.sha256 ?? null, previousGood, input.actor, input.at, input.holder);
|
|
235
|
+
return rolloutAt(db, input.kind, next);
|
|
236
|
+
}
|
|
237
|
+
/** End a rollout the caller began, as the exclusive holder. A good one makes its release current. */
|
|
238
|
+
export function finishStoreKindRolloutIn(db, input) {
|
|
239
|
+
assertExclusive(db, input.kind, input.holder, input.nowMs);
|
|
240
|
+
const row = rolloutAt(db, input.kind, input.seq);
|
|
241
|
+
if (!row)
|
|
242
|
+
throw substratError('not_found', `'${input.kind}' has no rollout ${input.seq}`);
|
|
243
|
+
if (row.state !== 'rolling')
|
|
244
|
+
throw substratError('conflict', `rollout ${input.seq} of '${input.kind}' already ended ${row.state}`);
|
|
245
|
+
db.run('UPDATE store_kind_rollouts SET state = ?, ended_at = ?, detail = ? WHERE kind = ? AND seq = ?', input.state, input.at, input.detail, input.kind, input.seq);
|
|
246
|
+
if (input.state === 'good') {
|
|
247
|
+
db.run(`INSERT INTO store_kind_current (kind, sha256, seq) VALUES (?, ?, ?)
|
|
248
|
+
ON CONFLICT (kind) DO UPDATE SET sha256 = excluded.sha256, seq = excluded.seq`, input.kind, row.sha256, input.seq);
|
|
249
|
+
}
|
|
250
|
+
return rolloutAt(db, input.kind, input.seq);
|
|
251
|
+
}
|
|
252
|
+
//# sourceMappingURL=store-kind-releases.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store-kind-releases.js","sourceRoot":"","sources":["../src/store-kind-releases.ts"],"names":[],"mappings":"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"}
|