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.
Files changed (42) hide show
  1. package/index.d.ts +16 -0
  2. package/misc/dist/environment.ts.cache +2 -2
  3. package/misc/dist/zip.ts.cache +2 -2
  4. package/package.json +1 -1
  5. package/render-utils/dist/observer.tsx.cache +2 -2
  6. package/storage/BulkDatabase2/dist/BulkDatabaseBase.ts.cache +2 -2
  7. package/storage/BulkDatabase2/dist/BulkDatabaseFormat.ts.cache +2 -2
  8. package/storage/BulkDatabase2/dist/BulkDatabaseMerge.ts.cache +2 -2
  9. package/storage/BulkDatabase2/dist/BulkDatabaseReader.ts.cache +2 -2
  10. package/storage/BulkDatabase2/dist/LoadedIndex.ts.cache +2 -2
  11. package/storage/BulkDatabase2/dist/WriteOverlay.ts.cache +2 -2
  12. package/storage/BulkDatabase2/dist/blockCache.ts.cache +2 -2
  13. package/storage/BulkDatabase2/dist/mergeLock.ts.cache +2 -2
  14. package/storage/BulkDatabase2/dist/mergeMarkers.ts.cache +2 -2
  15. package/storage/BulkDatabase2/dist/streamLog.ts.cache +2 -2
  16. package/storage/BulkDatabase2/dist/syncClient.ts.cache +2 -2
  17. package/storage/dist/ArchivesDisk.ts.cache +2 -2
  18. package/storage/dist/FileFolderAPI.tsx.cache +2 -2
  19. package/storage/dist/IndexedDBFileFolderAPI.ts.cache +2 -2
  20. package/storage/dist/JSONStorage.ts.cache +2 -2
  21. package/storage/dist/PendingManager.tsx.cache +2 -2
  22. package/storage/dist/TransactionStorage.ts.cache +2 -2
  23. package/storage/dist/fileSystemPointer.ts.cache +2 -2
  24. package/storage/dist/remoteFileStorage.ts.cache +2 -2
  25. package/storage/remoteStorage/createArchives.d.ts +7 -0
  26. package/storage/remoteStorage/createArchives.ts +5 -0
  27. package/storage/remoteStorage/deployTakeover.ts +1 -1
  28. package/storage/remoteStorage/dist/ArchivesRemote.ts.cache +2 -2
  29. package/storage/remoteStorage/dist/ArchivesUrl.ts.cache +2 -2
  30. package/storage/remoteStorage/dist/blobStore.ts.cache +2 -2
  31. package/storage/remoteStorage/dist/cliArgs.ts.cache +2 -2
  32. package/storage/remoteStorage/dist/createArchives.ts.cache +9 -4
  33. package/storage/remoteStorage/dist/deployTakeover.ts.cache +4 -4
  34. package/storage/remoteStorage/dist/intermediateSources.ts.cache +2 -2
  35. package/storage/remoteStorage/dist/remoteConfig.ts.cache +2 -2
  36. package/storage/remoteStorage/dist/storageClientController.ts.cache +2 -2
  37. package/storage/remoteStorage/dist/storageController.ts.cache +8 -3
  38. package/storage/remoteStorage/dist/storageServerState.ts.cache +67 -10
  39. package/storage/remoteStorage/storageController.d.ts +4 -0
  40. package/storage/remoteStorage/storageController.ts +6 -1
  41. package/storage/remoteStorage/storageServerState.d.ts +5 -0
  42. 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 our own routing config update for bucket ${key} (${reason}), version ${getConfigVersion(loaded.routing)} -> ${version}: ${JSON.stringify(next)}`);
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(`Propagated our routing config update to ${url}`);
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
- for (let key of [...buckets.keys()]) {
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) continue;
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)) continue;
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 maintainIntermediates().catch((e: Error) => console.error(`Maintaining switchover routing windows failed: ${e.stack ?? e}`));
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