sliftutils 1.7.90 → 1.7.92
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 +38 -79
- package/misc/https/dist/cloudflareHelpers.ts.cache +2 -2
- package/misc/https/dist/dns.ts.cache +2 -2
- package/package.json +1 -1
- 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/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/IArchives.d.ts +1 -0
- package/storage/IArchives.ts +3 -0
- package/storage/remoteStorage/accessStats.d.ts +12 -0
- package/storage/remoteStorage/accessStats.ts +47 -0
- package/storage/remoteStorage/blobStore.d.ts +6 -1
- package/storage/remoteStorage/blobStore.ts +34 -5
- package/storage/remoteStorage/createArchives.ts +13 -6
- package/storage/remoteStorage/dist/accessStats.ts.cache +42 -3
- package/storage/remoteStorage/dist/blobStore.ts.cache +6 -3
- package/storage/remoteStorage/dist/intermediateManagement.ts.cache +56 -50
- package/storage/remoteStorage/dist/storageController.ts.cache +36 -29
- package/storage/remoteStorage/dist/storageServerState.ts.cache +110 -233
- package/storage/remoteStorage/dist/storeConfig.ts.cache +2 -2
- package/storage/remoteStorage/dist/storePlan.ts.cache +4 -56
- package/storage/remoteStorage/intermediateManagement.d.ts +2 -3
- package/storage/remoteStorage/intermediateManagement.ts +53 -46
- package/storage/remoteStorage/storageController.ts +22 -14
- package/storage/remoteStorage/storageServerState.d.ts +15 -55
- package/storage/remoteStorage/storageServerState.ts +106 -268
- package/storage/remoteStorage/storeConfig.d.ts +2 -0
- package/storage/remoteStorage/storeConfig.ts +2 -0
- package/storage/remoteStorage/storePlan.d.ts +0 -20
- package/storage/remoteStorage/storePlan.ts +1 -69
|
@@ -48,5 +48,5 @@ class StoreConfig {
|
|
|
48
48
|
exports.StoreConfig = StoreConfig;
|
|
49
49
|
// A store nobody has configured: always valid, the whole key space, no delays and no limits. Every one of these is the answer that does the least - it holds its own data and nothing else happens to it - which is what makes a store usable before it has ever seen a config.
|
|
50
50
|
const UNCONFIGURED = { validWindow: IArchives_1.FULL_VALID_WINDOW };
|
|
51
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
52
|
-
/* _JS_SOURCE_HASH = "
|
|
51
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RvcmVDb25maWcuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzdG9yZUNvbmZpZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxtREFBZ0Q7QUFDaEQsNENBQStEO0FBRS9ELDJZQUEyWTtBQUUzWSxNQUFhLFdBQVc7SUFDcEIsWUFDb0IsSUFBWSxFQUM1QixPQUF1QjtRQURQLFNBQUksR0FBSixJQUFJLENBQVE7UUFNaEMsc0tBQXNLO1FBQzlKLFlBQU8sR0FBbUIsRUFBRSxDQUFDO1FBSmpDLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDekIsQ0FBQztJQUtELDJJQUEySTtJQUMzSSw2SkFBNko7SUFDdEosTUFBTSxDQUFDLE9BQXVCO1FBQ2pDLElBQUksT0FBTyxHQUFHLENBQUMsR0FBRyxPQUFPLENBQUMsQ0FBQztRQUMzQixJQUFBLFdBQUksRUFBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDckMsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUM7SUFDM0IsQ0FBQztJQUVNLEdBQUc7UUFDTixPQUFPLElBQUksQ0FBQyxPQUFPLENBQUM7SUFDeEIsQ0FBQztJQUVEOzs7Ozs7Ozs7T0FTRztJQUNJLE9BQU87UUFDVixJQUFJLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDckIsSUFBSSxVQUFVLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxJQUFJLEdBQUcsSUFBSSxHQUFHLEdBQUcsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzNGLElBQUksVUFBVTtZQUFFLE9BQU8sVUFBVSxDQUFDO1FBQ2xDLElBQUksUUFBUSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQztRQUM5RCxJQUFJLFFBQVE7WUFBRSxPQUFPLFFBQVEsQ0FBQztRQUM5QixJQUFJLElBQUksR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQ2pELElBQUksSUFBSTtZQUFFLE9BQU8sSUFBSSxDQUFDO1FBQ3RCLE9BQU8sWUFBWSxDQUFDO0lBQ3hCLENBQUM7Q0FDSjtBQTNDRCxrQ0EyQ0M7QUFjRCxnUkFBZ1I7QUFDaFIsTUFBTSxZQUFZLEdBQWdCLEVBQUUsV0FBVyxFQUFFLDZCQUFpQixFQUFFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBzb3J0IH0gZnJvbSBcInNvY2tldC1mdW5jdGlvbi9zcmMvbWlzY1wiO1xuaW1wb3J0IHsgSG9zdGVkQ29uZmlnLCBGVUxMX1ZBTElEX1dJTkRPVyB9IGZyb20gXCIuLi9JQXJjaGl2ZXNcIjtcblxuLy8gVGhlIGNvbmZpZ3VyYXRpb24gb2YgT05FIHN0b3JlLCBrZXB0IGN1cnJlbnQuIEEgc3RvcmUgaXMgbmFtZWQgYnkgaXRzIGVudHJpZXMgKHNlZSBDb21tb25Db25maWcubmFtZSksIGFuZCBhdCBhbnkgaW5zdGFudCBleGFjdGx5IG9uZSBvZiB0aGVtIGlzIGluIGVmZmVjdCAtIHRoZSBjb25maWcgd3JpdGUgcGF0aCBlbmZvcmNlcyB0aGF0IC0gc28gXCJ0aGUgY29uZmlndXJhdGlvbiBvZiB0aGlzIHN0b3JlIHJpZ2h0IG5vd1wiIGlzIGEgc2luZ2xlIGVudHJ5LCBhbmQgZXZlcnl0aGluZyB0aGUgc3RvcmUgZG9lcyB3aXRoIHJvdXRlcywgZmxhZ3MgYW5kIGxpbWl0cyByZWFkcyBpdCBmcm9tIGhlcmUgcmF0aGVyIHRoYW4gYmVpbmcgaGFuZGVkIGEgc25hcHNob3QgdGhhdCBnb2VzIHN0YWxlLlxuXG5leHBvcnQgY2xhc3MgU3RvcmVDb25maWcge1xuICAgIGNvbnN0cnVjdG9yKFxuICAgICAgICBwdWJsaWMgcmVhZG9ubHkgbmFtZTogc3RyaW5nLFxuICAgICAgICBlbnRyaWVzOiBIb3N0ZWRDb25maWdbXSxcbiAgICApIHtcbiAgICAgICAgdGhpcy51cGRhdGUoZW50cmllcyk7XG4gICAgfVxuXG4gICAgLy8gRXZlcnkgZW50cnkgbmFtaW5nIHRoaXMgc3RvcmUsIG9sZGVzdCB3aW5kb3cgZmlyc3QgLSBwYXN0IG9uZXMgaW5jbHVkZWQsIGJlY2F1c2UgYSBzdGFtcGVkIHdyaXRlIG9yIGEgc2NhbiBjYW4gbGVnaXRpbWF0ZWx5IGNvbmNlcm4gYSB3aW5kb3cgdGhhdCBoYXMgYWxyZWFkeSBlbmRlZFxuICAgIHByaXZhdGUgZW50cmllczogSG9zdGVkQ29uZmlnW10gPSBbXTtcblxuICAgIC8qKiBUaGUgcm91dGluZyBjb25maWcgY2hhbmdlZC4gU2FtZSBzdG9yZSBlaXRoZXIgd2F5OiBpdHMgbmFtZSBkaWQgbm90IGNoYW5nZSwgc28gbmVpdGhlciBkaWQgaXRzIGZvbGRlciwgaXRzIGluZGV4LCBvciB0aGUgZGF0YSBpbiBpdC4gKi9cbiAgICAvKiogTm8gZW50cmllcyBpcyBhIHJlYWwgc3RhdGUsIG5vdCBhbiBlcnJvcjogYSBzdG9yZSBleGlzdHMgYXMgc29vbiBhcyBpdHMgZm9sZGVyIGRvZXMsIGFuZCBpdCBtYXkgbmV2ZXIgaGF2ZSBoZWFyZCBvZiBhIGNvbmZpZ3VyYXRpb24gKHNlZSBTdG9yZVBvbGljeSkuICovXG4gICAgcHVibGljIHVwZGF0ZShlbnRyaWVzOiBIb3N0ZWRDb25maWdbXSk6IHZvaWQge1xuICAgICAgICBsZXQgb3JkZXJlZCA9IFsuLi5lbnRyaWVzXTtcbiAgICAgICAgc29ydChvcmRlcmVkLCB4ID0+IHgudmFsaWRXaW5kb3dbMF0pO1xuICAgICAgICB0aGlzLmVudHJpZXMgPSBvcmRlcmVkO1xuICAgIH1cblxuICAgIHB1YmxpYyBhbGwoKTogSG9zdGVkQ29uZmlnW10ge1xuICAgICAgICByZXR1cm4gdGhpcy5lbnRyaWVzO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFdoYXQgdGhpcyBzdG9yZSBpcyBjb25maWd1cmVkIHRvIGJlIHJpZ2h0IG5vdzogdGhlIGVudHJ5IHdob3NlIHdpbmRvdyBjb250YWlucyB0aGlzIG1vbWVudDtcbiAgICAgKiBmYWlsaW5nIHRoYXQgdGhlIG5leHQgb25lIGR1ZSB0byBzdGFydDsgZmFpbGluZyB0aGF0IHRoZSBsYXN0IG9uZSB0byBoYXZlIGVuZGVkLlxuICAgICAqXG4gICAgICogVGhlcmUgaXMgYWx3YXlzIGFuIGFuc3dlciwgYW5kIGl0IG1hdHRlcnMgdGhhdCB0aGVyZSBpczogYSBzdG9yZSBiZXR3ZWVuIHdpbmRvd3Mgc3RpbGwgaG9sZHNcbiAgICAgKiBkYXRhIGFuZCBzdGlsbCBoYXMgdG8gYW5zd2VyIGZvciBpdCwgc28gaXQgbmVlZHMgYSByb3V0ZSBhbmQgZmxhZ3MgZXZlbiB3aGVuIG5vdGhpbmcgaXNcbiAgICAgKiBjdXJyZW50bHkgcG9pbnRpbmcgd3JpdGVzIGF0IGl0LiBXaGljaCBvZiB0aGUgdGhyZWUgY2FzZXMgcHJvZHVjZWQgdGhlIGFuc3dlciBpcyBkZWxpYmVyYXRlbHlcbiAgICAgKiBub3QgZXhwb3NlZCAtIHRoZSB2YWxpZCB3aW5kb3cgaXRzZWxmIGlzIHdoYXQgc2F5cyB3aGV0aGVyIHdyaXRlcyBiZWxvbmcgaGVyZSwgYW5kIGV2ZXJ5IHdyaXRlXG4gICAgICogaXMgY2hlY2tlZCBhZ2FpbnN0IGl0IHNlcGFyYXRlbHkuXG4gICAgICovXG4gICAgcHVibGljIGN1cnJlbnQoKTogU3RvcmVQb2xpY3kge1xuICAgICAgICBsZXQgbm93ID0gRGF0ZS5ub3coKTtcbiAgICAgICAgbGV0IGNvbnRhaW5pbmcgPSB0aGlzLmVudHJpZXMuZmluZCh4ID0+IHgudmFsaWRXaW5kb3dbMF0gPD0gbm93ICYmIG5vdyA8IHgudmFsaWRXaW5kb3dbMV0pO1xuICAgICAgICBpZiAoY29udGFpbmluZykgcmV0dXJuIGNvbnRhaW5pbmc7XG4gICAgICAgIGxldCB1cGNvbWluZyA9IHRoaXMuZW50cmllcy5maW5kKHggPT4geC52YWxpZFdpbmRvd1swXSA+IG5vdyk7XG4gICAgICAgIGlmICh1cGNvbWluZykgcmV0dXJuIHVwY29taW5nO1xuICAgICAgICBsZXQgbGFzdCA9IHRoaXMuZW50cmllc1t0aGlzLmVudHJpZXMubGVuZ3RoIC0gMV07XG4gICAgICAgIGlmIChsYXN0KSByZXR1cm4gbGFzdDtcbiAgICAgICAgcmV0dXJuIFVOQ09ORklHVVJFRDtcbiAgICB9XG59XG5cbi8qKiBUaGUgcGFydHMgb2YgYSBjb25maWcgZW50cnkgdGhhdCBkZXNjcmliZSB3aGF0IGEgc3RvcmUgSVMgLSBhcyBvcHBvc2VkIHRvIHdoaWNoIGVudHJ5IHNhaWQgc28uIEtlcHQgc2VwYXJhdGUgYmVjYXVzZSBhIHN0b3JlIHdpdGggbm8gZW50cmllcyBzdGlsbCBoYXMgYWxsIG9mIHRoZW0uICovXG5leHBvcnQgdHlwZSBTdG9yZVBvbGljeSA9IHtcbiAgICB2YWxpZFdpbmRvdzogW251bWJlciwgbnVtYmVyXTtcbiAgICByb3V0ZT86IFtudW1iZXIsIG51bWJlcl07XG4gICAgcHVibGljPzogYm9vbGVhbjtcbiAgICBpbW11dGFibGU/OiBib29sZWFuO1xuICAgIGZhc3Q/OiBib29sZWFuO1xuICAgIHdyaXRlRGVsYXk/OiBudW1iZXI7XG4gICAgbm9GdWxsU3luYz86IGJvb2xlYW47XG4gICAgcmVhZGVyRGlza0xpbWl0PzogbnVtYmVyO1xufTtcblxuLy8gQSBzdG9yZSBub2JvZHkgaGFzIGNvbmZpZ3VyZWQ6IGFsd2F5cyB2YWxpZCwgdGhlIHdob2xlIGtleSBzcGFjZSwgbm8gZGVsYXlzIGFuZCBubyBsaW1pdHMuIEV2ZXJ5IG9uZSBvZiB0aGVzZSBpcyB0aGUgYW5zd2VyIHRoYXQgZG9lcyB0aGUgbGVhc3QgLSBpdCBob2xkcyBpdHMgb3duIGRhdGEgYW5kIG5vdGhpbmcgZWxzZSBoYXBwZW5zIHRvIGl0IC0gd2hpY2ggaXMgd2hhdCBtYWtlcyBhIHN0b3JlIHVzYWJsZSBiZWZvcmUgaXQgaGFzIGV2ZXIgc2VlbiBhIGNvbmZpZy5cbmNvbnN0IFVOQ09ORklHVVJFRDogU3RvcmVQb2xpY3kgPSB7IHZhbGlkV2luZG93OiBGVUxMX1ZBTElEX1dJTkRPVyB9O1xuIl19
|
|
52
|
+
/* _JS_SOURCE_HASH = "8bb3f6f96b5bcb9f85a1dc5d367811caff8fa8ab88234e66e59890d123460dba"; */
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
|
|
3
|
-
//exports.
|
|
4
|
-
const misc_1 = require("socket-function/src/misc");
|
|
3
|
+
//exports.previousWindowOwners = exports.selectEntryAt = exports.findSelfIndexes = exports.isSelfSource = void 0;
|
|
5
4
|
const IArchives_1 = require("../IArchives");
|
|
6
5
|
const remoteConfig_1 = require("./remoteConfig");
|
|
7
6
|
const serverConfig_1 = require("./serverConfig");
|
|
8
|
-
//
|
|
7
|
+
// Pure helpers over a bucket's routing config: which entries are this server, which entry applies at a moment, and who owned what before a window boundary. Config in, answer out - nothing here reads a store, a clock, or the network (except selectEntryAt being handed a time).
|
|
9
8
|
/** Whether a config entry is THIS server's copy of this bucket - the same account and bucket, at an address this process answers on. */
|
|
10
9
|
function isSelfSource(source, account, bucketName) {
|
|
11
10
|
if (source.type !== "remote")
|
|
@@ -132,56 +131,5 @@ function previousWindowOwners(config, windowStart, selfIndexes) {
|
|
|
132
131
|
return [...byRoute.values()].filter(x => x.scanOwnDisk || x.remotes.size);
|
|
133
132
|
}
|
|
134
133
|
exports.previousWindowOwners = previousWindowOwners;
|
|
135
|
-
function mergeRoutes(routes) {
|
|
136
|
-
|
|
137
|
-
(0, misc_1.sort)(list, x => x[0]);
|
|
138
|
-
let merged = [];
|
|
139
|
-
for (let route of list) {
|
|
140
|
-
let last = merged[merged.length - 1];
|
|
141
|
-
if (last && route[0] <= last[1]) {
|
|
142
|
-
last[1] = Math.max(last[1], route[1]);
|
|
143
|
-
continue;
|
|
144
|
-
}
|
|
145
|
-
merged.push(route);
|
|
146
|
-
}
|
|
147
|
-
return merged;
|
|
148
|
-
}
|
|
149
|
-
function summarizeSelf(selfEntries, now) {
|
|
150
|
-
var _a;
|
|
151
|
-
let current = selfEntries.filter(x => x.validWindow[0] <= now && now < x.validWindow[1]);
|
|
152
|
-
if (!current.length) {
|
|
153
|
-
let nearest = selectEntryAt(selfEntries, now);
|
|
154
|
-
current = nearest && [nearest] || [];
|
|
155
|
-
}
|
|
156
|
-
if (!current.length) {
|
|
157
|
-
return undefined;
|
|
158
|
-
}
|
|
159
|
-
return {
|
|
160
|
-
routes: mergeRoutes(current.map(x => x.route)),
|
|
161
|
-
public: current.some(x => x.public),
|
|
162
|
-
immutable: current.some(x => x.immutable),
|
|
163
|
-
noFullSync: current.some(x => x.noFullSync),
|
|
164
|
-
readerDiskLimit: (_a = current.find(x => x.readerDiskLimit !== undefined)) === null || _a === void 0 ? void 0 : _a.readerDiskLimit,
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
/** Which stores this server runs for a bucket, by name. Nothing more: a store is found by name, and configures itself. */
|
|
168
|
-
function planSelfStores(account, bucketName, routing) {
|
|
169
|
-
let selfIndexes = findSelfIndexes(routing, account, bucketName);
|
|
170
|
-
let selfEntries = selfIndexes.map(i => routing.sources[i]);
|
|
171
|
-
let self = summarizeSelf(selfEntries, Date.now());
|
|
172
|
-
// One store per NAME among ALL our entries - past and future windows included, so a name we no longer write to keeps serving its data and a name we are about to use exists ahead of its window
|
|
173
|
-
let byName = new Map();
|
|
174
|
-
for (let entry of selfEntries) {
|
|
175
|
-
let entries = byName.get(entry.name);
|
|
176
|
-
if (!entries) {
|
|
177
|
-
entries = [];
|
|
178
|
-
byName.set(entry.name, entries);
|
|
179
|
-
}
|
|
180
|
-
entries.push(entry);
|
|
181
|
-
}
|
|
182
|
-
// Not in the config at all: no name means no store here
|
|
183
|
-
return { selfEntries, self, stores: [...byName].map(([name, entries]) => ({ name, entries })) };
|
|
184
|
-
}
|
|
185
|
-
exports.planSelfStores = planSelfStores;
|
|
186
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RvcmVQbGFuLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsic3RvcmVQbGFuLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLG1EQUFnRDtBQUNoRCw0Q0FBb0Y7QUFDcEYsaURBQWtGO0FBQ2xGLGlEQUE4QztBQUU5QyxnTEFBZ0w7QUFFaEwsd0lBQXdJO0FBQ3hJLFNBQWdCLFlBQVksQ0FBQyxNQUFvQixFQUFFLE9BQWUsRUFBRSxVQUFrQjtJQUNsRixJQUFJLE1BQU0sQ0FBQyxJQUFJLEtBQUssUUFBUTtRQUFFLE9BQU8sS0FBSyxDQUFDO0lBQzNDLElBQUksTUFBTSxHQUFHLElBQUEsNkJBQWMsRUFBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDeEMsSUFBSSxNQUFNLENBQUMsT0FBTyxLQUFLLE9BQU8sSUFBSSxNQUFNLENBQUMsVUFBVSxLQUFLLFVBQVU7UUFBRSxPQUFPLEtBQUssQ0FBQztJQUNqRixPQUFPLElBQUEsMkJBQVksRUFBQyxNQUFNLENBQUMsT0FBTyxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQztBQUNyRCxDQUFDO0FBTEQsb0NBS0M7QUFFRCxTQUFnQixlQUFlLENBQUMsT0FBcUIsRUFBRSxPQUFlLEVBQUUsVUFBa0I7SUFDdEYsSUFBSSxPQUFPLEdBQWEsRUFBRSxDQUFDO0lBQzNCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO1FBQzlDLElBQUksTUFBTSxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDaEMsSUFBSSxPQUFPLE1BQU0sS0FBSyxRQUFRO1lBQUUsU0FBUztRQUN6QyxJQUFJLFlBQVksQ0FBQyxNQUFNLEVBQUUsT0FBTyxFQUFFLFVBQVUsQ0FBQyxFQUFFLENBQUM7WUFDNUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FB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R0FBRyxFQUEwQixDQUFDO0lBQy9DLEtBQUssSUFBSSxLQUFLLElBQUksV0FBVyxFQUFFLENBQUM7UUFDNUIsSUFBSSxPQUFPLEdBQUcsTUFBTSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDckMsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ1gsT0FBTyxHQUFHLEVBQUUsQ0FBQztZQUNiLE1BQU0sQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxPQUFPLENBQUMsQ0FBQztRQUNwQyxDQUFDO1FBQ0QsT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUN4QixDQUFDO0lBQ0Qsd0RBQXdEO0lBQ3hELE9BQU8sRUFBRSxXQUFXLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxDQUFDLEdBQUcsTUFBTSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsT0FBTyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQyxFQUFFLENBQUM7QUFDcEcsQ0FBQztBQWhCRCx3Q0FnQkMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBzb3J0IH0gZnJvbSBcInNvY2tldC1mdW5jdGlvbi9zcmMvbWlzY1wiO1xuaW1wb3J0IHsgUmVtb3RlQ29uZmlnLCBIb3N0ZWRDb25maWcsIFNvdXJjZUNvbmZpZywgRlVMTF9ST1VURSB9IGZyb20gXCIuLi9JQXJjaGl2ZXNcIjtcbmltcG9ydCB7IHBhcnNlSG9zdGVkVXJsLCByb3V0ZUNvbnRhaW5zLCByb3V0ZUludGVyc2VjdGlvbiB9IGZyb20gXCIuL3JlbW90ZUNvbmZpZ1wiO1xuaW1wb3J0IHsgaXNPd25BZGRyZXNzIH0gZnJvbSBcIi4vc2VydmVyQ29uZmlnXCI7XG5cbi8vIFR1cm5zIGEgYnVja2V0J3Mgcm91dGluZyBjb25maWcgaW50byB0aGlzIHNlcnZlcidzIHN0b3JlIHBsYW46IHdoaWNoIG9mIHRoZSBlbnRyaWVzIGFyZSB1cywgd2hhdCBzdG9yZXMgKG9uZSBwZXIgcm91dGUpIHdlIHJ1biwgYW5kIHdoaWNoIHBlZXJzIGVhY2ggc3RvcmUgc3luY2hyb25pemVzIGZyb20uXG5cbi8qKiBXaGV0aGVyIGEgY29uZmlnIGVudHJ5IGlzIFRISVMgc2VydmVyJ3MgY29weSBvZiB0aGlzIGJ1Y2tldCAtIHRoZSBzYW1lIGFjY291bnQgYW5kIGJ1Y2tldCwgYXQgYW4gYWRkcmVzcyB0aGlzIHByb2Nlc3MgYW5zd2VycyBvbi4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc1NlbGZTb3VyY2Uoc291cmNlOiBTb3VyY2VDb25maWcsIGFjY291bnQ6IHN0cmluZywgYnVja2V0TmFtZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgaWYgKHNvdXJjZS50eXBlICE9PSBcInJlbW90ZVwiKSByZXR1cm4gZmFsc2U7XG4gICAgbGV0IHBhcnNlZCA9IHBhcnNlSG9zdGVkVXJsKHNvdXJjZS51cmwpO1xuICAgIGlmIChwYXJzZWQuYWNjb3VudCAhPT0gYWNjb3VudCB8fCBwYXJzZWQuYnVja2V0TmFtZSAhPT0gYnVja2V0TmFtZSkgcmV0dXJuIGZhbHNlO1xuICAgIHJldHVybiBpc093bkFkZHJlc3MocGFyc2VkLmFkZHJlc3MsIHBhcnNlZC5wb3J0KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGZpbmRTZWxmSW5kZXhlcyhyb3V0aW5nOiBSZW1vdGVDb25maWcsIGFjY291bnQ6IHN0cmluZywgYnVja2V0TmFtZTogc3RyaW5nKTogbnVtYmVyW10ge1xuICAgIGxldCBpbmRleGVzOiBudW1iZXJbXSA9IFtdO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcm91dGluZy5zb3VyY2VzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGxldCBzb3VyY2UgPSByb3V0aW5nLnNvdXJjZXNbaV07XG4gICAgICAgIGlmICh0eXBlb2Ygc291cmNlID09PSBcInN0cmluZ1wiKSBjb250aW51ZTtcbiAgICAgICAgaWYgKGlzU2VsZlNvdXJjZShzb3VyY2UsIGFjY291bnQsIGJ1Y2tldE5hbWUpKSB7XG4gICAgICAgICAgICBpbmRleGVzLnB1c2goaSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGluZGV4ZXM7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBzZWxlY3RFbnRyeUF0KGVudHJpZXM6IEhvc3RlZENvbmZpZ1tdLCB0aW1lOiBudW1iZXIsIHJvdXRlPzogbnVtYmVyKTogSG9zdGVkQ29uZmlnIHwgdW5kZWZpbmVkIHtcbiAgICBpZiAocm91dGUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBsZXQgY292ZXJpbmcgPSBlbnRyaWVzLmZpbHRlcih4ID0+IHJvdXRlQ29udGFpbnMoeC5yb3V0ZSwgcm91dGUpKTtcbiAgICAgICAgaWYgKGNvdmVyaW5nLmxlbmd0aCkge1xuICAgICAgICAgICAgZW50cmllcyA9IGNvdmVyaW5nO1xuICAgICAgICB9XG4gICAgfVxuICAgIGxldCBjb250YWluaW5nID0gZW50cmllcy5maW5kKHggPT4geC52YWxpZFdpbmRvd1swXSA8PSB0aW1lICYmIHRpbWUgPCB4LnZhbGlkV2luZG93WzFdKTtcbiAgICBpZiAoY29udGFpbmluZykgcmV0dXJuIGNvbnRhaW5pbmc7XG4gICAgbGV0IGJlc3Q6IEhvc3RlZENvbmZpZyB8IHVuZGVmaW5lZDtcbiAgICBsZXQgYmVzdERpc3RhbmNlID0gSW5maW5pdHk7XG4gICAgZm9yIChsZXQgZW50cnkgb2YgZW50cmllcykge1xuICAgICAgICBsZXQgZGlzdGFuY2UgPSBNYXRoLm1pbihNYXRoLmFicyh0aW1lIC0gZW50cnkudmFsaWRXaW5kb3dbMF0pLCBNYXRoLmFicyh0aW1lIC0gZW50cnkudmFsaWRXaW5kb3dbMV0pKTtcbiAgICAgICAgaWYgKGRpc3RhbmNlIDwgYmVzdERpc3RhbmNlKSB7XG4gICAgICAgICAgICBiZXN0RGlzdGFuY2UgPSBkaXN0YW5jZTtcbiAgICAgICAgICAgIGJlc3QgPSBlbnRyeTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gYmVzdDtcbn1cblxuLyoqIFRoZSBwYXJ0cyBvZiBgcmFuZ2VzYCB0aGF0IGBjdXRgIGRvZXMgbm90IGNvdmVyLCBwbHVzIHRoZSBzaW5nbGUgcmFuZ2Ugc3Bhbm5pbmcgd2hhdCBpdCBkaWQuIFJvdXRlcyBhcmUgaGFsZi1vcGVuIFtzdGFydCwgZW5kKSwgc28gc3VidHJhY3Rpbmcgb25lIGZyb20gYW5vdGhlciBsZWF2ZXMgYXQgbW9zdCBhIHBpZWNlIG9uIGVhY2ggc2lkZS4gKi9cbmZ1bmN0aW9uIHN1YnRyYWN0Um91dGUocmFuZ2VzOiBbbnVtYmVyLCBudW1iZXJdW10sIGN1dDogW251bWJlciwgbnVtYmVyXSk6IHsgcmVtYWluaW5nOiBbbnVtYmVyLCBudW1iZXJdW107IGNsYWltZWQ/OiBbbnVtYmVyLCBudW1iZXJdIH0ge1xuICAgIGxldCByZW1haW5pbmc6IFtudW1iZXIsIG51bWJlcl1bXSA9IFtdO1xuICAgIGxldCBjbGFpbWVkOiBbbnVtYmVyLCBudW1iZXJdIHwgdW5kZWZpbmVkO1xuICAgIGZvciAobGV0IHJhbmdlIG9mIHJhbmdlcykge1xuICAgICAgICBsZXQgb3ZlcmxhcCA9IHJvdXRlSW50ZXJzZWN0aW9uKHJhbmdlLCBjdXQpO1xuICAgICAgICBpZiAoIW92ZXJsYXApIHtcbiAgICAgICAgICAgIHJlbWFpbmluZy5wdXNoKHJhbmdlKTtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIGNsYWltZWQgPSBjbGFpbWVkICYmIFtNYXRoLm1pbihjbGFpbWVkWzBdLCBvdmVybGFwWzBdKSwgTWF0aC5tYXgoY2xhaW1lZFsxXSwgb3ZlcmxhcFsxXSldIGFzIFtudW1iZXIsIG51bWJlcl0gfHwgb3ZlcmxhcDtcbiAgICAgICAgaWYgKHJhbmdlWzBdIDwgb3ZlcmxhcFswXSkgcmVtYWluaW5nLnB1c2goW3JhbmdlWzBdLCBvdmVybGFwWzBdXSk7XG4gICAgICAgIGlmIChvdmVybGFwWzFdIDwgcmFuZ2VbMV0pIHJlbWFpbmluZy5wdXNoKFtvdmVybGFwWzFdLCByYW5nZVsxXV0pO1xuICAgIH1cbiAgICByZXR1cm4geyByZW1haW5pbmcsIGNsYWltZWQgfTtcbn1cblxuLyoqIFdoYXQgb25lIG9mIG91ciBzdG9yZXMgaGFzIHRvIHB1bGwgaW4gYXQgYSB2YWxpZC13aW5kb3cgYm91bmRhcnksIHNvIHRoZSB3cml0ZXMgdGhhdCBsYW5kZWQganVzdCBiZWZvcmUgdGhlIGhhbmRvdmVyIGFyZSBub3QgbWlzc2VkLiAqL1xuZXhwb3J0IHR5cGUgQm91bmRhcnlIYW5kb3ZlciA9IHtcbiAgICAvLyBUaGUgc3RvcmUgdGhhdCBuZWVkcyB0aGUgZGF0YTogdGhlIG5hbWUgb2YgdGhlIHNlbGYgZW50cnkgdGFraW5nIG92ZXIgYXQgdGhlIGJvdW5kYXJ5XG4gICAgbmFtZTogc3RyaW5nO1xuICAgIC8vIFRoZSByb3V0ZSBpdCBpcyB0YWtpbmcgb3Zlciwgd2hpY2ggaXMgdGhlIHNsaWNlIG9mIHRoZSBrZXkgc3BhY2UgdGhlIHB1bGxzIGJlbG93IGFyZSBsaW1pdGVkIHRvXG4gICAgcm91dGU6IFtudW1iZXIsIG51bWJlcl07XG4gICAgLy8gV2UgaGVsZCBwYXJ0IG9mIHRoaXMgcm91dGUgaW4gdGhlIHByZXZpb3VzIHdpbmRvdyB0b28sIHNvIHRob3NlIHdyaXRlcyBhcmUgYWxyZWFkeSBpbiBvdXIgb3duIGZvbGRlciBhbmQgYSBkaXNrIHJlc2NhbiBmaW5kcyB0aGVtXG4gICAgc2Nhbk93bkRpc2s6IGJvb2xlYW47XG4gICAgLy8gUGVyIHNvdXJjZSBpbmRleCBpbiB0aGUgY29uZmlnLCB0aGUgc2xpY2Ugb2Ygb3VyIHJvdXRlIFRIQVQgc291cmNlIGhlbGQgaW4gdGhlIHByZXZpb3VzIHdpbmRvdyAtIGEgYm91bmRhcnkgc2NhbiBwdWxscyBpdHMgcmVjZW50IGNoYW5nZXNcbiAgICByZW1vdGVzOiBNYXA8bnVtYmVyLCBbbnVtYmVyLCBudW1iZXJdPjtcbn07XG5cbi8qKlxuICogV2hvIGhlbGQgZWFjaCBzbGljZSBvZiBvdXIgcm91dGUgaW4gdGhlIHdpbmRvdyBiZWZvcmUgd2luZG93U3RhcnQsIGZvciBldmVyeSBzZWxmIGVudHJ5IHdob3NlXG4gKiB3aW5kb3cgc3RhcnRzIGV4YWN0bHkgdGhlbi4gVGhpcyBpcyB0aGUgd2hvbGUgb2YgXCJ3aG8gZG8gd2UgdGFrZSBvdmVyIGZyb21cIjogYSBzdG9yZSB0YWtpbmcgb3ZlciBhXG4gKiByb3V0ZSBtYXkgYmUgdGFraW5nIGl0IGZyb20gc2V2ZXJhbCBwcmV2aW91cyBvd25lcnMgYXQgb25jZSAodGhlaXIgc2hhcmRzIG5lZWQgbm90IGxpbmUgdXAgd2l0aFxuICogb3VycyksIGFuZCBmcm9tIGl0c2VsZiBmb3IgdGhlIHBhcnRzIGl0IGFscmVhZHkgaGVsZC5cbiAqXG4gKiBBIHNlbGYgZW50cnkgaXMgc2tpcHBlZCB3aGVuIGFuIEVBUkxJRVIgZW50cnkgdmFsaWQgYXQgdGhlIGJvdW5kYXJ5IGFscmVhZHkgY292ZXJzIGl0cyB3aG9sZSByb3V0ZTpcbiAqIGNvbmZpZyBvcmRlciBpcyBwcmlvcml0eSwgc28gdGhhdCBlbnRyeSBpcyB0aGUgd3JpdGUgdGFyZ2V0IGFuZCB3ZSBhcmUgbm90IHRoZSBvbmUgdGFraW5nIG92ZXIuXG4gKiBPd25lcnMgYXJlIHRoZW4gcmVzb2x2ZWQgaW4gY29uZmlnIG9yZGVyIHRvbywgZWFjaCBjbGFpbWluZyB0aGUgcGFydCBvZiBvdXIgcm91dGUgc3RpbGwgdW5jbGFpbWVkIC1cbiAqIHRoZSBzYW1lIGZpcnN0LW1hdGNoLXdpbnMgcnVsZSB0aGF0IHBpY2tzIGEgd3JpdGUgdGFyZ2V0IGF0IGFueSBvdGhlciBtb21lbnQuXG4gKlxuICogUHVyZTogY29uZmlnIGluLCBwbGFuIG91dC4gTm90aGluZyBoZXJlIHJlYWRzIGEgc3RvcmUsIGEgY2xvY2ssIG9yIHRoZSBuZXR3b3JrLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcHJldmlvdXNXaW5kb3dPd25lcnMoY29uZmlnOiBSZW1vdGVDb25maWcsIHdpbmRvd1N0YXJ0OiBudW1iZXIsIHNlbGZJbmRleGVzOiBudW1iZXJbXSk6IEJvdW5kYXJ5SGFuZG92ZXJbXSB7XG4gICAgbGV0IHNlbGZJbmRleFNldCA9IG5ldyBTZXQoc2VsZkluZGV4ZXMpO1xuICAgIGxldCBwcmV2aW91c1RpbWUgPSB3aW5kb3dTdGFydCAtIDE7XG4gICAgbGV0IHZhbGlkQXQgPSAoc291cmNlOiBTb3VyY2VDb25maWcsIHRpbWU6IG51bWJlcikgPT4gc291cmNlLnZhbGlkV2luZG93WzBdIDw9IHRpbWUgJiYgdGltZSA8IHNvdXJjZS52YWxpZFdpbmRvd1sxXTtcbiAgICBsZXQgYnlSb3V0ZSA9IG5ldyBNYXA8c3RyaW5nLCBCb3VuZGFyeUhhbmRvdmVyPigpO1xuICAgIGZvciAobGV0IHNlbGZJbmRleCBvZiBzZWxmSW5kZXhlcykge1xuICAgICAgICBsZXQgc2VsZiA9IGNvbmZpZy5zb3VyY2VzW3NlbGZJbmRleF07XG4gICAgICAgIGlmICh0eXBlb2Ygc2VsZiA9PT0gXCJzdHJpbmdcIiB8fCBzZWxmLnZhbGlkV2luZG93WzBdICE9PSB3aW5kb3dTdGFydCkgY29udGludWU7XG4gICAgICAgIGxldCBzZWxmUm91dGUgPSBzZWxmLnJvdXRlIHx8IEZVTExfUk9VVEU7XG4gICAgICAgIGxldCBzaGFkb3dlZCA9IGZhbHNlO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHNlbGZJbmRleDsgaSsrKSB7XG4gICAgICAgICAgICBsZXQgb3RoZXIgPSBjb25maWcuc291cmNlc1tpXTtcbiAgICAgICAgICAgIGlmICh0eXBlb2Ygb3RoZXIgPT09IFwic3RyaW5nXCIgfHwgIXZhbGlkQXQob3RoZXIsIHdpbmRvd1N0YXJ0KSkgY29udGludWU7XG4gICAgICAgICAgICBsZXQgcm91dGUgPSBvdGhlci5yb3V0ZSB8fCBGVUxMX1JPVVRFO1xuICAgICAgICAgICAgaWYgKHJvdXRlWzBdIDw9IHNlbGZSb3V0ZVswXSAmJiBzZWxmUm91dGVbMV0gPD0gcm91dGVbMV0pIHtcbiAgICAgICAgICAgICAgICBzaGFkb3dlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHNoYWRvd2VkKSBjb250aW51ZTtcbiAgICAgICAgLy8gS2V5ZWQgYnkgYm90aDogb25lIG5hbWUgY2FuIHRha2Ugb3ZlciBzZXZlcmFsIHJvdXRlcyBhdCB0aGUgc2FtZSBib3VuZGFyeSwgYW5kIGVhY2ggaXMgcHVsbGVkIHNlcGFyYXRlbHlcbiAgICAgICAgbGV0IGhhbmRvdmVyS2V5ID0gYCR7c2VsZi5uYW1lfXwke0pTT04uc3RyaW5naWZ5KHNlbGZSb3V0ZSl9YDtcbiAgICAgICAgbGV0IGhhbmRvdmVyID0gYnlSb3V0ZS5nZXQoaGFuZG92ZXJLZXkpO1xuICAgICAgICBpZiAoIWhhbmRvdmVyKSB7XG4gICAgICAgICAgICBoYW5kb3ZlciA9IHsgbmFtZTogc2VsZi5uYW1lLCByb3V0ZTogc2VsZlJvdXRlLCBzY2FuT3duRGlzazogZmFsc2UsIHJlbW90ZXM6IG5ldyBNYXAoKSB9O1xuICAgICAgICAgICAgYnlSb3V0ZS5zZXQoaGFuZG92ZXJLZXksIGhhbmRvdmVyKTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgdW5jbGFpbWVkOiBbbnVtYmVyLCBudW1iZXJdW10gPSBbW3NlbGZSb3V0ZVswXSwgc2VsZlJvdXRlWzFdXV07XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgY29uZmlnLnNvdXJjZXMubGVuZ3RoICYmIHVuY2xhaW1lZC5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgbGV0IG90aGVyID0gY29uZmlnLnNvdXJjZXNbaV07XG4gICAgICAgICAgICBpZiAodHlwZW9mIG90aGVyID09PSBcInN0cmluZ1wiIHx8ICF2YWxpZEF0KG90aGVyLCBwcmV2aW91c1RpbWUpKSBjb250aW51ZTtcbiAgICAgICAgICAgIGxldCB7IHJlbWFpbmluZywgY2xhaW1lZCB9ID0gc3VidHJhY3RSb3V0ZSh1bmNsYWltZWQsIG90aGVyLnJvdXRlIHx8IEZVTExfUk9VVEUpO1xuICAgICAgICAgICAgdW5jbGFpbWVkID0gcmVtYWluaW5nO1xuICAgICAgICAgICAgaWYgKCFjbGFpbWVkKSBjb250aW51ZTtcbiAgICAgICAgICAgIGlmIChzZWxmSW5kZXhTZXQuaGFzKGkpKSB7XG4gICAgICAgICAgICAgICAgaGFuZG92ZXIuc2Nhbk93bkRpc2sgPSB0cnVlO1xuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgbGV0IGV4aXN0aW5nID0gaGFuZG92ZXIucmVtb3Rlcy5nZXQoaSk7XG4gICAgICAgICAgICBoYW5kb3Zlci5yZW1vdGVzLnNldChpLCBleGlzdGluZyAmJiBbTWF0aC5taW4oZXhpc3RpbmdbMF0sIGNsYWltZWRbMF0pLCBNYXRoLm1heChleGlzdGluZ1sxXSwgY2xhaW1lZFsxXSldIGFzIFtudW1iZXIsIG51bWJlcl0gfHwgY2xhaW1lZCk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIFsuLi5ieVJvdXRlLnZhbHVlcygpXS5maWx0ZXIoeCA9PiB4LnNjYW5Pd25EaXNrIHx8IHgucmVtb3Rlcy5zaXplKTtcbn1cblxuLyoqIE91ciByb2xlIGluIGEgYnVja2V0J3Mgcm91dGluZyBjb25maWcsIHN1bW1hcml6ZWQgYWNyb3NzIEFMTCBjdXJyZW50bHktdmFsaWQgc2VsZiBlbnRyaWVzLiBTdG9yZWQgaW5zdGVhZCBvZiBhIHNpbmdsZSByZXByZXNlbnRhdGl2ZSBIb3N0ZWRDb25maWcsIHNvIG5vdGhpbmcgY2FuIGFjY2lkZW50YWxseSB1c2Ugb25lIGVudHJ5J3Mgcm91dGUgb3IgZmxhZ3Mgd2hlcmUgdGhlIHVuaW9uIGlzIHJlcXVpcmVkIC0gdGhlIHN0YW5kYXJkIGNvbmZpZyBoYXMgdGhlIHNhbWUgVVJMIHR3aWNlOiBhIHJvdXRlZCB3cml0ZS1zaGFyZCBlbnRyeSBwbHVzIGFuIHVucm91dGVkIHJlYWQtZXZlcnl0aGluZyBlbnRyeS4gKi9cbmV4cG9ydCB0eXBlIFNlbGZTdW1tYXJ5ID0ge1xuICAgIC8qKiBUaGUgdW5pb24gb2YgdGhlIGN1cnJlbnQgZW50cmllcycgcm91dGVzLCB3aXRoIG92ZXJsYXBwaW5nL2FkamFjZW50IHJhbmdlcyBjb21iaW5lZCAtIHdoaWNoIGNvbW1vbmx5IGNvbGxhcHNlcyB0byBhIHNpbmdsZSBmdWxsIHJhbmdlLCBtYWtpbmcgbWF0Y2hpbmcgdHJpdmlhbC4gKi9cbiAgICByb3V0ZXM6IFtudW1iZXIsIG51bWJlcl1bXTtcbiAgICBwdWJsaWM6IGJvb2xlYW47XG4gICAgaW1tdXRhYmxlOiBib29sZWFuO1xuICAgIG5vRnVsbFN5bmM6IGJvb2xlYW47XG4gICAgcmVhZGVyRGlza0xpbWl0PzogbnVtYmVyO1xufTtcblxuZnVuY3Rpb24gbWVyZ2VSb3V0ZXMocm91dGVzOiAoW251bWJlciwgbnVtYmVyXSB8IHVuZGVmaW5lZClbXSk6IFtudW1iZXIsIG51bWJlcl1bXSB7XG4gICAgbGV0IGxpc3QgPSByb3V0ZXMubWFwKHggPT4geCB8fCBGVUxMX1JPVVRFKS5tYXAoeCA9PiBbeFswXSwgeFsxXV0gYXMgW251bWJlciwgbnVtYmVyXSk7XG4gICAgc29ydChsaXN0LCB4ID0+IHhbMF0pO1xuICAgIGxldCBtZXJnZWQ6IFtudW1iZXIsIG51bWJlcl1bXSA9IFtdO1xuICAgIGZvciAobGV0IHJvdXRlIG9mIGxpc3QpIHtcbiAgICAgICAgbGV0IGxhc3QgPSBtZXJnZWRbbWVyZ2VkLmxlbmd0aCAtIDFdO1xuICAgICAgICBpZiAobGFzdCAmJiByb3V0ZVswXSA8PSBsYXN0WzFdKSB7XG4gICAgICAgICAgICBsYXN0WzFdID0gTWF0aC5tYXgobGFzdFsxXSwgcm91dGVbMV0pO1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgbWVyZ2VkLnB1c2gocm91dGUpO1xuICAgIH1cbiAgICByZXR1cm4gbWVyZ2VkO1xufVxuXG5mdW5jdGlvbiBzdW1tYXJpemVTZWxmKHNlbGZFbnRyaWVzOiBIb3N0ZWRDb25maWdbXSwgbm93OiBudW1iZXIpOiBTZWxmU3VtbWFyeSB8IHVuZGVmaW5lZCB7XG4gICAgbGV0IGN1cnJlbnQgPSBzZWxmRW50cmllcy5maWx0ZXIoeCA9PiB4LnZhbGlkV2luZG93WzBdIDw9IG5vdyAmJiBub3cgPCB4LnZhbGlkV2luZG93WzFdKTtcbiAgICBpZiAoIWN1cnJlbnQubGVuZ3RoKSB7XG4gICAgICAgIGxldCBuZWFyZXN0ID0gc2VsZWN0RW50cnlBdChzZWxmRW50cmllcywgbm93KTtcbiAgICAgICAgY3VycmVudCA9IG5lYXJlc3QgJiYgW25lYXJlc3RdIHx8IFtdO1xuICAgIH1cbiAgICBpZiAoIWN1cnJlbnQubGVuZ3RoKSB7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuICAgIHJldHVybiB7XG4gICAgICAgIHJvdXRlczogbWVyZ2VSb3V0ZXMoY3VycmVudC5tYXAoeCA9PiB4LnJvdXRlKSksXG4gICAgICAgIHB1YmxpYzogY3VycmVudC5zb21lKHggPT4geC5wdWJsaWMpLFxuICAgICAgICBpbW11dGFibGU6IGN1cnJlbnQuc29tZSh4ID0+IHguaW1tdXRhYmxlKSxcbiAgICAgICAgbm9GdWxsU3luYzogY3VycmVudC5zb21lKHggPT4geC5ub0Z1bGxTeW5jKSxcbiAgICAgICAgcmVhZGVyRGlza0xpbWl0OiBjdXJyZW50LmZpbmQoeCA9PiB4LnJlYWRlckRpc2tMaW1pdCAhPT0gdW5kZWZpbmVkKT8ucmVhZGVyRGlza0xpbWl0LFxuICAgIH07XG59XG5cbi8qKiBPbmUgc3RvcmUgdGhpcyBzZXJ2ZXIgcnVucyBmb3IgYSBidWNrZXQ6IHRoZSBuYW1lIHRoYXQgSVMgdGhlIHN0b3JlLCBhbmQgdGhlIGVudHJpZXMgdGhhdCBuYW1lIGl0LiBXaGF0IGl0IHN5bmNocm9uaXplcyB3aXRoIGlzIE5PVCBkZWNpZGVkIGhlcmUgLSB0aGUgc3RvcmUgcmVhZHMgaXRzIG93biBjb3B5IG9mIHRoZSBjb25maWcgYW5kIHdvcmtzIHRoYXQgb3V0IGl0c2VsZiAoc2VlIEJsb2JTdG9yZS5hcHBseVJvdXRpbmdDb25maWcpLiAqL1xuZXhwb3J0IHR5cGUgU2VsZlN0b3JlID0ge1xuICAgIG5hbWU6IHN0cmluZztcbiAgICBlbnRyaWVzOiBIb3N0ZWRDb25maWdbXTtcbn07XG5cbi8qKiBXaGljaCBzdG9yZXMgdGhpcyBzZXJ2ZXIgcnVucyBmb3IgYSBidWNrZXQsIGJ5IG5hbWUuIE5vdGhpbmcgbW9yZTogYSBzdG9yZSBpcyBmb3VuZCBieSBuYW1lLCBhbmQgY29uZmlndXJlcyBpdHNlbGYuICovXG5leHBvcnQgZnVuY3Rpb24gcGxhblNlbGZTdG9yZXMoYWNjb3VudDogc3RyaW5nLCBidWNrZXROYW1lOiBzdHJpbmcsIHJvdXRpbmc6IFJlbW90ZUNvbmZpZyk6IHsgc2VsZkVudHJpZXM6IEhvc3RlZENvbmZpZ1tdOyBzZWxmOiBTZWxmU3VtbWFyeSB8IHVuZGVmaW5lZDsgc3RvcmVzOiBTZWxmU3RvcmVbXSB9IHtcbiAgICBsZXQgc2VsZkluZGV4ZXMgPSBmaW5kU2VsZkluZGV4ZXMocm91dGluZywgYWNjb3VudCwgYnVja2V0TmFtZSk7XG4gICAgbGV0IHNlbGZFbnRyaWVzID0gc2VsZkluZGV4ZXMubWFwKGkgPT4gcm91dGluZy5zb3VyY2VzW2ldIGFzIEhvc3RlZENvbmZpZyk7XG4gICAgbGV0IHNlbGYgPSBzdW1tYXJpemVTZWxmKHNlbGZFbnRyaWVzLCBEYXRlLm5vdygpKTtcbiAgICAvLyBPbmUgc3RvcmUgcGVyIE5BTUUgYW1vbmcgQUxMIG91ciBlbnRyaWVzIC0gcGFzdCBhbmQgZnV0dXJlIHdpbmRvd3MgaW5jbHVkZWQsIHNvIGEgbmFtZSB3ZSBubyBsb25nZXIgd3JpdGUgdG8ga2VlcHMgc2VydmluZyBpdHMgZGF0YSBhbmQgYSBuYW1lIHdlIGFyZSBhYm91dCB0byB1c2UgZXhpc3RzIGFoZWFkIG9mIGl0cyB3aW5kb3dcbiAgICBsZXQgYnlOYW1lID0gbmV3IE1hcDxzdHJpbmcsIEhvc3RlZENvbmZpZ1tdPigpO1xuICAgIGZvciAobGV0IGVudHJ5IG9mIHNlbGZFbnRyaWVzKSB7XG4gICAgICAgIGxldCBlbnRyaWVzID0gYnlOYW1lLmdldChlbnRyeS5uYW1lKTtcbiAgICAgICAgaWYgKCFlbnRyaWVzKSB7XG4gICAgICAgICAgICBlbnRyaWVzID0gW107XG4gICAgICAgICAgICBieU5hbWUuc2V0KGVudHJ5Lm5hbWUsIGVudHJpZXMpO1xuICAgICAgICB9XG4gICAgICAgIGVudHJpZXMucHVzaChlbnRyeSk7XG4gICAgfVxuICAgIC8vIE5vdCBpbiB0aGUgY29uZmlnIGF0IGFsbDogbm8gbmFtZSBtZWFucyBubyBzdG9yZSBoZXJlXG4gICAgcmV0dXJuIHsgc2VsZkVudHJpZXMsIHNlbGYsIHN0b3JlczogWy4uLmJ5TmFtZV0ubWFwKChbbmFtZSwgZW50cmllc10pID0+ICh7IG5hbWUsIGVudHJpZXMgfSkpIH07XG59XG4iXX0=
|
|
187
|
-
/* _JS_SOURCE_HASH = "34bdac815bba6b0da86e3b712610c28994f577faf6bb0acd7d09b73d2d301e81"; */
|
|
134
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RvcmVQbGFuLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsic3RvcmVQbGFuLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLDRDQUFvRjtBQUNwRixpREFBa0Y7QUFDbEYsaURBQThDO0FBRTlDLG9SQUFvUjtBQUVwUix3SUFBd0k7QUFDeEksU0FBZ0IsWUFBWSxDQUFDLE1BQW9CLEVBQUUsT0FBZSxFQUFFLFVBQWtCO0lBQ2xGLElBQUksTUFBTSxDQUFDLElBQUksS0FBSyxRQUFRO1FBQUUsT0FBTyxLQUFLLENBQUM7SUFDM0MsSUFBSSxNQUFNLEdBQUcsSUFBQSw2QkFBYyxFQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUN4QyxJQUFJLE1BQU0sQ0FBQyxPQUFPLEtBQUssT0FBTyxJQUFJLE1BQU0sQ0FBQyxVQUFVLEtBQUssVUFBVTtRQUFFLE9BQU8sS0FBSyxDQUFDO0lBQ2pGLE9BQU8sSUFBQSwyQkFBWSxFQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO0FBQ3JELENBQUM7QUFMRCxvQ0FLQztBQUVELFNBQWdCLGVBQWUsQ0FBQyxPQUFxQixFQUFFLE9BQWUsRUFBRSxVQUFrQjtJQUN0RixJQUFJLE9BQU8sR0FBYSxFQUFFLENBQUM7SUFDM0IsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7UUFDOUMsSUFBSSxNQUFNLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNoQyxJQUFJLE9BQU8sTUFBTSxLQUFLLFFBQVE7WUFBRSxTQUFTO1FBQ3pDLElBQUksWUFBWSxDQUFDLE1BQU0sRUFBRSxPQUFPLEVBQUUsVUFBVSxDQUFDLEVBQUUsQ0FBQztZQUM1QyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3BCLENBQUM7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O2dCQUFFLFNBQVM7WUFDekUsSUFBSSxFQUFFLFNBQVMsRUFBRSxPQUFPLEVBQUUsR0FBRyxhQUFhLENBQUMsU0FBUyxFQUFFLEtBQUssQ0FBQyxLQUFLLElBQUksc0JBQVUsQ0FBQyxDQUFDO1lBQ2pGLFNBQVMsR0FBRyxTQUFTLENBQUM7WUFDdEIsSUFBSSxDQUFDLE9BQU87Z0JBQUUsU0FBUztZQUN2QixJQUFJLFlBQVksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztnQkFDdEIsUUFBUSxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUM7Z0JBQzVCLFNBQVM7WUFDYixDQUFDO1lBQ0QsSUFBSSxRQUFRLEdBQUcsUUFBUSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDdkMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLFFBQVEsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFxQixJQUFJLE9BQU8sQ0FBQyxDQUFDO1FBQy9JLENBQUM7SUFDTCxDQUFDO0lBQ0QsT0FBTyxDQUFDLEdBQUcsT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLFdBQVcsSUFBSSxDQUFDLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO0FBQzlFLENBQUM7QUEzQ0Qsb0RBMkNDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgUmVtb3RlQ29uZmlnLCBIb3N0ZWRDb25maWcsIFNvdXJjZUNvbmZpZywgRlVMTF9ST1VURSB9IGZyb20gXCIuLi9JQXJjaGl2ZXNcIjtcbmltcG9ydCB7IHBhcnNlSG9zdGVkVXJsLCByb3V0ZUNvbnRhaW5zLCByb3V0ZUludGVyc2VjdGlvbiB9IGZyb20gXCIuL3JlbW90ZUNvbmZpZ1wiO1xuaW1wb3J0IHsgaXNPd25BZGRyZXNzIH0gZnJvbSBcIi4vc2VydmVyQ29uZmlnXCI7XG5cbi8vIFB1cmUgaGVscGVycyBvdmVyIGEgYnVja2V0J3Mgcm91dGluZyBjb25maWc6IHdoaWNoIGVudHJpZXMgYXJlIHRoaXMgc2VydmVyLCB3aGljaCBlbnRyeSBhcHBsaWVzIGF0IGEgbW9tZW50LCBhbmQgd2hvIG93bmVkIHdoYXQgYmVmb3JlIGEgd2luZG93IGJvdW5kYXJ5LiBDb25maWcgaW4sIGFuc3dlciBvdXQgLSBub3RoaW5nIGhlcmUgcmVhZHMgYSBzdG9yZSwgYSBjbG9jaywgb3IgdGhlIG5ldHdvcmsgKGV4Y2VwdCBzZWxlY3RFbnRyeUF0IGJlaW5nIGhhbmRlZCBhIHRpbWUpLlxuXG4vKiogV2hldGhlciBhIGNvbmZpZyBlbnRyeSBpcyBUSElTIHNlcnZlcidzIGNvcHkgb2YgdGhpcyBidWNrZXQgLSB0aGUgc2FtZSBhY2NvdW50IGFuZCBidWNrZXQsIGF0IGFuIGFkZHJlc3MgdGhpcyBwcm9jZXNzIGFuc3dlcnMgb24uICovXG5leHBvcnQgZnVuY3Rpb24gaXNTZWxmU291cmNlKHNvdXJjZTogU291cmNlQ29uZmlnLCBhY2NvdW50OiBzdHJpbmcsIGJ1Y2tldE5hbWU6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIGlmIChzb3VyY2UudHlwZSAhPT0gXCJyZW1vdGVcIikgcmV0dXJuIGZhbHNlO1xuICAgIGxldCBwYXJzZWQgPSBwYXJzZUhvc3RlZFVybChzb3VyY2UudXJsKTtcbiAgICBpZiAocGFyc2VkLmFjY291bnQgIT09IGFjY291bnQgfHwgcGFyc2VkLmJ1Y2tldE5hbWUgIT09IGJ1Y2tldE5hbWUpIHJldHVybiBmYWxzZTtcbiAgICByZXR1cm4gaXNPd25BZGRyZXNzKHBhcnNlZC5hZGRyZXNzLCBwYXJzZWQucG9ydCk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBmaW5kU2VsZkluZGV4ZXMocm91dGluZzogUmVtb3RlQ29uZmlnLCBhY2NvdW50OiBzdHJpbmcsIGJ1Y2tldE5hbWU6IHN0cmluZyk6IG51bWJlcltdIHtcbiAgICBsZXQgaW5kZXhlczogbnVtYmVyW10gPSBbXTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHJvdXRpbmcuc291cmNlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICBsZXQgc291cmNlID0gcm91dGluZy5zb3VyY2VzW2ldO1xuICAgICAgICBpZiAodHlwZW9mIHNvdXJjZSA9PT0gXCJzdHJpbmdcIikgY29udGludWU7XG4gICAgICAgIGlmIChpc1NlbGZTb3VyY2Uoc291cmNlLCBhY2NvdW50LCBidWNrZXROYW1lKSkge1xuICAgICAgICAgICAgaW5kZXhlcy5wdXNoKGkpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBpbmRleGVzO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gc2VsZWN0RW50cnlBdChlbnRyaWVzOiBIb3N0ZWRDb25maWdbXSwgdGltZTogbnVtYmVyLCByb3V0ZT86IG51bWJlcik6IEhvc3RlZENvbmZpZyB8IHVuZGVmaW5lZCB7XG4gICAgaWYgKHJvdXRlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgbGV0IGNvdmVyaW5nID0gZW50cmllcy5maWx0ZXIoeCA9PiByb3V0ZUNvbnRhaW5zKHgucm91dGUsIHJvdXRlKSk7XG4gICAgICAgIGlmIChjb3ZlcmluZy5sZW5ndGgpIHtcbiAgICAgICAgICAgIGVudHJpZXMgPSBjb3ZlcmluZztcbiAgICAgICAgfVxuICAgIH1cbiAgICBsZXQgY29udGFpbmluZyA9IGVudHJpZXMuZmluZCh4ID0+IHgudmFsaWRXaW5kb3dbMF0gPD0gdGltZSAmJiB0aW1lIDwgeC52YWxpZFdpbmRvd1sxXSk7XG4gICAgaWYgKGNvbnRhaW5pbmcpIHJldHVybiBjb250YWluaW5nO1xuICAgIGxldCBiZXN0OiBIb3N0ZWRDb25maWcgfCB1bmRlZmluZWQ7XG4gICAgbGV0IGJlc3REaXN0YW5jZSA9IEluZmluaXR5O1xuICAgIGZvciAobGV0IGVudHJ5IG9mIGVudHJpZXMpIHtcbiAgICAgICAgbGV0IGRpc3RhbmNlID0gTWF0aC5taW4oTWF0aC5hYnModGltZSAtIGVudHJ5LnZhbGlkV2luZG93WzBdKSwgTWF0aC5hYnModGltZSAtIGVudHJ5LnZhbGlkV2luZG93WzFdKSk7XG4gICAgICAgIGlmIChkaXN0YW5jZSA8IGJlc3REaXN0YW5jZSkge1xuICAgICAgICAgICAgYmVzdERpc3RhbmNlID0gZGlzdGFuY2U7XG4gICAgICAgICAgICBiZXN0ID0gZW50cnk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGJlc3Q7XG59XG5cbi8qKiBUaGUgcGFydHMgb2YgYHJhbmdlc2AgdGhhdCBgY3V0YCBkb2VzIG5vdCBjb3ZlciwgcGx1cyB0aGUgc2luZ2xlIHJhbmdlIHNwYW5uaW5nIHdoYXQgaXQgZGlkLiBSb3V0ZXMgYXJlIGhhbGYtb3BlbiBbc3RhcnQsIGVuZCksIHNvIHN1YnRyYWN0aW5nIG9uZSBmcm9tIGFub3RoZXIgbGVhdmVzIGF0IG1vc3QgYSBwaWVjZSBvbiBlYWNoIHNpZGUuICovXG5mdW5jdGlvbiBzdWJ0cmFjdFJvdXRlKHJhbmdlczogW251bWJlciwgbnVtYmVyXVtdLCBjdXQ6IFtudW1iZXIsIG51bWJlcl0pOiB7IHJlbWFpbmluZzogW251bWJlciwgbnVtYmVyXVtdOyBjbGFpbWVkPzogW251bWJlciwgbnVtYmVyXSB9IHtcbiAgICBsZXQgcmVtYWluaW5nOiBbbnVtYmVyLCBudW1iZXJdW10gPSBbXTtcbiAgICBsZXQgY2xhaW1lZDogW251bWJlciwgbnVtYmVyXSB8IHVuZGVmaW5lZDtcbiAgICBmb3IgKGxldCByYW5nZSBvZiByYW5nZXMpIHtcbiAgICAgICAgbGV0IG92ZXJsYXAgPSByb3V0ZUludGVyc2VjdGlvbihyYW5nZSwgY3V0KTtcbiAgICAgICAgaWYgKCFvdmVybGFwKSB7XG4gICAgICAgICAgICByZW1haW5pbmcucHVzaChyYW5nZSk7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgICBjbGFpbWVkID0gY2xhaW1lZCAmJiBbTWF0aC5taW4oY2xhaW1lZFswXSwgb3ZlcmxhcFswXSksIE1hdGgubWF4KGNsYWltZWRbMV0sIG92ZXJsYXBbMV0pXSBhcyBbbnVtYmVyLCBudW1iZXJdIHx8IG92ZXJsYXA7XG4gICAgICAgIGlmIChyYW5nZVswXSA8IG92ZXJsYXBbMF0pIHJlbWFpbmluZy5wdXNoKFtyYW5nZVswXSwgb3ZlcmxhcFswXV0pO1xuICAgICAgICBpZiAob3ZlcmxhcFsxXSA8IHJhbmdlWzFdKSByZW1haW5pbmcucHVzaChbb3ZlcmxhcFsxXSwgcmFuZ2VbMV1dKTtcbiAgICB9XG4gICAgcmV0dXJuIHsgcmVtYWluaW5nLCBjbGFpbWVkIH07XG59XG5cbi8qKiBXaGF0IG9uZSBvZiBvdXIgc3RvcmVzIGhhcyB0byBwdWxsIGluIGF0IGEgdmFsaWQtd2luZG93IGJvdW5kYXJ5LCBzbyB0aGUgd3JpdGVzIHRoYXQgbGFuZGVkIGp1c3QgYmVmb3JlIHRoZSBoYW5kb3ZlciBhcmUgbm90IG1pc3NlZC4gKi9cbmV4cG9ydCB0eXBlIEJvdW5kYXJ5SGFuZG92ZXIgPSB7XG4gICAgLy8gVGhlIHN0b3JlIHRoYXQgbmVlZHMgdGhlIGRhdGE6IHRoZSBuYW1lIG9mIHRoZSBzZWxmIGVudHJ5IHRha2luZyBvdmVyIGF0IHRoZSBib3VuZGFyeVxuICAgIG5hbWU6IHN0cmluZztcbiAgICAvLyBUaGUgcm91dGUgaXQgaXMgdGFraW5nIG92ZXIsIHdoaWNoIGlzIHRoZSBzbGljZSBvZiB0aGUga2V5IHNwYWNlIHRoZSBwdWxscyBiZWxvdyBhcmUgbGltaXRlZCB0b1xuICAgIHJvdXRlOiBbbnVtYmVyLCBudW1iZXJdO1xuICAgIC8vIFdlIGhlbGQgcGFydCBvZiB0aGlzIHJvdXRlIGluIHRoZSBwcmV2aW91cyB3aW5kb3cgdG9vLCBzbyB0aG9zZSB3cml0ZXMgYXJlIGFscmVhZHkgaW4gb3VyIG93biBmb2xkZXIgYW5kIGEgZGlzayByZXNjYW4gZmluZHMgdGhlbVxuICAgIHNjYW5Pd25EaXNrOiBib29sZWFuO1xuICAgIC8vIFBlciBzb3VyY2UgaW5kZXggaW4gdGhlIGNvbmZpZywgdGhlIHNsaWNlIG9mIG91ciByb3V0ZSBUSEFUIHNvdXJjZSBoZWxkIGluIHRoZSBwcmV2aW91cyB3aW5kb3cgLSBhIGJvdW5kYXJ5IHNjYW4gcHVsbHMgaXRzIHJlY2VudCBjaGFuZ2VzXG4gICAgcmVtb3RlczogTWFwPG51bWJlciwgW251bWJlciwgbnVtYmVyXT47XG59O1xuXG4vKipcbiAqIFdobyBoZWxkIGVhY2ggc2xpY2Ugb2Ygb3VyIHJvdXRlIGluIHRoZSB3aW5kb3cgYmVmb3JlIHdpbmRvd1N0YXJ0LCBmb3IgZXZlcnkgc2VsZiBlbnRyeSB3aG9zZVxuICogd2luZG93IHN0YXJ0cyBleGFjdGx5IHRoZW4uIFRoaXMgaXMgdGhlIHdob2xlIG9mIFwid2hvIGRvIHdlIHRha2Ugb3ZlciBmcm9tXCI6IGEgc3RvcmUgdGFraW5nIG92ZXIgYVxuICogcm91dGUgbWF5IGJlIHRha2luZyBpdCBmcm9tIHNldmVyYWwgcHJldmlvdXMgb3duZXJzIGF0IG9uY2UgKHRoZWlyIHNoYXJkcyBuZWVkIG5vdCBsaW5lIHVwIHdpdGhcbiAqIG91cnMpLCBhbmQgZnJvbSBpdHNlbGYgZm9yIHRoZSBwYXJ0cyBpdCBhbHJlYWR5IGhlbGQuXG4gKlxuICogQSBzZWxmIGVudHJ5IGlzIHNraXBwZWQgd2hlbiBhbiBFQVJMSUVSIGVudHJ5IHZhbGlkIGF0IHRoZSBib3VuZGFyeSBhbHJlYWR5IGNvdmVycyBpdHMgd2hvbGUgcm91dGU6XG4gKiBjb25maWcgb3JkZXIgaXMgcHJpb3JpdHksIHNvIHRoYXQgZW50cnkgaXMgdGhlIHdyaXRlIHRhcmdldCBhbmQgd2UgYXJlIG5vdCB0aGUgb25lIHRha2luZyBvdmVyLlxuICogT3duZXJzIGFyZSB0aGVuIHJlc29sdmVkIGluIGNvbmZpZyBvcmRlciB0b28sIGVhY2ggY2xhaW1pbmcgdGhlIHBhcnQgb2Ygb3VyIHJvdXRlIHN0aWxsIHVuY2xhaW1lZCAtXG4gKiB0aGUgc2FtZSBmaXJzdC1tYXRjaC13aW5zIHJ1bGUgdGhhdCBwaWNrcyBhIHdyaXRlIHRhcmdldCBhdCBhbnkgb3RoZXIgbW9tZW50LlxuICpcbiAqIFB1cmU6IGNvbmZpZyBpbiwgcGxhbiBvdXQuIE5vdGhpbmcgaGVyZSByZWFkcyBhIHN0b3JlLCBhIGNsb2NrLCBvciB0aGUgbmV0d29yay5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHByZXZpb3VzV2luZG93T3duZXJzKGNvbmZpZzogUmVtb3RlQ29uZmlnLCB3aW5kb3dTdGFydDogbnVtYmVyLCBzZWxmSW5kZXhlczogbnVtYmVyW10pOiBCb3VuZGFyeUhhbmRvdmVyW10ge1xuICAgIGxldCBzZWxmSW5kZXhTZXQgPSBuZXcgU2V0KHNlbGZJbmRleGVzKTtcbiAgICBsZXQgcHJldmlvdXNUaW1lID0gd2luZG93U3RhcnQgLSAxO1xuICAgIGxldCB2YWxpZEF0ID0gKHNvdXJjZTogU291cmNlQ29uZmlnLCB0aW1lOiBudW1iZXIpID0+IHNvdXJjZS52YWxpZFdpbmRvd1swXSA8PSB0aW1lICYmIHRpbWUgPCBzb3VyY2UudmFsaWRXaW5kb3dbMV07XG4gICAgbGV0IGJ5Um91dGUgPSBuZXcgTWFwPHN0cmluZywgQm91bmRhcnlIYW5kb3Zlcj4oKTtcbiAgICBmb3IgKGxldCBzZWxmSW5kZXggb2Ygc2VsZkluZGV4ZXMpIHtcbiAgICAgICAgbGV0IHNlbGYgPSBjb25maWcuc291cmNlc1tzZWxmSW5kZXhdO1xuICAgICAgICBpZiAodHlwZW9mIHNlbGYgPT09IFwic3RyaW5nXCIgfHwgc2VsZi52YWxpZFdpbmRvd1swXSAhPT0gd2luZG93U3RhcnQpIGNvbnRpbnVlO1xuICAgICAgICBsZXQgc2VsZlJvdXRlID0gc2VsZi5yb3V0ZSB8fCBGVUxMX1JPVVRFO1xuICAgICAgICBsZXQgc2hhZG93ZWQgPSBmYWxzZTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzZWxmSW5kZXg7IGkrKykge1xuICAgICAgICAgICAgbGV0IG90aGVyID0gY29uZmlnLnNvdXJjZXNbaV07XG4gICAgICAgICAgICBpZiAodHlwZW9mIG90aGVyID09PSBcInN0cmluZ1wiIHx8ICF2YWxpZEF0KG90aGVyLCB3aW5kb3dTdGFydCkpIGNvbnRpbnVlO1xuICAgICAgICAgICAgbGV0IHJvdXRlID0gb3RoZXIucm91dGUgfHwgRlVMTF9ST1VURTtcbiAgICAgICAgICAgIGlmIChyb3V0ZVswXSA8PSBzZWxmUm91dGVbMF0gJiYgc2VsZlJvdXRlWzFdIDw9IHJvdXRlWzFdKSB7XG4gICAgICAgICAgICAgICAgc2hhZG93ZWQgPSB0cnVlO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmIChzaGFkb3dlZCkgY29udGludWU7XG4gICAgICAgIC8vIEtleWVkIGJ5IGJvdGg6IG9uZSBuYW1lIGNhbiB0YWtlIG92ZXIgc2V2ZXJhbCByb3V0ZXMgYXQgdGhlIHNhbWUgYm91bmRhcnksIGFuZCBlYWNoIGlzIHB1bGxlZCBzZXBhcmF0ZWx5XG4gICAgICAgIGxldCBoYW5kb3ZlcktleSA9IGAke3NlbGYubmFtZX18JHtKU09OLnN0cmluZ2lmeShzZWxmUm91dGUpfWA7XG4gICAgICAgIGxldCBoYW5kb3ZlciA9IGJ5Um91dGUuZ2V0KGhhbmRvdmVyS2V5KTtcbiAgICAgICAgaWYgKCFoYW5kb3Zlcikge1xuICAgICAgICAgICAgaGFuZG92ZXIgPSB7IG5hbWU6IHNlbGYubmFtZSwgcm91dGU6IHNlbGZSb3V0ZSwgc2Nhbk93bkRpc2s6IGZhbHNlLCByZW1vdGVzOiBuZXcgTWFwKCkgfTtcbiAgICAgICAgICAgIGJ5Um91dGUuc2V0KGhhbmRvdmVyS2V5LCBoYW5kb3Zlcik7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IHVuY2xhaW1lZDogW251bWJlciwgbnVtYmVyXVtdID0gW1tzZWxmUm91dGVbMF0sIHNlbGZSb3V0ZVsxXV1dO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGNvbmZpZy5zb3VyY2VzLmxlbmd0aCAmJiB1bmNsYWltZWQubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGxldCBvdGhlciA9IGNvbmZpZy5zb3VyY2VzW2ldO1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBvdGhlciA9PT0gXCJzdHJpbmdcIiB8fCAhdmFsaWRBdChvdGhlciwgcHJldmlvdXNUaW1lKSkgY29udGludWU7XG4gICAgICAgICAgICBsZXQgeyByZW1haW5pbmcsIGNsYWltZWQgfSA9IHN1YnRyYWN0Um91dGUodW5jbGFpbWVkLCBvdGhlci5yb3V0ZSB8fCBGVUxMX1JPVVRFKTtcbiAgICAgICAgICAgIHVuY2xhaW1lZCA9IHJlbWFpbmluZztcbiAgICAgICAgICAgIGlmICghY2xhaW1lZCkgY29udGludWU7XG4gICAgICAgICAgICBpZiAoc2VsZkluZGV4U2V0LmhhcyhpKSkge1xuICAgICAgICAgICAgICAgIGhhbmRvdmVyLnNjYW5Pd25EaXNrID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxldCBleGlzdGluZyA9IGhhbmRvdmVyLnJlbW90ZXMuZ2V0KGkpO1xuICAgICAgICAgICAgaGFuZG92ZXIucmVtb3Rlcy5zZXQoaSwgZXhpc3RpbmcgJiYgW01hdGgubWluKGV4aXN0aW5nWzBdLCBjbGFpbWVkWzBdKSwgTWF0aC5tYXgoZXhpc3RpbmdbMV0sIGNsYWltZWRbMV0pXSBhcyBbbnVtYmVyLCBudW1iZXJdIHx8IGNsYWltZWQpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBbLi4uYnlSb3V0ZS52YWx1ZXMoKV0uZmlsdGVyKHggPT4geC5zY2FuT3duRGlzayB8fCB4LnJlbW90ZXMuc2l6ZSk7XG59XG5cbiJdfQ==
|
|
135
|
+
/* _JS_SOURCE_HASH = "13281f47f964117e77880e640758502933893081f631d576b59362f111f165cd"; */
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { RemoteConfig } from "../IArchives";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export declare function scheduleBoundaryWork(loaded: BucketState): void;
|
|
2
|
+
/** Called every time a store applies a routing config to itself (see BlobStore's onRoutingApplied): arms the scans the config's upcoming window boundaries need. Each scan is scheduled once - the key includes the boundary it is for - so re-arming on every config application is harmless. */
|
|
3
|
+
export declare function scheduleBoundaryWork(account: string, bucketName: string, routing: RemoteConfig): void;
|
|
5
4
|
/** An operator's config knows nothing about a switchover that is in flight right now, so writing it as-is would cancel one mid-handover. The in-flight windows are put back into it first. */
|
|
6
5
|
export declare function reinjectIntermediates(current: RemoteConfig | undefined, incoming: RemoteConfig): RemoteConfig;
|
|
7
6
|
/** 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. */
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { lazy } from "socket-function/src/caching";
|
|
2
2
|
import { runInfinitePoll } from "socket-function/src/batching";
|
|
3
3
|
import { RemoteConfig, SourceConfig, HostedConfig } from "../IArchives";
|
|
4
|
-
import { ROUTING_FILE, getConfigVersion, serializeRemoteConfig, parseHostedUrl, replaceHostedUrlPort } from "./remoteConfig";
|
|
4
|
+
import { ROUTING_FILE, getConfigVersion, serializeRemoteConfig, parseRoutingData, parseHostedUrl, replaceHostedUrlPort } from "./remoteConfig";
|
|
5
5
|
import { injectIntermediateSource, expireIntermediateSources, getIntermediateSources, nextIntermediateVersion, INTERMEDIATE_EXPIRE_GRACE } from "./intermediateSources";
|
|
6
6
|
import { getTakeoverIntermediate } from "./deployTakeover";
|
|
7
7
|
import { getStorageServerConfig } from "./serverConfig";
|
|
8
8
|
import { createApiArchives, listServerActiveBucketKeys } from "./createArchives";
|
|
9
9
|
import { findSelfIndexes, previousWindowOwners } from "./storePlan";
|
|
10
|
-
import {
|
|
10
|
+
import { getActiveBucketKeys, getStore, activateBucket, writeRoutingConfig } from "./storageServerState";
|
|
11
|
+
import { readRoutingFromDisk, readNewestRoutingFile } from "./bucketDisk";
|
|
11
12
|
import { DEFAULT_FAST_WRITE_DELAY } from "./ArchivesDelayed";
|
|
12
13
|
import { WINDOW_END_FLUSH_MARGIN } from "./blobStore";
|
|
13
14
|
|
|
@@ -26,19 +27,20 @@ const INTERMEDIATE_MAINTAIN_INTERVAL = 60 * 1000;
|
|
|
26
27
|
const scheduledBoundaryScans = new Set<string>();
|
|
27
28
|
const boundaryScansRunning = new Set<string>();
|
|
28
29
|
|
|
29
|
-
/** Called
|
|
30
|
-
export function scheduleBoundaryWork(
|
|
31
|
-
let key = `${
|
|
30
|
+
/** Called every time a store applies a routing config to itself (see BlobStore's onRoutingApplied): arms the scans the config's upcoming window boundaries need. Each scan is scheduled once - the key includes the boundary it is for - so re-arming on every config application is harmless. */
|
|
31
|
+
export function scheduleBoundaryWork(account: string, bucketName: string, routing: RemoteConfig): void {
|
|
32
|
+
let key = `${account}/${bucketName}`;
|
|
33
|
+
let selfEntries = findSelfIndexes(routing, account, bucketName).map(i => routing.sources[i] as HostedConfig);
|
|
32
34
|
let now = Date.now();
|
|
33
35
|
let starts = new Set<number>();
|
|
34
|
-
for (let self of
|
|
36
|
+
for (let self of selfEntries) {
|
|
35
37
|
let start = self.validWindow[0];
|
|
36
38
|
if (start > now && start < Number.MAX_SAFE_INTEGER) {
|
|
37
39
|
starts.add(start);
|
|
38
40
|
}
|
|
39
41
|
}
|
|
40
42
|
// A window we have only just taken over, on a server that has only just started: the boundary happened while we were not running, so its scan still has to happen
|
|
41
|
-
for (let self of
|
|
43
|
+
for (let self of selfEntries) {
|
|
42
44
|
let [start, end] = self.validWindow;
|
|
43
45
|
if (!(start <= now && now < end) || start <= 0) continue;
|
|
44
46
|
if (now - start > BOUNDARY_SCAN_LOOKBACK) continue;
|
|
@@ -46,7 +48,7 @@ export function scheduleBoundaryWork(loaded: BucketState): void {
|
|
|
46
48
|
if (scheduledBoundaryScans.has(scheduleKey)) continue;
|
|
47
49
|
scheduledBoundaryScans.add(scheduleKey);
|
|
48
50
|
let timer = setTimeout(() => {
|
|
49
|
-
void runBoundaryScan(
|
|
51
|
+
void runBoundaryScan(account, bucketName, start, STARTUP_BOUNDARY_SCAN_DELAY, "startup+30s").catch((e: Error) => console.error(`Boundary scan for bucket ${key} failed: ${e.stack ?? e}`));
|
|
50
52
|
}, STARTUP_BOUNDARY_SCAN_DELAY);
|
|
51
53
|
(timer as { unref?: () => void }).unref?.();
|
|
52
54
|
}
|
|
@@ -64,7 +66,7 @@ export function scheduleBoundaryWork(loaded: BucketState): void {
|
|
|
64
66
|
arm();
|
|
65
67
|
return;
|
|
66
68
|
}
|
|
67
|
-
void runBoundaryScan(
|
|
69
|
+
void runBoundaryScan(account, bucketName, start, offset).catch((e: Error) => console.error(`Boundary scan for bucket ${key} failed: ${e.stack ?? e}`));
|
|
68
70
|
}, Math.min(at - Date.now(), MAX_TIMER_DELAY));
|
|
69
71
|
(timer as { unref?: () => void }).unref?.();
|
|
70
72
|
};
|
|
@@ -73,9 +75,9 @@ export function scheduleBoundaryWork(loaded: BucketState): void {
|
|
|
73
75
|
}
|
|
74
76
|
}
|
|
75
77
|
|
|
76
|
-
/** Collects the writes that landed on the previous window's owners just before a boundary, into the store that has just taken over. Who owned what is worked out purely from the config (see previousWindowOwners); this only does the pulling. */
|
|
77
|
-
async function runBoundaryScan(
|
|
78
|
-
let key = `${
|
|
78
|
+
/** Collects the writes that landed on the previous window's owners just before a boundary, into the store that has just taken over. Who owned what is worked out purely from the config (see previousWindowOwners); this only does the pulling. The config is read off the disk at FIRE time, not captured when the scan was armed - it may have changed in between, and the newest copy is the one the handover actually happened under. */
|
|
79
|
+
async function runBoundaryScan(account: string, bucketName: string, windowStart: number, offset: number, offsetLabel?: string): Promise<void> {
|
|
80
|
+
let key = `${account}/${bucketName}`;
|
|
79
81
|
let label = `bucket ${key}, window starting ${new Date(windowStart).toISOString()}, offset ${offsetLabel || `${offset / 1000}s`}`;
|
|
80
82
|
if (boundaryScansRunning.has(key)) {
|
|
81
83
|
console.log(`Skipping boundary scan (${label}): the previous boundary scan is still running`);
|
|
@@ -83,23 +85,22 @@ async function runBoundaryScan(loaded: BucketState, windowStart: number, offset:
|
|
|
83
85
|
}
|
|
84
86
|
boundaryScansRunning.add(key);
|
|
85
87
|
try {
|
|
86
|
-
let effective =
|
|
88
|
+
let effective = await readRoutingFromDisk(account, bucketName);
|
|
87
89
|
if (!effective) return;
|
|
88
|
-
let handovers = previousWindowOwners(effective, windowStart, findSelfIndexes(effective,
|
|
90
|
+
let handovers = previousWindowOwners(effective, windowStart, findSelfIndexes(effective, account, bucketName));
|
|
89
91
|
if (!handovers.length) return;
|
|
90
92
|
console.log(`Boundary scan (${label}): ${handovers.length} route(s) taking over: ${handovers.map(x => `${JSON.stringify(x.route)} from ${x.scanOwnDisk && "our own disk" || ""}${x.scanOwnDisk && x.remotes.size && " + " || ""}${[...x.remotes.keys()].map(i => `source ${i}`).join(", ")}`).join("; ")}`);
|
|
91
93
|
let since = windowStart - BOUNDARY_SCAN_LOOKBACK;
|
|
92
94
|
for (let handover of handovers) {
|
|
93
|
-
let selfStore =
|
|
94
|
-
if (!selfStore) continue;
|
|
95
|
+
let selfStore = getStore(account, bucketName, handover.name);
|
|
95
96
|
if (handover.scanOwnDisk) {
|
|
96
|
-
await selfStore.
|
|
97
|
+
await selfStore.rescanBase();
|
|
97
98
|
}
|
|
98
99
|
for (let [sourceIndex, route] of handover.remotes) {
|
|
99
100
|
let ownerSource = effective.sources[sourceIndex];
|
|
100
101
|
if (typeof ownerSource === "string") continue;
|
|
101
102
|
try {
|
|
102
|
-
await selfStore.
|
|
103
|
+
await selfStore.boundaryScanRemote(createApiArchives(ownerSource), { since, route });
|
|
103
104
|
} catch (e) {
|
|
104
105
|
console.error(`Boundary scan (${label}) of previous-window owner (source index ${sourceIndex}) failed: ${(e as Error).stack ?? e}`);
|
|
105
106
|
}
|
|
@@ -133,66 +134,69 @@ export function reinjectIntermediates(current: RemoteConfig | undefined, incomin
|
|
|
133
134
|
// Per bucket, not global: a switchover has to write every bucket's windows at once, and a shared throttle would let only one bucket through per interval
|
|
134
135
|
const lastOwnConfigWrite = new Map<string, number>();
|
|
135
136
|
|
|
136
|
-
async function writeOwnRoutingConfig(
|
|
137
|
-
let
|
|
137
|
+
async function writeOwnRoutingConfig(config: { account: string; bucketName: string; storeName: string; current: RemoteConfig; updated: RemoteConfig; reason: string }): Promise<void> {
|
|
138
|
+
let { account, bucketName, current, updated, reason } = config;
|
|
139
|
+
let key = `${account}/${bucketName}`;
|
|
138
140
|
let sinceLast = Date.now() - (lastOwnConfigWrite.get(key) || 0);
|
|
139
141
|
if (sinceLast < OWN_CONFIG_WRITE_THROTTLE) {
|
|
140
142
|
console.log(`Not writing our own routing config update for bucket ${key} (${reason}): the last one was ${sinceLast}ms ago, under the ${OWN_CONFIG_WRITE_THROTTLE}ms throttle. Retrying on the next maintenance pass.`);
|
|
141
143
|
return;
|
|
142
144
|
}
|
|
143
145
|
lastOwnConfigWrite.set(key, Date.now());
|
|
144
|
-
|
|
145
|
-
if (!loaded.routing) return;
|
|
146
|
-
let currentVersion = getConfigVersion(loaded.routing);
|
|
146
|
+
let currentVersion = getConfigVersion(current);
|
|
147
147
|
let version = nextIntermediateVersion(currentVersion);
|
|
148
148
|
let next: RemoteConfig = { ...updated, version };
|
|
149
149
|
console.log(`Writing ${ROUTING_FILE} for bucket ${key} (${reason}), version ${currentVersion} -> ${version}: ${JSON.stringify(next)}`);
|
|
150
150
|
let data = Buffer.from(serializeRemoteConfig(next));
|
|
151
|
-
// Into
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
await writeRoutingConfig(loaded.account, loaded.bucketName, ourStore.name, data);
|
|
155
|
-
}
|
|
156
|
-
await propagateRoutingConfig(loaded, next, data);
|
|
151
|
+
// Into the store holding the newest copy - it applies it and its peers pull it - and directly to the other servers, which is what makes a switchover take effect in seconds rather than at the next poll
|
|
152
|
+
await writeRoutingConfig(account, bucketName, config.storeName, data);
|
|
153
|
+
await propagateRoutingConfig({ account, bucketName, current, next, data });
|
|
157
154
|
}
|
|
158
155
|
|
|
159
|
-
async function propagateRoutingConfig(
|
|
156
|
+
async function propagateRoutingConfig(config: { account: string; bucketName: string; current: RemoteConfig; next: RemoteConfig; data: Buffer }): Promise<void> {
|
|
160
157
|
let targets = new Map<string, SourceConfig>();
|
|
161
|
-
for (let source of [...
|
|
158
|
+
for (let source of [...config.current.sources, ...config.next.sources]) {
|
|
162
159
|
if (typeof source === "string" || source.intermediate) continue;
|
|
163
160
|
if (source.type === "remote") {
|
|
164
161
|
let parsed = parseHostedUrl(source.url);
|
|
165
|
-
if (parsed.account !==
|
|
162
|
+
if (parsed.account !== config.account || parsed.bucketName !== config.bucketName) continue;
|
|
166
163
|
}
|
|
167
164
|
if (targets.has(source.url)) continue;
|
|
168
165
|
targets.set(source.url, source);
|
|
169
166
|
}
|
|
170
167
|
for (let [url, source] of targets) {
|
|
171
168
|
try {
|
|
172
|
-
await createApiArchives(source).set(ROUTING_FILE, data);
|
|
173
|
-
console.log(`Wrote ${ROUTING_FILE} for bucket ${
|
|
169
|
+
await createApiArchives(source).set(ROUTING_FILE, config.data);
|
|
170
|
+
console.log(`Wrote ${ROUTING_FILE} for bucket ${config.account}/${config.bucketName} to ${url}`);
|
|
174
171
|
} catch (e) {
|
|
175
172
|
console.error(`Propagating our routing config update to ${url} failed: ${(e as Error).stack ?? e}`);
|
|
176
173
|
}
|
|
177
174
|
}
|
|
178
175
|
}
|
|
179
176
|
|
|
180
|
-
/** Keeps every
|
|
177
|
+
/** Keeps every active bucket's switchover windows current: gives our alternate port its window while a takeover is in flight, and takes expired ones back out. */
|
|
181
178
|
async function maintainIntermediates(): Promise<void> {
|
|
182
179
|
let { domain, port } = getStorageServerConfig();
|
|
183
180
|
let takeover = getTakeoverIntermediate();
|
|
184
181
|
let written: string[] = [];
|
|
185
182
|
let alreadyCorrect: string[] = [];
|
|
186
183
|
let notOurs: string[] = [];
|
|
187
|
-
// ONLY buckets already
|
|
188
|
-
let
|
|
189
|
-
for (let
|
|
190
|
-
let key = `${
|
|
191
|
-
let
|
|
192
|
-
if (!
|
|
184
|
+
// ONLY buckets already active. A switchover must never activate a bucket: that 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 activates on that access, and the next pass gives it its window.
|
|
185
|
+
let activeKeys = getActiveBucketKeys();
|
|
186
|
+
for (let { account, bucketName } of activeKeys) {
|
|
187
|
+
let key = `${account}/${bucketName}`;
|
|
188
|
+
let newest = await readNewestRoutingFile(account, bucketName);
|
|
189
|
+
if (!newest) continue;
|
|
190
|
+
let routing: RemoteConfig;
|
|
191
|
+
try {
|
|
192
|
+
routing = parseRoutingData(newest.data);
|
|
193
|
+
} catch (e) {
|
|
194
|
+
console.error(`Skipping switchover maintenance for bucket ${key}: its routing config could not be parsed (${(e as Error).message})`);
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
193
197
|
let expired = expireIntermediateSources(routing, Date.now());
|
|
194
198
|
if (JSON.stringify(expired) !== JSON.stringify(routing)) {
|
|
195
|
-
await writeOwnRoutingConfig(
|
|
199
|
+
await writeOwnRoutingConfig({ account, bucketName, storeName: newest.name, current: routing, updated: expired, reason: `switchover windows expired more than ${INTERMEDIATE_EXPIRE_GRACE / 1000}s ago` });
|
|
196
200
|
written.push(key);
|
|
197
201
|
continue;
|
|
198
202
|
}
|
|
@@ -216,16 +220,16 @@ async function maintainIntermediates(): Promise<void> {
|
|
|
216
220
|
alreadyCorrect.push(key);
|
|
217
221
|
continue;
|
|
218
222
|
}
|
|
219
|
-
await writeOwnRoutingConfig(
|
|
223
|
+
await writeOwnRoutingConfig({ account, bucketName, storeName: newest.name, current: routing, updated: injected, reason: `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()}` });
|
|
220
224
|
written.push(key);
|
|
221
225
|
}
|
|
222
226
|
if (!takeover) return;
|
|
223
|
-
if (!
|
|
227
|
+
if (!activeKeys.length) {
|
|
224
228
|
console.log(`No active buckets, so no config files to write the intermediate into (a bucket is only active once something uses it)`);
|
|
225
229
|
return;
|
|
226
230
|
}
|
|
227
231
|
if (!written.length) {
|
|
228
|
-
console.log(`Wrote no config files: of ${
|
|
232
|
+
console.log(`Wrote no config files: of ${activeKeys.length} active buckets, ${alreadyCorrect.length} already contain the intermediate and ${notOurs.length} are not hosted by us`);
|
|
229
233
|
}
|
|
230
234
|
}
|
|
231
235
|
|
|
@@ -247,7 +251,10 @@ async function activatePredecessorBuckets(): Promise<void> {
|
|
|
247
251
|
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(", ")}`);
|
|
248
252
|
for (let { account, bucketName } of keys) {
|
|
249
253
|
try {
|
|
250
|
-
await
|
|
254
|
+
let result = await activateBucket(account, bucketName);
|
|
255
|
+
if (typeof result === "string") {
|
|
256
|
+
console.error(`Activating bucket ${account}/${bucketName} (active on our predecessor) failed: ${result}`);
|
|
257
|
+
}
|
|
251
258
|
} catch (e) {
|
|
252
259
|
console.error(`Activating bucket ${account}/${bucketName} (active on our predecessor) failed: ${(e as Error).stack ?? e}`);
|
|
253
260
|
}
|
|
@@ -9,11 +9,12 @@ import { getCommonName, getPublicIdentifier, getOwnMachineId, verify, verifyMach
|
|
|
9
9
|
import { ArchiveFileInfo, ArchivesConfig, ArchivesSyncStatus, FindConfig, SourceConfig, IMMUTABLE_CACHE_TIME } from "../IArchives";
|
|
10
10
|
import { ROUTING_FILE, getRoute, routeContains } from "./remoteConfig";
|
|
11
11
|
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
debugListAccountBuckets, ServerBucketInfo,
|
|
12
|
+
findBucketStore, getStore, getBucketStores, readBucketInternal, writeRoutingConfig,
|
|
13
|
+
getBucketArchivesConfig, bucketSyncStatus, debugBucketIndexTotals, ActiveBucketInfo,
|
|
14
|
+
debugListAccountBuckets, ServerBucketInfo,
|
|
15
15
|
debugGetActiveBucket, activateBucket, getActiveBucketKeys,
|
|
16
16
|
} from "./storageServerState";
|
|
17
|
+
import { debugClearAccountWriteStats } from "./accessStats";
|
|
17
18
|
import { getStorageServerConfig, getTrust, getRequests, assertWritesAllowed } from "./serverConfig";
|
|
18
19
|
import { BlobStore } from "./blobStore";
|
|
19
20
|
import { getRoutingFileResult } from "./bucketDisk";
|
|
@@ -332,7 +333,7 @@ class RemoteStorageControllerBase {
|
|
|
332
333
|
}
|
|
333
334
|
@assertValidArgs
|
|
334
335
|
async getArchivesConfig(config: { account: string; bucketName: string }): Promise<ArchivesConfig> {
|
|
335
|
-
return
|
|
336
|
+
return await getBucketArchivesConfig(config.account, config.bucketName);
|
|
336
337
|
}
|
|
337
338
|
@assertValidArgs
|
|
338
339
|
async listBuckets(config: { account: string }): Promise<ServerBucketInfo[]> {
|
|
@@ -372,11 +373,11 @@ class RemoteStorageControllerBase {
|
|
|
372
373
|
}
|
|
373
374
|
@assertValidArgs
|
|
374
375
|
async getIndexInfo(config: { account: string; bucketName: string }): Promise<{ fileCount: number; byteCount: number; sources: { debugName: string; fileCount: number; byteCount: number }[] } | undefined> {
|
|
375
|
-
return await debugBucketIndexTotals(
|
|
376
|
+
return await debugBucketIndexTotals(config.account, config.bucketName);
|
|
376
377
|
}
|
|
377
378
|
@assertValidArgs
|
|
378
379
|
async getSyncStatus(config: { account: string; bucketName: string }): Promise<ArchivesSyncStatus> {
|
|
379
|
-
return await bucketSyncStatus(
|
|
380
|
+
return await bucketSyncStatus(config.account, config.bucketName);
|
|
380
381
|
}
|
|
381
382
|
|
|
382
383
|
@assertValidArgs
|
|
@@ -435,20 +436,26 @@ class RemoteStorageControllerBase {
|
|
|
435
436
|
assertValidName(account, "account");
|
|
436
437
|
assertValidName(bucketName, "bucket name");
|
|
437
438
|
assertValidPath(filePath);
|
|
438
|
-
let
|
|
439
|
-
if (!
|
|
439
|
+
let bucketStores = await getBucketStores(account, bucketName);
|
|
440
|
+
if (!bucketStores.length) {
|
|
440
441
|
return setHTTPResultHeaders(Buffer.from(""), { status: "404" });
|
|
441
442
|
}
|
|
442
|
-
|
|
443
|
+
// Each store's policy comes from its own config, which it has only read once init ran
|
|
444
|
+
await Promise.all(bucketStores.map(x => x.store.init()));
|
|
445
|
+
let policies = bucketStores.map(x => ({ store: x.store, policy: x.store.storeConfig.current() }));
|
|
446
|
+
if (!policies.some(x => x.policy.public)) {
|
|
443
447
|
throw new Error(`Bucket ${account}/${bucketName} is not public, so its files cannot be read over plain URLs`);
|
|
444
448
|
}
|
|
445
449
|
// Anonymous URL reads carry no source selection - the file's route picks the store, and a route no store here covers is simply not found (the routing file itself lives outside every store)
|
|
446
|
-
let httpStore:
|
|
450
|
+
let httpStore: BlobStore | undefined;
|
|
451
|
+
let immutable = false;
|
|
447
452
|
let info: { writeTime: number; size: number } | undefined;
|
|
448
453
|
if (filePath !== ROUTING_FILE) {
|
|
449
454
|
let route = getRoute(filePath);
|
|
450
|
-
|
|
451
|
-
|
|
455
|
+
let serving = policies.find(x => x.policy.public && routeContains(x.policy.route, route));
|
|
456
|
+
httpStore = serving?.store;
|
|
457
|
+
immutable = !!serving?.policy.immutable;
|
|
458
|
+
info = httpStore && await httpStore.getInfo({ path: filePath }) || undefined;
|
|
452
459
|
} else {
|
|
453
460
|
info = await getRoutingFileResult(account, bucketName);
|
|
454
461
|
}
|
|
@@ -462,7 +469,8 @@ class RemoteStorageControllerBase {
|
|
|
462
469
|
"Last-Modified": new Date(info.writeTime).toUTCString(),
|
|
463
470
|
"Accept-Ranges": "bytes",
|
|
464
471
|
};
|
|
465
|
-
|
|
472
|
+
// The serving store's own policy - and never for the routing file, which changing is the whole point of
|
|
473
|
+
if (immutable) {
|
|
466
474
|
headers["Cache-Control"] = `max-age=${IMMUTABLE_CACHE_TIME / 1000}`;
|
|
467
475
|
}
|
|
468
476
|
let ifModifiedSince = request?.headers["if-modified-since"];
|
|
@@ -495,7 +503,7 @@ class RemoteStorageControllerBase {
|
|
|
495
503
|
}
|
|
496
504
|
let result: { data: Buffer; writeTime: number; size: number } | undefined;
|
|
497
505
|
if (httpStore) {
|
|
498
|
-
result = await httpStore.
|
|
506
|
+
result = await httpStore.get2({ path: filePath, range });
|
|
499
507
|
} else {
|
|
500
508
|
result = await getRoutingFileResult(account, bucketName);
|
|
501
509
|
if (result && range) {
|