querysub 0.407.0 → 0.409.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.
Files changed (44) hide show
  1. package/bin/audit-disk-values.js +7 -0
  2. package/package.json +4 -3
  3. package/src/-a-archives/archiveCache.ts +12 -9
  4. package/src/-a-auth/certs.ts +1 -1
  5. package/src/-c-identity/IdentityController.ts +9 -1
  6. package/src/-f-node-discovery/NodeDiscovery.ts +63 -8
  7. package/src/0-path-value-core/AuthorityLookup.ts +8 -3
  8. package/src/0-path-value-core/PathRouter.ts +109 -68
  9. package/src/0-path-value-core/PathRouterServerAuthoritySpec.tsx +4 -2
  10. package/src/0-path-value-core/PathValueCommitter.ts +3 -1
  11. package/src/0-path-value-core/PathValueController.ts +75 -4
  12. package/src/0-path-value-core/PathWatcher.ts +39 -0
  13. package/src/0-path-value-core/ShardPrefixes.ts +2 -0
  14. package/src/0-path-value-core/ValidStateComputer.ts +20 -8
  15. package/src/0-path-value-core/hackedPackedPathParentFiltering.ts +11 -29
  16. package/src/0-path-value-core/pathValueArchives.ts +16 -5
  17. package/src/0-path-value-core/pathValueCore.ts +43 -3
  18. package/src/1-path-client/RemoteWatcher.ts +46 -25
  19. package/src/4-querysub/Querysub.ts +17 -5
  20. package/src/4-querysub/QuerysubController.ts +21 -10
  21. package/src/4-querysub/predictionQueue.tsx +3 -0
  22. package/src/4-querysub/querysubPrediction.ts +27 -20
  23. package/src/5-diagnostics/nodeMetadata.ts +17 -0
  24. package/src/deployManager/components/MachineDetailPage.tsx +1 -1
  25. package/src/diagnostics/NodeConnectionsPage.tsx +167 -0
  26. package/src/diagnostics/NodeViewer.tsx +11 -15
  27. package/src/diagnostics/PathDistributionInfo.tsx +102 -0
  28. package/src/diagnostics/auditDiskValues.ts +221 -0
  29. package/src/diagnostics/auditDiskValuesEntry.ts +43 -0
  30. package/src/diagnostics/logs/IndexedLogs/LogViewer3.tsx +5 -1
  31. package/src/diagnostics/logs/TimeRangeSelector.tsx +3 -3
  32. package/src/diagnostics/logs/lifeCycleAnalysis/LifeCycleRenderer.tsx +2 -0
  33. package/src/diagnostics/managementPages.tsx +10 -1
  34. package/src/diagnostics/misc-pages/ArchiveViewer.tsx +3 -2
  35. package/src/diagnostics/pathAuditer.ts +21 -0
  36. package/src/storage/diskCache2.ts +6 -0
  37. package/tempnotes.txt +9 -44
  38. package/test.ts +13 -301
  39. package/src/diagnostics/benchmark.ts +0 -139
  40. package/src/diagnostics/runSaturationTest.ts +0 -416
  41. package/src/diagnostics/satSchema.ts +0 -64
  42. package/src/test/mongoSatTest.tsx +0 -55
  43. package/src/test/satTest.ts +0 -193
  44. package/src/test/test.tsx +0 -552
package/tempnotes.txt CHANGED
@@ -1,51 +1,16 @@
1
1
 
2
- 2) Change the test page lookup to be an actual lookup (and make it actually use the type safe schema)
3
- - And... deploy, we need to deploy the function too...
4
-
5
- 3) After making it an actual lookup, it should match with the function sharding. And so this should get rid of the cases when one update goes to both servers (Which happens because without the lookup both the data values and the function values could resolve to be on different servers, meaning both servers will know about the write).
6
-
7
- 4) Verify the test page works well, and shards
8
- - We have the function sharding, so the values shouldn't be sent to both servers because the function calls themselves should be sharded.
9
-
10
-
11
- 3) add code so that client-side we can get a breakdown of How many paths we have per authority. The goal is to have it heavily biased, not balanced. We want to only use a single server. (But then, of course, for different users, we should be using a different server)
12
- 3.1) AND Give a count of how many writes per authority and how many reads, as in how many changes per authority.
13
- 3.2) Let it popup and show which paths are on each server
14
-
15
-
16
- 4) Get the AI to go through and add function remapping code. Basically, the idea is that we take the most accessed lookup that we're accessing and we use the key for that as our hash. For simple functions, we could actually automate this, but I'll see how the AI can do.
17
-
18
- 5) Verify we are mostly accessing paths on one authority
19
-
20
- 3.3) Do more testing with having a partial shard range being down. Realistically, we should be able to set some kind of range, maybe just a very small range in the middle of the two main servers that isn't covered, and still be able to use the site. Previously, we weren't able to. Maybe this was because the transactions just never resolved because we couldn't synchronize some of the values?
21
-
22
-
23
- 7) Test 4 servers, sharded and redundant as the same time
24
- 8) Verify on the test page
25
-
26
- 8) Shard FunctionRunner
27
- - Now is as good a time as any to deal with any of the sharding issues. And it should work easily enough...
28
- - Verify the secondary run backup code works too.
29
-
30
- 9) Do some tests with adding new modules and new functions in development
31
- - I think we need to have the git prefix code. Get some extra prefixes in development.
32
- - And likely import the deploy.ts code...
33
- - Some kind of "getDevelopmentPrefixes" should be fine, which we dynamically call when is not public in getShardPrefixes
34
-
35
- 2) Add disk verification service
36
- - pick a random authority => read the same we would as startup => do an extra backblaze getKeys and getInfo to make sure our cache is accurate => load in the data into memory => verify all old paths with that authority?
37
- - I wasn't planning on verifying all paths, but we should be able to. They have to be old enough, of course. But we kind of already have that logic, so the AI can probably write it. The one somewhat hard thing, of course, is doing the hashes, especially because new data could cause the hashes to change because of GCing in memory. But if that's the case, for now we can error. Eventually we will warn and then we will drill down further to find the specific paths that are wrong. And if they actually are wrong, then we can actually error.
38
-
39
-
40
- 2) Allow remote servers to talk to our local server, via using the connection the local server makes
41
- AH! Add a connectivity page that we can go to, and you can tell all the servers to ping all the other servers, and then it will give us a full list of all that are inaccessible. We should start with this page, deploy it, Then witness that the remote server can't talk to our local servers. They don't even need to be local path value servers, just our local CYOA server, etc.
42
- I think what we need to do is we need to group connections by the resolved identity instead of by the underlying node ID. Maybe this is already done? (But I don't remember doing it).
43
-
44
-
45
2
 
46
3
  3) Deploy EVERYTHING (all services) to remote servers
47
4
  3.0) deploy the path value servers shard it like we were testing locally
48
5
  - 4, for redundancy and sharding
49
- 5) Deploy disk verification service
6
+ 3.1) Make sure the gc services are deployed too
7
+ 5) Deploy disk audit service too
8
+ `yarn audit-disk-values` should work
9
+
10
+ 1) Use connection page to verify server can talk to our locally hosted server
11
+ 1.1) Verify by breaking into our local server that we are receiving values written on the remote server in the local server.
12
+ - This is extremely important. Without this, we can't run a local server. There's all kinds of issues, but our socket function changes should make this so this just works.
50
13
 
14
+ I think even if we run into some occasional issues, we should just power through and try to fix them later. Because I'm sick of working on the framework...
51
15
 
16
+ MONTHLY SUMMARY!
package/test.ts CHANGED
@@ -2,313 +2,25 @@ import { chdir } from "process";
2
2
  chdir("D:/repos/qs-cyoa/");
3
3
 
4
4
  import "./inject";
5
-
6
- import path from "path";
7
- import { list, sort } from "socket-function/src/misc";
8
- import { formatNumber } from "socket-function/src/formatting/format";
9
- import { PathValueArchives, archives, archivesLocks, archivesRecycleBin, pathValueArchives } from "./src/0-path-value-core/pathValueArchives";
10
- import { trimPathStrToDepth } from "./src/path";
11
- import { Querysub } from "./src/4-querysub/QuerysubController";
12
- import { clientWatcher } from "./src/1-path-client/pathValueClientWatcher";
5
+ import { SocketFunction } from "socket-function/SocketFunction";
6
+ import { getControllerNodeIdList } from "./src/-g-core-values/NodeCapabilities";
13
7
  import { delay } from "socket-function/src/batching";
14
- import { authorityStorage } from "./src/0-path-value-core/pathValueCore";
15
- import { authorityLookup } from "./src/0-path-value-core/AuthorityLookup";
16
- import { getSnapshot, loadSnapshot, saveSnapshot } from "./src/0-path-value-core/archiveLocks/archiveSnapshots";
17
- import { Transaction } from "./src/0-path-value-core/archiveLocks/ArchiveLocks2";
18
- import { getArchives } from "./src/-a-archives/archives";
19
- import { unique } from "./src/misc";
20
- import { getAllAuthoritySpec, getOurAuthoritySpec } from "./src/0-path-value-core/PathRouterServerAuthoritySpec";
21
- import { PathRouter } from "./src/0-path-value-core/PathRouter";
22
- import { pathValueSerializer } from "./src/-h-path-value-serialize/PathValueSerializer";
23
- import { getShardPrefixes } from "./src/0-path-value-core/ShardPrefixes";
24
- import { getPrefixesForDeploy } from "./src/3-path-functions/syncSchema";
25
-
26
- async function main() {
27
- let deployPath = path.resolve("./deploy.ts");
28
- await import(deployPath);
29
- let prefixes = await getPrefixesForDeploy();
30
- console.log(prefixes);
31
- // let prefixes = await getShardPrefixes();
32
- // console.log(prefixes);
33
- return;
34
- // let paths = await pathValueArchives.getValuePaths(getAllAuthoritySpec());
35
- // paths = paths.filter(x => x.startsWith("P!REMAINING/"));
36
- // for (let path of paths) {
37
- // let data = await archives().get(path);
38
- // if (!data) {
39
- // console.log(`Missing data file: ${path}`);
40
- // continue;
41
- // }
42
- // let loadObj = await PathValueArchives.loadValuesFromBuffer({ path, data });
43
-
44
- // for (let value of loadObj.values) {
45
- // if (!PathRouter.matchesAuthoritySpec(getAllAuthoritySpec(), value.path)) {
46
- // throw new Error(`Value ${value.path} does not match authority spec`);
47
- // }
48
- // console.log(pathValueSerializer.getPathValue(value));
49
- // }
50
- // }
51
- // return;
8
+ import { green, yellow } from "socket-function/src/formatting/logColors";
9
+ import { Querysub } from "./src/4-querysub/Querysub";
10
+ import { pathValueArchives } from "./src/0-path-value-core/pathValueArchives";
11
+ import { getAllAuthoritySpec } from "./src/0-path-value-core/PathRouterServerAuthoritySpec";
52
12
 
53
- // let path = "P!REMAINING/data_37c5d323e0f9a083.1ed7a7340a015680.querysubtest.com:52026_1775097754671.579_3_1_337_1775097652829.5793_1775097652829.5793_genesis_.data";
54
- // let value = await archives().get(path);
55
- // console.log(value?.toString());
56
- // return;
57
13
 
58
- // const path = list(500).map(x => "a").join("");
59
- // await archives().set(path, Buffer.from("Hello, world!"));
60
- // let value = await archives().get(path);
61
- // console.log(value?.toString());
14
+ async function main() {
15
+ await Querysub.hostService("test");
62
16
 
63
- // function getName(path: string): string {
64
- // return path.split("/").at(-1)!;
65
- // }
17
+ let spec = await getAllAuthoritySpec();
66
18
 
67
- //*
68
- let allValuesObj = await pathValueArchives.loadValues({
69
- nodeId: "",
70
- prefixes: [],
71
- routeStart: 0,
72
- routeEnd: 1,
19
+ let data = await pathValueArchives.loadValues({
20
+ ...spec,
21
+ routeStart: 0.5,
22
+ routeEnd: 0.6,
73
23
  });
74
- let allValues = Object.values(allValuesObj.values).flat();
75
- console.log(`Total values loaded: ${formatNumber(allValues.length)}`);
76
- //*/
77
-
78
- // const badDeleteTransaction = "transaction_ tSeqNum=887 tWriteTime=1774715868374.9143 thread=9dc0 cCount=14 dCount=3482 create=X,X,X,X,X,X,X,X,X,X,X,X,X,X delete=2@0977,3@0977,4@0977,1@0a2a,2@0a2a,3@0a2a,4@0a2... .transaction";
79
-
80
-
81
- // // const snapshotFile = "fileCount=3482 valueCount=1142614 byteCount=1074547019 time=1774724950047.202 hash=9d9acc132ccfbf898ae0c287391e48a88e4e3b3ed3beda16f81a0936e710ab07";
82
- // // const snapshotFile2 = "fileCount=51 valueCount=1040817 byteCount=1019830353 time=1772831139982.38 hash=7c6acb6b705a8c68892f787e9c9f958b527bde8b60fb914045863a4bedc269e7";
83
- // const fixedSnapshotFile = "fileCount=3482 valueCount=1142614 byteCount=1074547019 time=1774760576390.8218 hash=6ef29678cb600f6920d1615c265ff5150ba97c847143fae2832e26d9e1adf1cf";
84
- // let snapshotFileObj = await getSnapshot(fixedSnapshotFile);
85
-
86
- // // let files: string[] = [];
87
- // // for (let file of snapshotFileObj.files) {
88
- // // files.push("NEW_remaining/" + getName(file.file));
89
- // // }
90
- // // let joinedSnapshot = await saveSnapshot({ files });
91
- // // console.log(`Joined snapshot: ${joinedSnapshot.file}`);
92
- // //await loadSnapshot({ overview: { file: fixedSnapshotFile }, noExit: true, hackNoDelete: true });
93
-
94
- // let snapshot = await getSnapshot(fixedSnapshotFile);
95
- // let found = 0;
96
- // let recycleBin = 0;
97
- // for (let file of snapshot.files) {
98
- // let data = await archives().get(file.file);
99
- // if (data) {
100
- // found++;
101
- // console.log("Found");
102
- // } else if (await archivesRecycleBin().get(file.file)) {
103
- // recycleBin++;
104
- // console.log("Found in recycle bin");
105
- // } else {
106
- // console.log("MISSING!");
107
- // }
108
- // }
109
- // // console.log(`Found ${found}/${snapshot.files.length} files | Recycle bin: ${recycleBin}`);
110
-
111
- //await loadSnapshot({ overview: { file: fixedSnapshotFile }, noExit: true, hackNoDelete: true });
112
-
113
-
114
-
115
- // // let joinedFiles = unique([...snapshot1.files, ...snapshot2.files].map(x => x.file));
116
- // // require("debugbreak")(2);
117
- // // debugger;
118
- // // let joinedSnapshot = await saveSnapshot({ files: joinedFiles });
119
- // // console.log(`Joined snapshot: ${joinedSnapshot.file}`);
120
- // // let joinedSnapshotFile = "fileCount=3482 valueCount=1142614 byteCount=1074547019 time=1774745293898.8706 hash=9d9acc132ccfbf898ae0c287391e48a88e4e3b3ed3beda16f81a0936e710ab07";
121
- // // joinedSnapshotFile = snapshotFile2;
122
-
123
- // // await loadSnapshot({ overview: { file: snapshotFile2 }, noExit: true, hackNoDelete: true });
124
-
125
- /*
126
- let allFiles = await getArchives("").find("");
127
- let allFileNames = new Set(allFiles.map(getName));
128
-
129
- let joinedSnapshot = await getSnapshot(snapshotFile2);
130
-
131
- let countByExtension = new Map<string, { value: number }>();
132
- let found = 0;
133
- let recycleBin = 0;
134
- for (let file of joinedSnapshot.files) {
135
- let extension = file.file.split(".").pop() || "";
136
- let existing = countByExtension.get(extension);
137
- if (!existing) {
138
- existing = { value: 0 };
139
- countByExtension.set(extension, existing);
140
- }
141
- existing.value++;
142
- let data = await archives().get(file.file);
143
- if (data) {
144
- found++;
145
- } else if (await archivesRecycleBin().get(file.file)) {
146
- recycleBin++;
147
- } else if (allFileNames.has(getName(file.file))) {
148
- require("debugbreak")(2);
149
- debugger;
150
- }
151
- }
152
- console.log(Array.from(countByExtension.entries()).map(([extension, value]) => `${extension}: ${value.value}`).join(" | "));
153
- console.log(`Found ${found}/${joinedSnapshot.files.length} files | Recycle bin: ${recycleBin}`);
154
-
155
-
156
- //*/
157
-
158
-
159
- // let joined = await saveSnapshot({ files: joinedFiles });
160
- // console.log(`Joined snapshot: ${joined.file}`);
161
-
162
- // let recycleBinFiles = await archivesRecycleBin().find("");
163
-
164
- // //let snapshot = await getSnapshot(snapshotFile);
165
- //await loadSnapshot({ overview: { file: joinedSnapshotFile }, noExit: true, hackNoDelete: true });
166
- // require("debugbreak")(2);
167
- // debugger;
168
-
169
- //Ugh... we restored... SOME values. 34.4K. But we should have restored over 1 million. And... it doesn't work, of course.
170
-
171
-
172
- //let recycleBinFiles = await archivesRecycleBin().find("");
173
-
174
- /*
175
- {
176
- let snapshot = await getSnapshot(joinedSnapshotFile);
177
- let snapshotNames = new Set(snapshot.files.map(x => getName(x.file)));
178
-
179
- let archivesRoot = getArchives("");
180
- let allFiles = await archivesRoot.find("");
181
- let fullPaths = allFiles.filter(x => snapshotNames.has(getName(x)));
182
- let correct = 0;
183
- let wrong = 0;
184
- let duplicate = 0;
185
- let foundPaths = new Set<string>();
186
- for (let i = 0; i < fullPaths.length; i++) {
187
- let fullPath = fullPaths[i];
188
- let name = getName(fullPath);
189
- let correctPath = `path-values-recycle-bin/NEW_remaining/${name}`;
190
- if (fullPath === correctPath) {
191
- correct++;
192
- continue;
193
- }
194
- wrong++;
195
- if (foundPaths.has(name)) {
196
- duplicate++;
197
- continue;
198
- }
199
- console.log(`Path is wrong at ${i}/${fullPaths.length}: ${fullPath}`);
200
- foundPaths.add(name);
201
- await archivesRoot.move({
202
- path: fullPath,
203
- targetPath: correctPath,
204
- target: archivesRoot,
205
- });
206
- }
207
- console.log({ correct, wrong, duplicate, snapshotCount: snapshot.files.length, allCount: allFiles.length, fullPathsCount: fullPaths.length });
208
- }
209
-
210
- //*/
211
-
212
- // let recycleBinValues = await archivesRecycleBin().findInfo("");
213
- // require("debugbreak")(2);
214
- // debugger;
215
-
216
- // // File =-.,querysubtest._com.,/data_0ee02faf16c0fadf.1ed7a7340a015680.querysubtest.com:58985_1773251893137_6_1_337_1773251743670_1773251743670_genesis_.data is not in the recycle bin, skipping
217
-
218
- // // UGH... they values we delete are not in the recycle bin? Wtf...
219
- // // Welp... files ARE KEPT after deletion natively, so maybe we can find them that way
220
-
221
- // //todonext
222
- // // "move" must be broken? Hmm...
223
-
224
- // // HMM... Why do we have all these files in the root? That is surely not correct. These kinda look like our restored snapshot...
225
- // // That would make sense if move lost its ability to nest values. Maybe due to our caching?
226
-
227
-
228
-
229
- // //let snapshot = await getSnapshot(snapshotFile);
230
-
231
-
232
-
233
- // let test = await archives().find("");
234
- // console.log(test.length);
235
-
236
-
237
-
238
- // We have 125K paths in the recycle bin. We read it surprisingly fast (2 minutes), but yeah... we need to fix this...
239
- // So... archivesRecycleBin is VERY slow. Hmm... do we ever clean it up? I think we have to?
240
- // - We will want to thin the snapshots, not just remove all old ones.
241
- // Hmm... So what even happened?
242
- // - We have some transactions. It looks like they just deleted all the data. I guess our GC code accidentally matched everything.
243
- // Ah, but... We know the files that were deleted, and they're just moved to the recycle bin. So we should just really go from the transactions to find all of the old values.
244
- // AND... somehow we deleted everything, all transactions, everything.
245
- // - Must have been during the attempt to restore it.
246
- // let files = await archivesRecycleBin().findInfo("");
247
- // console.log(files);
248
- // console.log(files.length);
249
- // require("debugbreak")(2);
250
- // debugger;
251
-
252
- // let snapshot = await pathValueArchives.loadValues({
253
- // type: "remaining",
254
- // excludedPrefixes: [],
255
- // });
256
- // let allValues = Object.values(snapshot.values).flat();
257
- // console.log(`Total values loaded: ${formatNumber(allValues.length)}`);
258
-
259
-
260
- // let transactionRaw = await archivesRecycleBin().get(badDeleteTransaction);
261
- // if (!transactionRaw) throw new Error(`Transaction not found: ${badDeleteTransaction}`);
262
- // console.log(transactionRaw?.toString());
263
-
264
- // let transaction = JSON.parse(transactionRaw.toString()) as Transaction;
265
- // let files = transaction.ops.filter(a => a.type === "delete").map(a => a.key);
266
- // await saveSnapshot({ files });
267
-
268
-
269
-
270
-
271
- // await Querysub.hostService("test");
272
- // //let topology = await authorityLookup.getTopology();
273
- // let parentPath = ".,querysubtest._com.,PathFunctionRunner.,book.,Data.,edittingBooks.,hkwnmoiwhuyqenbi.,books.,";
274
- // clientWatcher.setWatches({
275
- // paths: new Set([]),
276
- // parentPaths: new Set([parentPath]),
277
- // callback: () => {
278
- // let value = authorityStorage.getPathsFromParent(parentPath);
279
- // console.log({ parentPaths: value?.size, isSynced: authorityStorage.isParentSynced(parentPath) });
280
- // }
281
- // });
282
-
283
- // await Querysub.hostService("test");
284
-
285
- // let snapshot = await pathValueArchives.loadValues({
286
- // type: "remaining",
287
- // excludedPrefixes: [],
288
- // });
289
- // let allValues = Object.values(snapshot.values).flat();
290
- // console.log(`Total values loaded: ${formatNumber(allValues.length)}`);
291
-
292
- // let splitLevel = 4;
293
- // let paths = new Map<string, {
294
- // count: number;
295
- // }>();
296
- // for (let value of allValues) {
297
- // let path = value.path;
298
- // let prefix = trimPathStrToDepth(path, splitLevel);
299
- // let entry = paths.get(prefix);
300
- // if (!entry) {
301
- // entry = { count: 0 };
302
- // paths.set(prefix, entry);
303
- // }
304
- // entry.count++;
305
- // }
306
- // // Log the 10 biggest paths
307
- // let entries = Array.from(paths.entries());
308
- // sort(entries, x => -x[1].count);
309
- // for (let [path, entry] of entries.slice(0, 10)) {
310
- // console.log(`${formatNumber(entry.count)}\t${path}`);
311
- // }
312
24
  }
313
25
 
314
26
  main().catch(console.error)
@@ -1,139 +0,0 @@
1
- import { addToStats, addToStatsValue, createStatsValue, getStatsTop } from "socket-function/src/profiling/stats";
2
- import type { PathValue } from "../0-path-value-core/pathValueCore";
3
- import { registerPeriodic } from "./periodic";
4
- import { formatTime } from "socket-function/src/formatting/format";
5
- import { formatStats } from "socket-function/src/profiling/statsFormat";
6
- import { getPathStr1 } from "../path";
7
- import { registerResource } from "./trackResources";
8
- import type { CallSpec } from "../3-path-functions/PathFunctionRunner";
9
- import { PromiseObj } from "../promise";
10
- import { lazy } from "socket-function/src/caching";
11
- import { isNode } from "socket-function/src/misc";
12
-
13
- const getCallResultPathFnc = lazy(() => import("../4-querysub/querysubPrediction").then((m) => m.getCallResultPath));
14
-
15
- // NOTE: There's no point to track non-predicted calls, because if we don't predict them we won't be watching
16
- // them, so we won't know when they finish!
17
-
18
- class OverlapRateTracker {
19
- public openCount = 0;
20
- private openTime = 0;
21
- public originalOpenTime = Date.now();
22
- private openCloseCount = 0;
23
-
24
- public finishedTime = 0;
25
- private finishedCount = 0;
26
-
27
- public openValue() {
28
- if (this.openCount === 0) {
29
- this.openTime = Date.now();
30
- }
31
- this.openCount++;
32
- this.openCloseCount++;
33
- }
34
- public closeValue() {
35
- this.openCount--;
36
- let now = Date.now();
37
- if (this.openCount === 0 || now - this.openTime > 5000) {
38
- this.finishedTime += now - this.openTime;
39
- this.openTime = now;
40
- this.finishedCount += this.openCloseCount;
41
- this.openCloseCount = 0;
42
- }
43
- }
44
- public viewRate() {
45
- if (this.finishedTime === 0) return 0;
46
- return this.finishedCount / this.finishedTime * 1000;
47
- }
48
- public saturatedFraction() {
49
- return this.finishedTime / (Date.now() - this.originalOpenTime);
50
- }
51
- public harvestRate() {
52
- let rate = this.viewRate();
53
- this.finishedTime = 0;
54
- this.finishedCount = 0;
55
- this.originalOpenTime = Date.now();
56
- return rate;
57
- }
58
- }
59
-
60
- export class Benchmark {
61
-
62
- public static predictCount = 0;
63
- public static receivedCount = 0;
64
-
65
- private static finishedCalls = createStatsValue();
66
- public static overlapRate = new OverlapRateTracker();
67
-
68
- private static predictedCalls = registerResource("Benchmark|predictedCalls", new Map<string, number>());
69
-
70
- private static waitingForCalls = registerResource("Benchmark|waitingForCalls", new Map<string, (() => void)[]>());
71
-
72
- public static onStartPredictCall(path: string) {
73
- this.predictedCalls.set(path, Date.now());
74
- Benchmark.predictCount++;
75
- this.overlapRate.openValue();
76
- }
77
- public static onReceivedValues(values: PathValue[]) {
78
- for (let value of values) {
79
- if (value.canGCValue) continue;
80
- if (!value.valid) continue;
81
- let list = this.waitingForCalls.get(value.path);
82
- if (!list) continue;
83
- this.waitingForCalls.delete(value.path);
84
- for (let resolve of list) {
85
- resolve();
86
- }
87
- }
88
-
89
- let now = Date.now();
90
- for (let value of values) {
91
- if (!value.path.includes(getPathStr1("Results"))) {
92
- continue;
93
- }
94
- if (value.canGCValue) continue;
95
- if (!value.valid) continue;
96
- let predictedTime = this.predictedCalls.get(value.path);
97
- if (!predictedTime) {
98
- continue;
99
- }
100
- this.overlapRate.closeValue();
101
- this.predictedCalls.delete(value.path);
102
- this.receivedCount++;
103
- addToStatsValue(this.finishedCalls, now - predictedTime);;
104
- }
105
- }
106
-
107
- public static async waitForCallToFinish(call: CallSpec) {
108
- let getCallResultPath = await getCallResultPathFnc();
109
- let path = getCallResultPath(call);
110
- let list = this.waitingForCalls.get(path);
111
- if (!list) {
112
- list = [];
113
- this.waitingForCalls.set(path, list);
114
- }
115
- let promiseObj = new PromiseObj();
116
- list.push(promiseObj.resolve);
117
- await promiseObj.promise;
118
- }
119
-
120
- public static logCallsNow() {
121
- let stats = this.finishedCalls;
122
- this.finishedCalls = createStatsValue();
123
- console.log(`Calls ${formatStats(stats)}, rate ${this.overlapRate.harvestRate()}`);
124
- }
125
-
126
- public static getLiveCallStats() {
127
- return this.finishedCalls;
128
- }
129
- public static getLiveRate() {
130
- return this.overlapRate.viewRate();
131
- }
132
- public static saturatedFraction() {
133
- return this.overlapRate.saturatedFraction();
134
- }
135
- }
136
-
137
- if (!isNode()) {
138
- registerPeriodic(() => Benchmark.logCallsNow());
139
- }