querysub 0.406.0 → 0.408.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/audit-disk-values.js +7 -0
- package/bin/deploy-prefixes.js +7 -0
- package/package.json +5 -3
- package/src/-a-archives/archiveCache.ts +12 -9
- package/src/-a-auth/certs.ts +1 -1
- package/src/-c-identity/IdentityController.ts +9 -1
- package/src/-f-node-discovery/NodeDiscovery.ts +63 -10
- package/src/0-path-value-core/AuthorityLookup.ts +14 -4
- package/src/0-path-value-core/PathRouter.ts +247 -117
- package/src/0-path-value-core/PathRouterRouteOverride.ts +1 -1
- package/src/0-path-value-core/PathRouterServerAuthoritySpec.tsx +4 -2
- package/src/0-path-value-core/PathValueCommitter.ts +68 -31
- package/src/0-path-value-core/PathValueController.ts +77 -8
- package/src/0-path-value-core/PathWatcher.ts +46 -4
- package/src/0-path-value-core/ShardPrefixes.ts +6 -0
- package/src/0-path-value-core/ValidStateComputer.ts +20 -8
- package/src/0-path-value-core/hackedPackedPathParentFiltering.ts +18 -55
- package/src/0-path-value-core/pathValueArchives.ts +19 -8
- package/src/0-path-value-core/pathValueCore.ts +75 -27
- package/src/0-path-value-core/startupAuthority.ts +9 -9
- package/src/1-path-client/RemoteWatcher.ts +217 -178
- package/src/1-path-client/pathValueClientWatcher.ts +6 -11
- package/src/2-proxy/pathValueProxy.ts +2 -3
- package/src/3-path-functions/PathFunctionRunner.ts +3 -1
- package/src/3-path-functions/syncSchema.ts +6 -2
- package/src/4-deploy/deployGetFunctionsInner.ts +1 -1
- package/src/4-deploy/deployPrefixes.ts +14 -0
- package/src/4-deploy/edgeNodes.ts +1 -1
- package/src/4-querysub/Querysub.ts +17 -5
- package/src/4-querysub/QuerysubController.ts +21 -10
- package/src/4-querysub/predictionQueue.tsx +3 -0
- package/src/4-querysub/querysubPrediction.ts +27 -20
- package/src/5-diagnostics/nodeMetadata.ts +17 -0
- package/src/diagnostics/NodeConnectionsPage.tsx +167 -0
- package/src/diagnostics/NodeViewer.tsx +11 -15
- package/src/diagnostics/PathDistributionInfo.tsx +102 -0
- package/src/diagnostics/SyncTestPage.tsx +19 -8
- package/src/diagnostics/auditDiskValues.ts +221 -0
- package/src/diagnostics/auditDiskValuesEntry.ts +43 -0
- package/src/diagnostics/logs/IndexedLogs/LogViewer3.tsx +5 -1
- package/src/diagnostics/logs/TimeRangeSelector.tsx +3 -3
- package/src/diagnostics/logs/lifeCycleAnalysis/LifeCycleRenderer.tsx +2 -0
- package/src/diagnostics/managementPages.tsx +10 -1
- package/src/diagnostics/misc-pages/ArchiveViewer.tsx +3 -2
- package/src/diagnostics/pathAuditer.ts +21 -0
- package/src/path.ts +9 -2
- package/src/rangeMath.ts +41 -0
- package/tempnotes.txt +5 -58
- package/test.ts +13 -295
- package/src/diagnostics/benchmark.ts +0 -139
- package/src/diagnostics/runSaturationTest.ts +0 -416
- package/src/diagnostics/satSchema.ts +0 -64
- package/src/test/mongoSatTest.tsx +0 -55
- package/src/test/satTest.ts +0 -193
- package/src/test/test.tsx +0 -552
|
@@ -1,416 +0,0 @@
|
|
|
1
|
-
import { delay } from "socket-function/src/batching";
|
|
2
|
-
import { formatTime, formatNumber } from "socket-function/src/formatting/format";
|
|
3
|
-
import { blue, green, red, yellow } from "socket-function/src/formatting/logColors";
|
|
4
|
-
import { createStatsValue, addToStatsValue, StatsValue, getStatsTop } from "socket-function/src/profiling/stats";
|
|
5
|
-
import { percent, formatStats } from "socket-function/src/profiling/statsFormat";
|
|
6
|
-
import { proxyWatcher } from "../2-proxy/PathValueProxyWatcher";
|
|
7
|
-
import { timeoutToError, logErrors } from "../errors";
|
|
8
|
-
import { PromiseObj } from "../promise";
|
|
9
|
-
import { Benchmark } from "./benchmark";
|
|
10
|
-
|
|
11
|
-
export class DriftValues {
|
|
12
|
-
constructor(public readonly config: {
|
|
13
|
-
count: number;
|
|
14
|
-
modulus: number;
|
|
15
|
-
driftFraction: number;
|
|
16
|
-
}) { }
|
|
17
|
-
seqNum = 0;
|
|
18
|
-
public getNextValues(): number[] {
|
|
19
|
-
const { count, modulus, driftFraction } = this.config;
|
|
20
|
-
let curSeqNum = this.seqNum++;
|
|
21
|
-
let drift = Math.ceil(driftFraction * count);
|
|
22
|
-
let startValue = curSeqNum * drift % modulus;
|
|
23
|
-
return Array(count).fill(0).map((_, i) => (startValue + i) % modulus);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface BenchmarkFunctions {
|
|
28
|
-
setValues(indexes: number[], value?: number): Promise<void>;
|
|
29
|
-
getValues(indexes: number[]): Promise<number[]>;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export async function runSingleSaturationTest(config: {
|
|
33
|
-
duration: number;
|
|
34
|
-
saturation: number;
|
|
35
|
-
writeSpec: DriftValues;
|
|
36
|
-
predictedValues?: number[];
|
|
37
|
-
functions: BenchmarkFunctions;
|
|
38
|
-
}) {
|
|
39
|
-
const { duration, saturation, writeSpec, predictedValues, functions } = config;
|
|
40
|
-
|
|
41
|
-
let finalEndTime = Date.now() + duration;
|
|
42
|
-
let done = new PromiseObj();
|
|
43
|
-
|
|
44
|
-
let baseStartTime = Date.now();
|
|
45
|
-
let totalOverlappedWaitTime = 0;
|
|
46
|
-
let errorCount = 0;
|
|
47
|
-
|
|
48
|
-
let lastActiveStartTime = 0;
|
|
49
|
-
let totalActiveTime = 0;
|
|
50
|
-
|
|
51
|
-
let runCount = 0;
|
|
52
|
-
|
|
53
|
-
let latencyStats = createStatsValue();
|
|
54
|
-
|
|
55
|
-
let currentParallelCount = 0;
|
|
56
|
-
async function spawnCall() {
|
|
57
|
-
if (currentParallelCount === 0) {
|
|
58
|
-
lastActiveStartTime = Date.now();
|
|
59
|
-
}
|
|
60
|
-
currentParallelCount++;
|
|
61
|
-
let time = Date.now();
|
|
62
|
-
let errored = true;
|
|
63
|
-
try {
|
|
64
|
-
let indexes = writeSpec.getNextValues();
|
|
65
|
-
if (predictedValues) {
|
|
66
|
-
for (let i of indexes) {
|
|
67
|
-
predictedValues[i]++;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
await timeoutToError(30 * 1000, functions.setValues(indexes), () => new Error(`Call timed out after 30 seconds`));
|
|
71
|
-
errored = false;
|
|
72
|
-
} finally {
|
|
73
|
-
let latency = Date.now() - time;
|
|
74
|
-
totalOverlappedWaitTime += latency;
|
|
75
|
-
addToStatsValue(latencyStats, latency);
|
|
76
|
-
if (errored) {
|
|
77
|
-
errorCount++;
|
|
78
|
-
}
|
|
79
|
-
runCount++;
|
|
80
|
-
currentParallelCount--;
|
|
81
|
-
if (currentParallelCount === 0) {
|
|
82
|
-
totalActiveTime += Date.now() - lastActiveStartTime;
|
|
83
|
-
}
|
|
84
|
-
trySpawnMore();
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
function getTargetParallelCount() {
|
|
88
|
-
let currentElapsedTime = Date.now() - baseStartTime;
|
|
89
|
-
let currentOverallSaturation = totalOverlappedWaitTime / currentElapsedTime;
|
|
90
|
-
|
|
91
|
-
// TODO: Use higher or lower saturation values if we are way off, BUT, only after the time is advanced enough,
|
|
92
|
-
// and only between 2X and 0.5X.
|
|
93
|
-
|
|
94
|
-
// Round down if we are oversatured, round up if we are undersaturated
|
|
95
|
-
if (currentOverallSaturation > saturation) {
|
|
96
|
-
return Math.floor(saturation);
|
|
97
|
-
} else {
|
|
98
|
-
return Math.ceil(saturation);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
function trySpawnMore() {
|
|
103
|
-
if (Date.now() >= finalEndTime) {
|
|
104
|
-
if (currentParallelCount === 0) {
|
|
105
|
-
done.resolve();
|
|
106
|
-
}
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
let parallelCount = getTargetParallelCount();
|
|
110
|
-
// If we want to run 0 values, then just wait a bit, and check again
|
|
111
|
-
if (parallelCount === 0) {
|
|
112
|
-
delay(10).finally(trySpawnMore);
|
|
113
|
-
}
|
|
114
|
-
while (currentParallelCount < parallelCount) {
|
|
115
|
-
logErrors(spawnCall());
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
trySpawnMore();
|
|
120
|
-
|
|
121
|
-
await done.promise;
|
|
122
|
-
|
|
123
|
-
let effectiveRate = runCount / totalActiveTime * 1000;
|
|
124
|
-
|
|
125
|
-
return {
|
|
126
|
-
effectiveRate,
|
|
127
|
-
achievedSaturation: totalOverlappedWaitTime / (Date.now() - baseStartTime),
|
|
128
|
-
latencyStats,
|
|
129
|
-
runCount,
|
|
130
|
-
errorCount,
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
export async function runSaturationTests(config: {
|
|
135
|
-
durationPer: number;
|
|
136
|
-
writeSpec: DriftValues;
|
|
137
|
-
functions: BenchmarkFunctions;
|
|
138
|
-
}) {
|
|
139
|
-
const { functions, durationPer, writeSpec } = config;
|
|
140
|
-
|
|
141
|
-
function shouldStopIterating(config: {
|
|
142
|
-
rateIncrease: number;
|
|
143
|
-
latencyIncrease: number;
|
|
144
|
-
saturation: number;
|
|
145
|
-
latencyAverage: number;
|
|
146
|
-
}): boolean {
|
|
147
|
-
const { rateIncrease, latencyIncrease, saturation, latencyAverage } = config;
|
|
148
|
-
if (rateIncrease < 1.1 && saturation >= 1) {
|
|
149
|
-
console.log(`Stopping due to low rate increase ${rateIncrease}`);
|
|
150
|
-
return true;
|
|
151
|
-
}
|
|
152
|
-
if (saturation >= 5 && rateIncrease / latencyIncrease < 0.1) {
|
|
153
|
-
console.log(`Stopping due to low rate/latency increase ${rateIncrease / latencyIncrease}`);
|
|
154
|
-
return true;
|
|
155
|
-
}
|
|
156
|
-
if (latencyAverage >= 500) {
|
|
157
|
-
console.log(`Stopping due to high latency ${latencyAverage}`);
|
|
158
|
-
return true;
|
|
159
|
-
}
|
|
160
|
-
return false;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
let results: string[] = [];
|
|
164
|
-
function log(text = "") {
|
|
165
|
-
results.push(text);
|
|
166
|
-
console.log(text);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// Run a test to warm things up
|
|
170
|
-
let initialResult = await runSingleSaturationTest({ duration: config.durationPer, saturation: 0.5, writeSpec, functions });
|
|
171
|
-
|
|
172
|
-
// Let our warmup settle
|
|
173
|
-
await delay(initialResult.latencyStats.sum * 0.5);
|
|
174
|
-
|
|
175
|
-
// Reset all of the values, both to fill up the server reservations, and so we can easily predict what
|
|
176
|
-
// the final values should be
|
|
177
|
-
console.log(`Start value fill`);
|
|
178
|
-
let fillTime = Date.now();
|
|
179
|
-
const batchCount = 1000;
|
|
180
|
-
for (let i = 0; i < writeSpec.config.modulus; i += batchCount) {
|
|
181
|
-
let currentCount = Math.min(batchCount, writeSpec.config.modulus - i);
|
|
182
|
-
await functions.setValues(Array(currentCount).fill(0).map((_, a) => i + a), 0);
|
|
183
|
-
}
|
|
184
|
-
fillTime = Date.now() - fillTime;
|
|
185
|
-
log(`Finished value fill in ${formatTime(fillTime)}`);
|
|
186
|
-
await delay(fillTime * 0.5 + 250);
|
|
187
|
-
|
|
188
|
-
type Result = {
|
|
189
|
-
actualSaturation: number;
|
|
190
|
-
effectiveRate: number;
|
|
191
|
-
latencyStats: StatsValue;
|
|
192
|
-
};
|
|
193
|
-
let allResults: Result[] = [];
|
|
194
|
-
|
|
195
|
-
let predictedValues = Array(writeSpec.config.modulus).fill(0);
|
|
196
|
-
|
|
197
|
-
let saturation = 1 / 16;
|
|
198
|
-
let lastRate = 0;
|
|
199
|
-
let lastLatency = Number.POSITIVE_INFINITY;
|
|
200
|
-
let stopCount = 0;
|
|
201
|
-
let totalErrorCount = 0;
|
|
202
|
-
while (true) {
|
|
203
|
-
console.log(`Start saturation ${percent(saturation)}`);
|
|
204
|
-
let actualTime = Date.now();
|
|
205
|
-
let result = await runSingleSaturationTest({
|
|
206
|
-
duration: durationPer,
|
|
207
|
-
saturation,
|
|
208
|
-
writeSpec,
|
|
209
|
-
predictedValues,
|
|
210
|
-
functions,
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
actualTime = Date.now() - actualTime;
|
|
214
|
-
|
|
215
|
-
allResults.push({
|
|
216
|
-
actualSaturation: result.achievedSaturation,
|
|
217
|
-
effectiveRate: result.effectiveRate,
|
|
218
|
-
latencyStats: result.latencyStats,
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
log(`In ${formatTime(actualTime).padEnd(8, " ")} target saturation ${percent(saturation).padEnd(8, " ")} achieved saturation ${percent(result.achievedSaturation).padEnd(8, " ")} effective rate ${(formatNumber(result.effectiveRate) + "/s").padEnd(12, " ")} latency ${formatStats(result.latencyStats, { noColor: true })}`);
|
|
222
|
-
if (result.errorCount > 0) {
|
|
223
|
-
log(` ERROR: ${result.errorCount} errors!`);
|
|
224
|
-
totalErrorCount += result.errorCount;
|
|
225
|
-
}
|
|
226
|
-
// Wait to let the server cleanup / recover
|
|
227
|
-
console.log(`Waiting for ${formatTime(actualTime * 0.5)}`);
|
|
228
|
-
await delay(actualTime * 0.5);
|
|
229
|
-
console.log(`End saturation ${percent(saturation)}`);
|
|
230
|
-
|
|
231
|
-
// Always stop if we are over 3X the target time
|
|
232
|
-
if (actualTime / durationPer > 2) {
|
|
233
|
-
console.log(`Stopping due to very high test time ${formatTime(actualTime)}`);
|
|
234
|
-
break;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
let rateIncrease = result.effectiveRate / lastRate;
|
|
238
|
-
let latencyIncrease = result.latencyStats.sum / lastLatency;
|
|
239
|
-
lastRate = result.effectiveRate;
|
|
240
|
-
lastLatency = result.latencyStats.sum;
|
|
241
|
-
if (shouldStopIterating({
|
|
242
|
-
rateIncrease,
|
|
243
|
-
latencyIncrease,
|
|
244
|
-
saturation: saturation,
|
|
245
|
-
latencyAverage: result.latencyStats.sum / result.latencyStats.count
|
|
246
|
-
})) {
|
|
247
|
-
stopCount++;
|
|
248
|
-
if (stopCount >= 3) {
|
|
249
|
-
break;
|
|
250
|
-
}
|
|
251
|
-
} else {
|
|
252
|
-
stopCount = 0;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
saturation *= 2;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
let afterResult = await runSingleSaturationTest({ duration: config.durationPer, saturation: 0.5, writeSpec, predictedValues, functions });
|
|
259
|
-
|
|
260
|
-
let initialAvgLatency = initialResult.latencyStats.sum / initialResult.latencyStats.count;
|
|
261
|
-
let afterAvgLatency = afterResult.latencyStats.sum / afterResult.latencyStats.count;
|
|
262
|
-
|
|
263
|
-
let latencyIncrease = afterAvgLatency / initialAvgLatency;
|
|
264
|
-
if (latencyIncrease > 1.2) {
|
|
265
|
-
console.log(red(`WARNING: Latency increased by ${percent(latencyIncrease - 1)}!`));
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
log("");
|
|
270
|
-
log(`Rate chart (op/s)`);
|
|
271
|
-
logChart(allResults.map(result => ({
|
|
272
|
-
x: result.actualSaturation,
|
|
273
|
-
y: result.effectiveRate,
|
|
274
|
-
xStr: percent(result.actualSaturation),
|
|
275
|
-
yStr: formatNumber(result.effectiveRate) + "/s",
|
|
276
|
-
})));
|
|
277
|
-
|
|
278
|
-
log("");
|
|
279
|
-
log(`Latency chart (average)`);
|
|
280
|
-
logChart(allResults.map(result => ({
|
|
281
|
-
x: result.actualSaturation,
|
|
282
|
-
y: result.latencyStats.sum / result.latencyStats.count,
|
|
283
|
-
xStr: percent(result.actualSaturation),
|
|
284
|
-
yStr: formatTime(result.latencyStats.sum / result.latencyStats.count),
|
|
285
|
-
})));
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
log("");
|
|
289
|
-
log(`Suggestions`);
|
|
290
|
-
|
|
291
|
-
let maxRate = allResults.reduce((a, b) => Math.max(a, b.effectiveRate), 0);
|
|
292
|
-
let minLatency = allResults[2].latencyStats ?? allResults[0].latencyStats;
|
|
293
|
-
|
|
294
|
-
function findClosest(dist: (other: Result) => number): Result {
|
|
295
|
-
let closest: Result | undefined;
|
|
296
|
-
let closestDist = Number.POSITIVE_INFINITY;
|
|
297
|
-
for (let result of allResults) {
|
|
298
|
-
let currentDist = Math.abs(dist(result));
|
|
299
|
-
if (currentDist < closestDist) {
|
|
300
|
-
closest = result;
|
|
301
|
-
closestDist = currentDist;
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
return closest!;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
const maxRateObj = findClosest(r => r.effectiveRate - maxRate * 0.8);
|
|
308
|
-
const heavySat = findClosest(r => r.actualSaturation - maxRateObj.actualSaturation * 0.5);
|
|
309
|
-
const minLatencyObj = findClosest(r => r.latencyStats.sum / r.latencyStats.count - minLatency.sum / minLatency.count);
|
|
310
|
-
const minLatency2XObj = findClosest(r => r.latencyStats.sum / r.latencyStats.count - minLatency.sum / minLatency.count * 2);
|
|
311
|
-
|
|
312
|
-
const normalLatency = findClosest(r => r.latencyStats.sum / r.latencyStats.count - 100);
|
|
313
|
-
const highLatency = findClosest(r => r.latencyStats.sum / r.latencyStats.count - 500);
|
|
314
|
-
|
|
315
|
-
function getSatObj(title: string, obj: Result) {
|
|
316
|
-
let output = "";
|
|
317
|
-
output += (title.padEnd(20, " ")) + " ";
|
|
318
|
-
output += (`${formatNumber(obj.effectiveRate)}/s`.padEnd(10, " ")) + " ";
|
|
319
|
-
|
|
320
|
-
let top = getStatsTop(obj.latencyStats);
|
|
321
|
-
if (top.topHeavy) {
|
|
322
|
-
output += `latency = ${formatStats(obj.latencyStats, { noColor: true, noSum: true })}`.padEnd(16, " ") + " ";
|
|
323
|
-
} else {
|
|
324
|
-
output += `latency = ${formatTime(obj.latencyStats.sum / obj.latencyStats.count)}`.padEnd(16, " ") + " ";
|
|
325
|
-
}
|
|
326
|
-
output += (`(${percent(obj.actualSaturation)} saturation)`.padEnd(25, " ")) + " ";
|
|
327
|
-
output += (`(${formatNumber(obj.latencyStats.count)} count)`.padEnd(12, " ")) + " ";
|
|
328
|
-
|
|
329
|
-
return output;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
if (maxRateObj.effectiveRate > highLatency.effectiveRate * 1.2) {
|
|
333
|
-
log(getSatObj("Max rate", maxRateObj));
|
|
334
|
-
}
|
|
335
|
-
if (heavySat.effectiveRate > highLatency.effectiveRate * 1.2) {
|
|
336
|
-
log(getSatObj("Heavy saturation", heavySat));
|
|
337
|
-
}
|
|
338
|
-
log(getSatObj("Min latency", minLatencyObj));
|
|
339
|
-
if (highLatency.effectiveRate > normalLatency.effectiveRate * 1.2) {
|
|
340
|
-
log(blue(getSatObj("500ms latency", highLatency)));
|
|
341
|
-
}
|
|
342
|
-
if (minLatency2XObj.effectiveRate > minLatencyObj.effectiveRate * 1.2) {
|
|
343
|
-
log(yellow(getSatObj("Min latency 2X", minLatency2XObj)));
|
|
344
|
-
}
|
|
345
|
-
if (
|
|
346
|
-
normalLatency.effectiveRate > minLatencyObj.effectiveRate * 1.2
|
|
347
|
-
&& (normalLatency.effectiveRate > minLatency2XObj.effectiveRate * 1.2)
|
|
348
|
-
) {
|
|
349
|
-
log(green(getSatObj("100ms latency", normalLatency)));
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
let realValues: number[] = await functions.getValues(predictedValues.map((_, i) => i));
|
|
354
|
-
|
|
355
|
-
let wrongIndexes = 0;
|
|
356
|
-
let wrongSum = 0;
|
|
357
|
-
for (let i = 0; i < predictedValues.length; i++) {
|
|
358
|
-
if (predictedValues[i] !== realValues[i]) {
|
|
359
|
-
wrongIndexes++;
|
|
360
|
-
wrongSum += Math.abs(predictedValues[i] - realValues[i]);
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
let wrongFraction = wrongSum / predictedValues.reduce((a, b) => a + b, 0);
|
|
364
|
-
if (wrongIndexes > 0) {
|
|
365
|
-
log(`!!!! ERROR !!!!: ${formatNumber(wrongIndexes)} indexes were wrong, ${percent(wrongFraction)} of operations were missed`);
|
|
366
|
-
}
|
|
367
|
-
if (totalErrorCount > 0) {
|
|
368
|
-
log(`!!!! ERROR !!!!: ${formatNumber(totalErrorCount)} errors were encountered`);
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
console.log();
|
|
373
|
-
console.log("Results");
|
|
374
|
-
for (let result of results) {
|
|
375
|
-
console.log(result);
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
return results;
|
|
379
|
-
|
|
380
|
-
function logChart(values: { x: number; y: number; xStr: string; yStr: string; }[]) {
|
|
381
|
-
const barWidth = 4;
|
|
382
|
-
let columnWidth = values.length * barWidth;
|
|
383
|
-
let columnHeight = 12;
|
|
384
|
-
function rightJustifyLog(text: string) {
|
|
385
|
-
let padding = " ".repeat(Math.max(columnWidth - text.length, 0));
|
|
386
|
-
log(padding + text);
|
|
387
|
-
}
|
|
388
|
-
function sidesLog(left: string, right: string) {
|
|
389
|
-
let padding = " ".repeat(Math.max(columnWidth - left.length - right.length, 0));
|
|
390
|
-
log(left + padding + right);
|
|
391
|
-
}
|
|
392
|
-
rightJustifyLog(values.at(-1)!.yStr);
|
|
393
|
-
log();
|
|
394
|
-
let maxY = values.reduce((a, b) => Math.max(a, b.y), 0);
|
|
395
|
-
let minY = values.reduce((a, b) => Math.min(a, b.y), Number.POSITIVE_INFINITY);
|
|
396
|
-
minY = 0;
|
|
397
|
-
let grid = Array(columnHeight).fill(0).map(() => Array(columnWidth).fill(" "));
|
|
398
|
-
let xIndex = 0;
|
|
399
|
-
for (let value of values) {
|
|
400
|
-
let barHeight = Math.floor((value.y - minY) / (maxY - minY) * columnHeight);
|
|
401
|
-
for (let y = 0; y < barHeight; y++) {
|
|
402
|
-
for (let xOff = 0; xOff < barWidth; xOff++) {
|
|
403
|
-
grid[y][xIndex + xOff] = "█";
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
xIndex += barWidth;
|
|
407
|
-
}
|
|
408
|
-
grid.reverse();
|
|
409
|
-
for (let row of grid) {
|
|
410
|
-
log(row.join(""));
|
|
411
|
-
}
|
|
412
|
-
rightJustifyLog(values.at(0)!.yStr);
|
|
413
|
-
sidesLog(values.at(0)!.xStr, values.at(-1)!.xStr);
|
|
414
|
-
log();
|
|
415
|
-
}
|
|
416
|
-
}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { red } from "socket-function/src/formatting/logColors";
|
|
2
|
-
import { Querysub } from "../4-querysub/Querysub";
|
|
3
|
-
import { delay } from "socket-function/src/batching";
|
|
4
|
-
import { atomic, proxyWatcher } from "../2-proxy/PathValueProxyWatcher";
|
|
5
|
-
import { Benchmark } from "./benchmark";
|
|
6
|
-
import { BenchmarkFunctions } from "./runSaturationTest";
|
|
7
|
-
import debugbreak from "debugbreak";
|
|
8
|
-
|
|
9
|
-
let { data, functions } = Querysub.createSchema<{
|
|
10
|
-
values: {
|
|
11
|
-
[index: number]: number;
|
|
12
|
-
};
|
|
13
|
-
}>()({
|
|
14
|
-
domainName: "querysub.com",
|
|
15
|
-
functions: {
|
|
16
|
-
setValues(indexes: number[], value?: number) {
|
|
17
|
-
for (let index of indexes) {
|
|
18
|
-
let newValue = value ?? (data().values[index] + 1);
|
|
19
|
-
data().values[index] = newValue;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
},
|
|
23
|
-
module,
|
|
24
|
-
moduleId: "saturationTest",
|
|
25
|
-
functionMetadata: {},
|
|
26
|
-
permissions: {
|
|
27
|
-
PERMISSIONS: isRegisteredUserCheck
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
function isRegisteredUserCheck(): boolean {
|
|
32
|
-
let allowed = Querysub.getCallerIP() === "127.0.0.1";
|
|
33
|
-
if (!allowed && Querysub.isAllSynced()) {
|
|
34
|
-
console.log(red(`Permission denied to IP ${JSON.stringify(Querysub.getCallerIP())}`));
|
|
35
|
-
}
|
|
36
|
-
return allowed;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export const sat_data = data;
|
|
40
|
-
export const sat_functions = functions;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
export function createBenchmarkFunctions(): BenchmarkFunctions {
|
|
44
|
-
return {
|
|
45
|
-
async setValues(indexes: number[], value?: number) {
|
|
46
|
-
let call = sat_functions.setValues(indexes, value);
|
|
47
|
-
await Benchmark.waitForCallToFinish(call);
|
|
48
|
-
},
|
|
49
|
-
async getValues(indexes: number[]): Promise<number[]> {
|
|
50
|
-
let realValues: number[] = [];
|
|
51
|
-
const watcher = proxyWatcher.createWatcher({
|
|
52
|
-
watchFunction() {
|
|
53
|
-
for (let i = 0; i < indexes.length; i++) {
|
|
54
|
-
let index = indexes[i];
|
|
55
|
-
realValues[i] = atomic(sat_data().values[index]) ?? 0;
|
|
56
|
-
}
|
|
57
|
-
},
|
|
58
|
-
});
|
|
59
|
-
await delay(10 * 1000);
|
|
60
|
-
watcher.dispose();
|
|
61
|
-
return realValues;
|
|
62
|
-
},
|
|
63
|
-
};
|
|
64
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
// import * as mongodb from "mongodb";
|
|
2
|
-
// import { lazy } from "socket-function/src/caching";
|
|
3
|
-
// import { BenchmarkFunctions, DriftValues, runSaturationTests } from "../diagnostics/runSaturationTest";
|
|
4
|
-
|
|
5
|
-
// export type MongoRow = {
|
|
6
|
-
// _id: string;
|
|
7
|
-
// [prop: string]: unknown;
|
|
8
|
-
// };
|
|
9
|
-
|
|
10
|
-
// let getMongoClient = lazy(async (): Promise<mongodb.MongoClient> => {
|
|
11
|
-
// let client = await mongodb.MongoClient.connect(
|
|
12
|
-
// `mongodb://admin:password@127.0.0.1:33208/?authSource=admin&readPreference=primary&appname=MongoDB%20Compass&ssl=false`,
|
|
13
|
-
// {
|
|
14
|
-
// ignoreUndefined: true
|
|
15
|
-
// }
|
|
16
|
-
// );
|
|
17
|
-
// return client;
|
|
18
|
-
// });
|
|
19
|
-
// async function getCollection(database: string, collection: string) {
|
|
20
|
-
// let client = await getMongoClient();
|
|
21
|
-
// return await client.db(database).collection<MongoRow>(collection);
|
|
22
|
-
// }
|
|
23
|
-
|
|
24
|
-
// export async function createBenchmarkFunctions(): Promise<BenchmarkFunctions> {
|
|
25
|
-
// let collection = await getCollection("TEST_DB", "TEST_COLLECTION");
|
|
26
|
-
// return {
|
|
27
|
-
// async setValues(indexes: number[], value?: number) {
|
|
28
|
-
// if (value !== undefined) {
|
|
29
|
-
// await collection.updateMany({ _id: { $in: indexes.map(i => i.toString()) } }, { $set: { value } }, { upsert: true });
|
|
30
|
-
// } else if (indexes.length === 1) {
|
|
31
|
-
// await collection.updateOne({ _id: indexes[0].toString() }, { $inc: { value: 1 } }, {});
|
|
32
|
-
// } else {
|
|
33
|
-
// await collection.updateMany({ _id: { $in: indexes.map(i => i.toString()) } }, { $inc: { value: 1 } as any }, {});
|
|
34
|
-
// }
|
|
35
|
-
// },
|
|
36
|
-
// async getValues(indexes: number[]): Promise<number[]> {
|
|
37
|
-
// let rows = await collection.find({ _id: { $in: indexes.map(i => i.toString()) } }).toArray();
|
|
38
|
-
// return rows.map(row => row.value as number);
|
|
39
|
-
// },
|
|
40
|
-
// };
|
|
41
|
-
// }
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
// export async function main() {
|
|
45
|
-
// await runSaturationTests({
|
|
46
|
-
// durationPer: 1000,
|
|
47
|
-
// //writeSpec: new DriftValues({ count: 77, modulus: INDEX_EXTENT, driftFraction: 0.1 }),
|
|
48
|
-
// //writeSpec: new DriftValues({ count: 10, modulus: INDEX_EXTENT, driftFraction: 0.1 }),
|
|
49
|
-
// //writeSpec: new DriftValues({ count: 9, modulus: 50 * 50, driftFraction: 0.1 }),
|
|
50
|
-
// writeSpec: new DriftValues({ count: 9, modulus: 50 * 50, driftFraction: 0.1 }),
|
|
51
|
-
// functions: await createBenchmarkFunctions(),
|
|
52
|
-
// });
|
|
53
|
-
// }
|
|
54
|
-
|
|
55
|
-
// main().catch(e => console.error(e)).finally(() => process.exit());
|