sliftutils 1.7.42 → 1.7.43
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/index.d.ts +16 -0
- package/misc/dist/environment.ts.cache +2 -2
- package/misc/dist/zip.ts.cache +2 -2
- package/package.json +1 -1
- package/render-utils/dist/observer.tsx.cache +2 -2
- package/storage/BulkDatabase2/dist/BulkDatabaseBase.ts.cache +2 -2
- package/storage/BulkDatabase2/dist/BulkDatabaseFormat.ts.cache +2 -2
- package/storage/BulkDatabase2/dist/BulkDatabaseMerge.ts.cache +2 -2
- package/storage/BulkDatabase2/dist/BulkDatabaseReader.ts.cache +2 -2
- package/storage/BulkDatabase2/dist/LoadedIndex.ts.cache +2 -2
- package/storage/BulkDatabase2/dist/WriteOverlay.ts.cache +2 -2
- package/storage/BulkDatabase2/dist/blockCache.ts.cache +2 -2
- package/storage/BulkDatabase2/dist/mergeLock.ts.cache +2 -2
- package/storage/BulkDatabase2/dist/mergeMarkers.ts.cache +2 -2
- package/storage/BulkDatabase2/dist/streamLog.ts.cache +2 -2
- package/storage/BulkDatabase2/dist/syncClient.ts.cache +2 -2
- package/storage/dist/ArchivesDisk.ts.cache +2 -2
- package/storage/dist/FileFolderAPI.tsx.cache +2 -2
- package/storage/dist/IndexedDBFileFolderAPI.ts.cache +2 -2
- package/storage/dist/JSONStorage.ts.cache +2 -2
- package/storage/dist/PendingManager.tsx.cache +2 -2
- package/storage/dist/TransactionStorage.ts.cache +2 -2
- package/storage/dist/fileSystemPointer.ts.cache +2 -2
- package/storage/dist/remoteFileStorage.ts.cache +2 -2
- package/storage/remoteStorage/createArchives.d.ts +7 -0
- package/storage/remoteStorage/createArchives.ts +5 -0
- package/storage/remoteStorage/deployTakeover.ts +1 -1
- package/storage/remoteStorage/dist/ArchivesRemote.ts.cache +2 -2
- package/storage/remoteStorage/dist/ArchivesUrl.ts.cache +2 -2
- package/storage/remoteStorage/dist/blobStore.ts.cache +2 -2
- package/storage/remoteStorage/dist/cliArgs.ts.cache +2 -2
- package/storage/remoteStorage/dist/createArchives.ts.cache +9 -4
- package/storage/remoteStorage/dist/deployTakeover.ts.cache +4 -4
- package/storage/remoteStorage/dist/intermediateSources.ts.cache +2 -2
- package/storage/remoteStorage/dist/remoteConfig.ts.cache +2 -2
- package/storage/remoteStorage/dist/storageClientController.ts.cache +2 -2
- package/storage/remoteStorage/dist/storageController.ts.cache +8 -3
- package/storage/remoteStorage/dist/storageServerState.ts.cache +67 -10
- package/storage/remoteStorage/storageController.d.ts +4 -0
- package/storage/remoteStorage/storageController.ts +6 -1
- package/storage/remoteStorage/storageServerState.d.ts +5 -0
- package/storage/remoteStorage/storageServerState.ts +63 -7
|
@@ -52,6 +52,10 @@ export declare const RemoteStorageController: import("socket-function/SocketFunc
|
|
|
52
52
|
getAccessState: (account: string) => Promise<AccessState>;
|
|
53
53
|
listRequestsForIP: (account: string, ip: string) => Promise<AccessRequest[]>;
|
|
54
54
|
grantAccess: (requestId: string) => Promise<TrustRecord>;
|
|
55
|
+
adminListActiveBuckets: () => Promise<{
|
|
56
|
+
account: string;
|
|
57
|
+
bucketName: string;
|
|
58
|
+
}[]>;
|
|
55
59
|
adminListRequests: (ip: string) => Promise<AccessRequest[]>;
|
|
56
60
|
adminGrantAccess: (requestId: string) => Promise<TrustRecord>;
|
|
57
61
|
get: (account: string, bucketName: string, path: string, range?: {
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
getStorageServerConfig, getTrust, getRequests, getLoadedBucket, writeBucketFile,
|
|
13
13
|
deleteBucketFile, assertWritesAllowed, assertMutable, LoadedBucket,
|
|
14
14
|
getBucketConfig, listAccountBuckets, ServerBucketInfo, clearAccountWriteStats,
|
|
15
|
-
getActiveBucket, activateBucket, ActiveBucketInfo,
|
|
15
|
+
getActiveBucket, activateBucket, ActiveBucketInfo, getActiveBucketKeys,
|
|
16
16
|
} from "./storageServerState";
|
|
17
17
|
import { StorageClientController } from "./storageClientController";
|
|
18
18
|
|
|
@@ -257,6 +257,10 @@ class RemoteStorageControllerBase {
|
|
|
257
257
|
throw new Error(`No access request found with id ${JSON.stringify(requestId)}. It may have already been granted or expired.`);
|
|
258
258
|
}
|
|
259
259
|
|
|
260
|
+
/** Admin (so only this machine's own processes can call it): the buckets this process has loaded. A deploy successor asks its predecessor for this, so it activates exactly the buckets that are in use instead of every bucket on disk. */
|
|
261
|
+
async adminListActiveBuckets(): Promise<{ account: string; bucketName: string }[]> {
|
|
262
|
+
return getActiveBucketKeys();
|
|
263
|
+
}
|
|
260
264
|
async adminListRequests(ip: string): Promise<AccessRequest[]> {
|
|
261
265
|
let requests = await getRequests();
|
|
262
266
|
return await requests.get(ip) || [];
|
|
@@ -511,6 +515,7 @@ export const RemoteStorageController = SocketFunction.register(
|
|
|
511
515
|
listRequestsForIP: { hooks: [accountAccess] },
|
|
512
516
|
grantAccess: {},
|
|
513
517
|
adminListRequests: { hooks: [adminAccess] },
|
|
518
|
+
adminListActiveBuckets: { hooks: [adminAccess] },
|
|
514
519
|
adminGrantAccess: { hooks: [adminAccess] },
|
|
515
520
|
get: { hooks: [accountAccess] },
|
|
516
521
|
get2: { hooks: [accountAccess] },
|
|
@@ -52,6 +52,11 @@ export declare function writeBucketFile(account: string, bucketName: string, fil
|
|
|
52
52
|
lastModified?: number;
|
|
53
53
|
}): Promise<void>;
|
|
54
54
|
export declare function getBucketConfig(bucket: LoadedBucket): ArchivesConfig;
|
|
55
|
+
/** Which buckets this process currently has loaded - what a deploy successor asks its predecessor for, so it activates exactly the buckets that are actually in use. */
|
|
56
|
+
export declare function getActiveBucketKeys(): {
|
|
57
|
+
account: string;
|
|
58
|
+
bucketName: string;
|
|
59
|
+
}[];
|
|
55
60
|
export declare function rebuildAllLoadedBuckets(): Promise<void>;
|
|
56
61
|
/** Started by deployTakeover once we are actually a deploy successor listening on an alternate port. Until then there are no switchover windows to write or expire, so nothing polls. */
|
|
57
62
|
export declare const startIntermediateMaintenance: {
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
import { ROUTING_FILE, parseRoutingData, serializeRemoteConfig, parseHostedUrl, replaceHostedUrlPort, buildFileUrl, getConfigVersion, getRoute, routeContains, routeIntersection } from "./remoteConfig";
|
|
16
16
|
import { injectIntermediateSource, expireIntermediateSources, getIntermediateSources, findSplitUrl, nextIntermediateVersion, INTERMEDIATE_EXPIRE_GRACE } from "./intermediateSources";
|
|
17
17
|
import { getTakeoverIntermediate } from "./deployTakeover";
|
|
18
|
-
import { createApiArchives } from "./createArchives";
|
|
18
|
+
import { createApiArchives, listServerActiveBucketKeys } from "./createArchives";
|
|
19
19
|
import type { IStorage } from "../IStorage";
|
|
20
20
|
import { broadcastRoutingChanged } from "./storageController";
|
|
21
21
|
import type { AccessRequest, TrustRecord } from "./storageController";
|
|
@@ -707,6 +707,14 @@ export function getBucketConfig(bucket: LoadedBucket): ArchivesConfig {
|
|
|
707
707
|
};
|
|
708
708
|
}
|
|
709
709
|
|
|
710
|
+
/** Which buckets this process currently has loaded - what a deploy successor asks its predecessor for, so it activates exactly the buckets that are actually in use. */
|
|
711
|
+
export function getActiveBucketKeys(): { account: string; bucketName: string }[] {
|
|
712
|
+
return [...buckets.keys()].map(key => {
|
|
713
|
+
let slash = key.indexOf("/");
|
|
714
|
+
return { account: key.slice(0, slash), bucketName: key.slice(slash + 1) };
|
|
715
|
+
});
|
|
716
|
+
}
|
|
717
|
+
|
|
710
718
|
export async function rebuildAllLoadedBuckets(): Promise<void> {
|
|
711
719
|
for (let key of [...buckets.keys()]) {
|
|
712
720
|
let slash = key.indexOf("/");
|
|
@@ -729,7 +737,7 @@ async function writeOwnRoutingConfig(loaded: LoadedBucket, updated: RemoteConfig
|
|
|
729
737
|
lastOwnConfigWrite.set(key, Date.now());
|
|
730
738
|
let version = nextIntermediateVersion(getConfigVersion(loaded.routing));
|
|
731
739
|
let next: RemoteConfig = { ...updated, version };
|
|
732
|
-
console.log(`Writing
|
|
740
|
+
console.log(`Writing ${ROUTING_FILE} for bucket ${key} (${reason}), version ${getConfigVersion(loaded.routing)} -> ${version}: ${JSON.stringify(next)}`);
|
|
733
741
|
let data = Buffer.from(serializeRemoteConfig(next));
|
|
734
742
|
await writeBucketFile(loaded.account, loaded.bucketName, ROUTING_FILE, data);
|
|
735
743
|
await propagateRoutingConfig(loaded, next, data);
|
|
@@ -749,7 +757,7 @@ async function propagateRoutingConfig(loaded: LoadedBucket, next: RemoteConfig,
|
|
|
749
757
|
for (let [url, source] of targets) {
|
|
750
758
|
try {
|
|
751
759
|
await createApiArchives(source).set(ROUTING_FILE, data);
|
|
752
|
-
console.log(`
|
|
760
|
+
console.log(`Wrote ${ROUTING_FILE} for bucket ${loaded.account}/${loaded.bucketName} to ${url}`);
|
|
753
761
|
} catch (e) {
|
|
754
762
|
console.error(`Propagating our routing config update to ${url} failed: ${(e as Error).stack ?? e}`);
|
|
755
763
|
}
|
|
@@ -759,8 +767,12 @@ async function propagateRoutingConfig(loaded: LoadedBucket, next: RemoteConfig,
|
|
|
759
767
|
async function maintainIntermediates(): Promise<void> {
|
|
760
768
|
let { domain, port } = getStorageServerConfig();
|
|
761
769
|
let takeover = getTakeoverIntermediate();
|
|
770
|
+
let written: string[] = [];
|
|
771
|
+
let alreadyCorrect: string[] = [];
|
|
772
|
+
let notOurs: string[] = [];
|
|
762
773
|
// ONLY buckets already in memory. A switchover must never load a bucket: loading starts its synchronization, and buckets nothing has touched (legacy ones especially) have no writes to hand off in the first place. One that does get used mid-switchover loads on that access, and the next pass gives it its window.
|
|
763
|
-
|
|
774
|
+
let keys = [...buckets.keys()];
|
|
775
|
+
for (let key of keys) {
|
|
764
776
|
let loadedPromise = buckets.get(key);
|
|
765
777
|
if (!loadedPromise) continue;
|
|
766
778
|
let loaded = await loadedPromise.catch(() => undefined);
|
|
@@ -768,6 +780,7 @@ async function maintainIntermediates(): Promise<void> {
|
|
|
768
780
|
let expired = expireIntermediateSources(loaded.routing, Date.now());
|
|
769
781
|
if (JSON.stringify(expired) !== JSON.stringify(loaded.routing)) {
|
|
770
782
|
await writeOwnRoutingConfig(loaded, expired, `switchover windows expired more than ${INTERMEDIATE_EXPIRE_GRACE / 1000}s ago`);
|
|
783
|
+
written.push(key);
|
|
771
784
|
continue;
|
|
772
785
|
}
|
|
773
786
|
if (!takeover) continue;
|
|
@@ -776,21 +789,64 @@ async function maintainIntermediates(): Promise<void> {
|
|
|
776
789
|
let parsed = parseHostedUrl(x.url);
|
|
777
790
|
return parsed.address === domain && parsed.port === port;
|
|
778
791
|
}) as HostedConfig | undefined;
|
|
779
|
-
if (!mainUrl)
|
|
792
|
+
if (!mainUrl) {
|
|
793
|
+
notOurs.push(key);
|
|
794
|
+
continue;
|
|
795
|
+
}
|
|
780
796
|
let injected = injectIntermediateSource(loaded.routing, {
|
|
781
797
|
splitUrl: mainUrl.url,
|
|
782
798
|
intermediateUrl: replaceHostedUrlPort(mainUrl.url, takeover.altPort),
|
|
783
799
|
start: takeover.start,
|
|
784
800
|
end: takeover.end,
|
|
785
801
|
});
|
|
786
|
-
if (JSON.stringify(injected) === JSON.stringify(loaded.routing))
|
|
802
|
+
if (JSON.stringify(injected) === JSON.stringify(loaded.routing)) {
|
|
803
|
+
alreadyCorrect.push(key);
|
|
804
|
+
continue;
|
|
805
|
+
}
|
|
787
806
|
await writeOwnRoutingConfig(loaded, injected, `we are a deploy successor: writes route to our alternate port ${takeover.altPort} from ${new Date(takeover.start).toISOString()} until our predecessor is killed at ${new Date(takeover.end).toISOString()}`);
|
|
807
|
+
written.push(key);
|
|
808
|
+
}
|
|
809
|
+
if (!takeover) return;
|
|
810
|
+
if (!keys.length) {
|
|
811
|
+
console.log(`No active buckets, so no config files to write the intermediate into (a bucket is only active once something uses it)`);
|
|
812
|
+
return;
|
|
813
|
+
}
|
|
814
|
+
if (!written.length) {
|
|
815
|
+
console.log(`Wrote no config files: of ${keys.length} active buckets, ${alreadyCorrect.length} already contain the intermediate and ${notOurs.length} are not hosted by us`);
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
/** Our predecessor still holds the main port and has been serving all along, so it - not us - knows which buckets are in use. We activate exactly those, which is what makes their config files get the intermediate; nothing else on disk is touched. */
|
|
820
|
+
async function activatePredecessorBuckets(): Promise<void> {
|
|
821
|
+
let { domain, port } = getStorageServerConfig();
|
|
822
|
+
let url = `https://${domain}:${port}`;
|
|
823
|
+
let keys: { account: string; bucketName: string }[];
|
|
824
|
+
try {
|
|
825
|
+
keys = await listServerActiveBucketKeys({ url });
|
|
826
|
+
} catch (e) {
|
|
827
|
+
console.error(`Could not ask our predecessor on ${url} which buckets are active, so only buckets used on this process get the intermediate: ${(e as Error).stack ?? e}`);
|
|
828
|
+
return;
|
|
829
|
+
}
|
|
830
|
+
if (!keys.length) {
|
|
831
|
+
console.log(`Our predecessor on ${url} has no active buckets, so there are no config files to write the intermediate into`);
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
834
|
+
console.log(`Our predecessor on ${url} has ${keys.length} active buckets, activating them here so their config files get the intermediate: ${keys.map(x => `${x.account}/${x.bucketName}`).join(", ")}`);
|
|
835
|
+
for (let { account, bucketName } of keys) {
|
|
836
|
+
try {
|
|
837
|
+
await getLoadedBucket(account, bucketName);
|
|
838
|
+
} catch (e) {
|
|
839
|
+
console.error(`Activating bucket ${account}/${bucketName} (active on our predecessor) failed: ${(e as Error).stack ?? e}`);
|
|
840
|
+
}
|
|
788
841
|
}
|
|
789
842
|
}
|
|
790
843
|
|
|
791
844
|
/** Started by deployTakeover once we are actually a deploy successor listening on an alternate port. Until then there are no switchover windows to write or expire, so nothing polls. */
|
|
792
845
|
export const startIntermediateMaintenance = lazy(() => {
|
|
793
|
-
void
|
|
846
|
+
void (async () => {
|
|
847
|
+
await activatePredecessorBuckets();
|
|
848
|
+
await maintainIntermediates();
|
|
849
|
+
})().catch((e: Error) => console.error(`Writing the intermediate into the config files failed: ${e.stack ?? e}`));
|
|
794
850
|
runInfinitePoll(INTERMEDIATE_MAINTAIN_INTERVAL, maintainIntermediates);
|
|
795
851
|
});
|
|
796
852
|
|