sliftutils 1.7.86 → 1.7.87

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.
@@ -81,7 +81,8 @@ export function injectIntermediateSource(config: RemoteConfig, inject: { splitUr
81
81
  if (middleStart > windowStart) {
82
82
  sources.push({ ...source, validWindow: [windowStart, middleStart] });
83
83
  }
84
- sources.push({ ...source, url: intermediateUrl, validWindow: [middleStart, middleEnd], intermediate: true });
84
+ // intermediate = the url this entry was split out of, so a request naming the intermediate still resolves to the original source
85
+ sources.push({ ...source, url: intermediateUrl, validWindow: [middleStart, middleEnd], intermediate: splitUrl });
85
86
  if (windowEnd > middleEnd) {
86
87
  sources.push({ ...source, validWindow: [middleEnd, windowEnd] });
87
88
  }
@@ -98,7 +99,8 @@ export function expireIntermediateSources(config: RemoteConfig, now: number): Re
98
99
  let result = resolved;
99
100
  for (let keep of keptIntermediates) {
100
101
  result = injectIntermediateSource(result, {
101
- splitUrl: findSplitUrl(config, keep) || keep.url,
102
+ // The intermediate carries the url it was split out of; fall back to its own url only for a legacy entry that predates that
103
+ splitUrl: keep.intermediate || keep.url,
102
104
  intermediateUrl: keep.url,
103
105
  start: keep.validWindow[0],
104
106
  end: keep.validWindow[1],
@@ -106,10 +108,3 @@ export function expireIntermediateSources(config: RemoteConfig, now: number): Re
106
108
  }
107
109
  return result;
108
110
  }
109
-
110
- /** The url of the entry an intermediate was split out of - the neighbour it touches. */
111
- export function findSplitUrl(config: RemoteConfig, intermediate: SourceConfig): string | undefined {
112
- let [start, end] = intermediate.validWindow;
113
- let neighbour = config.sources.find(x => isSourceConfig(x) && !x.intermediate && (x.validWindow[1] === start || x.validWindow[0] === end)) as SourceConfig | undefined;
114
- return neighbour?.url;
115
- }
@@ -10,7 +10,7 @@ import {
10
10
  ArchiveFileInfo, ChangesAfterConfig, DelConfig, FindConfig, GetConfig, GetInfoConfig, SetConfig, SyncActivity, FULL_ROUTE,
11
11
  } from "../IArchives";
12
12
  import { ROUTING_FILE, parseRoutingData, serializeRemoteConfig, parseHostedUrl, replaceHostedUrlPort, buildFileUrl, getConfigVersion, routeIntersection, normalizeSource } from "./remoteConfig";
13
- import { injectIntermediateSource, expireIntermediateSources, getIntermediateSources, findSplitUrl, nextIntermediateVersion, INTERMEDIATE_EXPIRE_GRACE } from "./intermediateSources";
13
+ import { injectIntermediateSource, expireIntermediateSources, getIntermediateSources, nextIntermediateVersion, INTERMEDIATE_EXPIRE_GRACE } from "./intermediateSources";
14
14
  import { getTakeoverIntermediate } from "./deployTakeover";
15
15
  import { createApiArchives, listServerActiveBucketKeys } from "./createArchives";
16
16
  import { broadcastRoutingChanged } from "./storageController";
@@ -62,9 +62,10 @@ export async function requireBucket(account: string, bucketName: string): Promis
62
62
  return bucket;
63
63
  }
64
64
 
65
- /** The stable identity of a source config for matching: everything EXCEPT the valid window. The window drifts (a switchover splits one window in two around an intermediate, then rejoins it), so a caller and this server routinely disagree on it while naming the very same source - matching on it would wrongly reject the request. The route stays in the identity (it selects the store/folder). */
65
+ /** The stable identity of a source config for matching: everything EXCEPT the valid window, and with an intermediate resolved back to the source it was split out of. The window drifts (a switchover splits one window in two around an intermediate, then rejoins it), so a caller and this server routinely disagree on it - matching on it would wrongly reject the request. An intermediate is a transient alt-port view of another source, so it must resolve to THAT source (config.intermediate holds its url + the intermediate flag is dropped), or a request naming the intermediate would fail to match once the intermediate has rejoined and its entry is gone. The route stays in the identity (it selects the store/folder). */
66
66
  function sourceMatchKey(config: SourceConfig): string {
67
- return stableStringify({ ...config, validWindow: undefined });
67
+ let url = config.intermediate || config.url;
68
+ return stableStringify({ ...config, url, intermediate: undefined, validWindow: undefined });
68
69
  }
69
70
 
70
71
  /** The store serving a request: the config entry the CLIENT selected, matched against the bucket's own entries by identity EXCLUDING the valid window (see sourceMatchKey). The selection never validates - the store's own window/route checks throw if the caller is stale - so honoring a window mismatch here is exactly right. Throws when nothing matches, listing what is available. */
@@ -517,7 +518,7 @@ async function writeRoutingConfig(account: string, bucketName: string, data: Buf
517
518
  let reinjected = 0;
518
519
  for (let intermediate of getIntermediateSources(expireIntermediateSources(loaded.routing, Date.now()))) {
519
520
  stored = injectIntermediateSource(stored, {
520
- splitUrl: findSplitUrl(loaded.routing, intermediate) || intermediate.url,
521
+ splitUrl: intermediate.intermediate || intermediate.url,
521
522
  intermediateUrl: intermediate.url,
522
523
  start: intermediate.validWindow[0],
523
524
  end: intermediate.validWindow[1],