querysub 0.403.0 → 0.405.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/.cursorrules +2 -0
- package/bin/audit-imports.js +4 -0
- package/bin/join.js +1 -1
- package/package.json +7 -4
- package/spec.txt +77 -0
- package/src/-a-archives/archiveCache.ts +9 -4
- package/src/-a-archives/archivesBackBlaze.ts +1039 -1039
- package/src/-a-auth/certs.ts +0 -12
- package/src/-c-identity/IdentityController.ts +12 -3
- package/src/-f-node-discovery/NodeDiscovery.ts +32 -26
- package/src/-g-core-values/NodeCapabilities.ts +12 -2
- package/src/0-path-value-core/AuthorityLookup.ts +239 -0
- package/src/0-path-value-core/LockWatcher2.ts +150 -0
- package/src/0-path-value-core/PathRouter.ts +543 -0
- package/src/0-path-value-core/PathRouterRouteOverride.ts +72 -0
- package/src/0-path-value-core/PathRouterServerAuthoritySpec.tsx +73 -0
- package/src/0-path-value-core/PathValueCommitter.ts +222 -488
- package/src/0-path-value-core/PathValueController.ts +277 -239
- package/src/0-path-value-core/PathWatcher.ts +534 -0
- package/src/0-path-value-core/ShardPrefixes.ts +31 -0
- package/src/0-path-value-core/ValidStateComputer.ts +303 -0
- package/src/0-path-value-core/archiveLocks/ArchiveLocks.ts +1 -1
- package/src/0-path-value-core/archiveLocks/ArchiveLocks2.ts +80 -44
- package/src/0-path-value-core/archiveLocks/archiveSnapshots.ts +13 -16
- package/src/0-path-value-core/auditLogs.ts +2 -0
- package/src/0-path-value-core/hackedPackedPathParentFiltering.ts +97 -0
- package/src/0-path-value-core/pathValueArchives.ts +491 -492
- package/src/0-path-value-core/pathValueCore.ts +195 -1496
- package/src/0-path-value-core/startupAuthority.ts +74 -0
- package/src/1-path-client/RemoteWatcher.ts +90 -82
- package/src/1-path-client/pathValueClientWatcher.ts +808 -815
- package/src/2-proxy/PathValueProxyWatcher.ts +10 -8
- package/src/2-proxy/archiveMoveHarness.ts +182 -214
- package/src/2-proxy/garbageCollection.ts +9 -8
- package/src/2-proxy/schema2.ts +21 -1
- package/src/3-path-functions/PathFunctionHelpers.ts +206 -180
- package/src/3-path-functions/PathFunctionRunner.ts +943 -766
- package/src/3-path-functions/PathFunctionRunnerMain.ts +5 -3
- package/src/3-path-functions/pathFunctionLoader.ts +2 -2
- package/src/3-path-functions/syncSchema.ts +596 -521
- package/src/4-deploy/deployFunctions.ts +19 -4
- package/src/4-deploy/deployGetFunctionsInner.ts +8 -2
- package/src/4-deploy/deployMain.ts +51 -68
- package/src/4-deploy/edgeClientWatcher.tsx +6 -1
- package/src/4-deploy/edgeNodes.ts +2 -2
- package/src/4-dom/qreact.tsx +2 -4
- package/src/4-dom/qreactTest.tsx +7 -13
- package/src/4-querysub/Querysub.ts +21 -8
- package/src/4-querysub/QuerysubController.ts +45 -29
- package/src/4-querysub/permissions.ts +2 -2
- package/src/4-querysub/querysubPrediction.ts +80 -70
- package/src/4-querysub/schemaHelpers.ts +5 -1
- package/src/5-diagnostics/GenericFormat.tsx +14 -9
- package/src/archiveapps/archiveGCEntry.tsx +9 -2
- package/src/archiveapps/archiveJoinEntry.ts +96 -84
- package/src/bits.ts +19 -0
- package/src/config.ts +21 -3
- package/src/config2.ts +23 -48
- package/src/deployManager/components/DeployPage.tsx +7 -3
- package/src/deployManager/machineSchema.ts +4 -1
- package/src/diagnostics/ActionsHistory.ts +3 -8
- package/src/diagnostics/AuditLogPage.tsx +2 -3
- package/src/diagnostics/FunctionCallInfo.tsx +141 -0
- package/src/diagnostics/FunctionCallInfoState.ts +162 -0
- package/src/diagnostics/MachineThreadInfo.tsx +1 -1
- package/src/diagnostics/NodeViewer.tsx +37 -48
- package/src/diagnostics/SyncTestPage.tsx +241 -0
- package/src/diagnostics/auditImportViolations.ts +185 -0
- package/src/diagnostics/listenOnDebugger.ts +3 -3
- package/src/diagnostics/logs/IndexedLogs/BufferUnitSet.ts +10 -4
- package/src/diagnostics/logs/IndexedLogs/IndexedLogs.ts +2 -2
- package/src/diagnostics/logs/IndexedLogs/LogViewer3.tsx +24 -22
- package/src/diagnostics/logs/IndexedLogs/moveIndexLogsToPublic.ts +1 -1
- package/src/diagnostics/logs/diskLogGlobalContext.ts +1 -0
- package/src/diagnostics/logs/errorNotifications2/logWatcher.ts +1 -3
- package/src/diagnostics/logs/lifeCycleAnalysis/LifeCycleEntryEditor.tsx +34 -16
- package/src/diagnostics/logs/lifeCycleAnalysis/LifeCycleEntryReadMode.tsx +4 -6
- package/src/diagnostics/logs/lifeCycleAnalysis/LifeCycleInstanceTableView.tsx +36 -5
- package/src/diagnostics/logs/lifeCycleAnalysis/LifeCyclePage.tsx +19 -5
- package/src/diagnostics/logs/lifeCycleAnalysis/LifeCycleRenderer.tsx +15 -7
- package/src/diagnostics/logs/lifeCycleAnalysis/NestedLifeCycleInfo.tsx +28 -106
- package/src/diagnostics/logs/lifeCycleAnalysis/lifeCycleMatching.ts +2 -0
- package/src/diagnostics/logs/lifeCycleAnalysis/lifeCycleMisc.ts +0 -0
- package/src/diagnostics/logs/lifeCycleAnalysis/lifeCycleSearch.tsx +18 -7
- package/src/diagnostics/logs/lifeCycleAnalysis/lifeCycles.tsx +3 -0
- package/src/diagnostics/managementPages.tsx +10 -3
- package/src/diagnostics/misc-pages/ArchiveViewer.tsx +20 -26
- package/src/diagnostics/misc-pages/ArchiveViewerTree.tsx +6 -4
- package/src/diagnostics/misc-pages/ComponentSyncStats.tsx +2 -2
- package/src/diagnostics/misc-pages/LocalWatchViewer.tsx +7 -9
- package/src/diagnostics/misc-pages/SnapshotViewer.tsx +23 -12
- package/src/diagnostics/misc-pages/archiveViewerShared.tsx +1 -1
- package/src/diagnostics/pathAuditer.ts +486 -0
- package/src/diagnostics/pathAuditerCallback.ts +20 -0
- package/src/diagnostics/watchdog.ts +8 -1
- package/src/library-components/URLParam.ts +1 -1
- package/src/misc/hash.ts +1 -0
- package/src/path.ts +21 -7
- package/src/server.ts +54 -47
- package/src/user-implementation/loginEmail.tsx +1 -1
- package/tempnotes.txt +65 -0
- package/test.ts +298 -97
- package/src/0-path-value-core/NodePathAuthorities.ts +0 -1057
- package/src/0-path-value-core/PathController.ts +0 -1
- package/src/5-diagnostics/diskValueAudit.ts +0 -218
- package/src/5-diagnostics/memoryValueAudit.ts +0 -438
- package/src/archiveapps/archiveMergeEntry.tsx +0 -48
- package/src/archiveapps/lockTest.ts +0 -127
package/src/config2.ts
CHANGED
|
@@ -1,48 +1,23 @@
|
|
|
1
|
-
import { deepCloneJSON, isNode } from "socket-function/src/misc";
|
|
2
|
-
import { hasArchivesPermissions } from "./-a-archives/archives";
|
|
3
|
-
import {
|
|
4
|
-
import { JSONLACKS } from "socket-function/src/JSONLACKS/JSONLACKS";
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
let isInCall = false;
|
|
10
|
-
export function isClient() {
|
|
11
|
-
isInCall = true;
|
|
12
|
-
try {
|
|
13
|
-
return !isNode() || baseIsClient() || !isInCall && !hasArchivesPermissions();
|
|
14
|
-
} finally {
|
|
15
|
-
isInCall = false;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function isServer() {
|
|
20
|
-
return !isClient();
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
let authorities: AuthorityPath[] = [];
|
|
25
|
-
let authority = authorityRaw();
|
|
26
|
-
|
|
27
|
-
let baseAuthorityPaths: AuthorityPath[] = [{
|
|
28
|
-
pathPrefix: rootPathStr
|
|
29
|
-
}];
|
|
30
|
-
if (authority) {
|
|
31
|
-
if (fs.existsSync(authority)) {
|
|
32
|
-
baseAuthorityPaths = JSONLACKS.parse(fs.readFileSync(authority, "utf8"));
|
|
33
|
-
} else {
|
|
34
|
-
baseAuthorityPaths = JSONLACKS.parse(Buffer.from(authority, "base64").toString("utf8"));
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
let domain = getDomain();
|
|
39
|
-
for (let base of baseAuthorityPaths) {
|
|
40
|
-
base = deepCloneJSON(base);
|
|
41
|
-
base.pathPrefix = prependToPathStr(base.pathPrefix, domain);
|
|
42
|
-
if (base.excludedChildren) {
|
|
43
|
-
base.excludedChildren = base.excludedChildren.map(x => prependToPathStr(x, domain));
|
|
44
|
-
}
|
|
45
|
-
authorities.push(base);
|
|
46
|
-
}
|
|
47
|
-
return authorities;
|
|
48
|
-
}
|
|
1
|
+
import { deepCloneJSON, isNode } from "socket-function/src/misc";
|
|
2
|
+
import { hasArchivesPermissions } from "./-a-archives/archives";
|
|
3
|
+
import { baseIsClient, getDomain } from "./config";
|
|
4
|
+
import { JSONLACKS } from "socket-function/src/JSONLACKS/JSONLACKS";
|
|
5
|
+
import { rootPathStr, prependToPathStr, getPathDepth } from "./path";
|
|
6
|
+
import fs from "fs";
|
|
7
|
+
import { AuthoritySpec } from "./0-path-value-core/PathRouter";
|
|
8
|
+
|
|
9
|
+
let isInCall = false;
|
|
10
|
+
export function isClient() {
|
|
11
|
+
isInCall = true;
|
|
12
|
+
try {
|
|
13
|
+
return !isNode() || baseIsClient() || !isInCall && !hasArchivesPermissions();
|
|
14
|
+
} finally {
|
|
15
|
+
isInCall = false;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function isServer() {
|
|
20
|
+
return !isClient();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// NOTE: getOurAuthorities moved to PathRouterHashOverrides, and renamed to getOurAuthoritySpec
|
|
@@ -257,7 +257,10 @@ export class DeployPage extends qreact.Component {
|
|
|
257
257
|
render() {
|
|
258
258
|
let controller = MachineServiceController(SocketFunction.browserNodeId());
|
|
259
259
|
let gitInfo = controller.getGitInfo();
|
|
260
|
-
let pendingFunctions = controller.getPendingFunctions() ||
|
|
260
|
+
let pendingFunctions = controller.getPendingFunctions() || {
|
|
261
|
+
functionSpecs: [],
|
|
262
|
+
prefixes: [],
|
|
263
|
+
};
|
|
261
264
|
let liveFunctions = controller.getLiveFunctions() || [];
|
|
262
265
|
|
|
263
266
|
let liveGitRef = mostCommon(liveFunctions.map(x => x.gitRef)) || "";
|
|
@@ -285,7 +288,8 @@ export class DeployPage extends qreact.Component {
|
|
|
285
288
|
|
|
286
289
|
try {
|
|
287
290
|
await deployFunctionsWithProgress({
|
|
288
|
-
functionSpecs: pendingFunctions,
|
|
291
|
+
functionSpecs: pendingFunctions.functionSpecs,
|
|
292
|
+
prefixes: pendingFunctions.prefixes,
|
|
289
293
|
// NOTE: Old code should always be compatible with new code, so a long delay is fine. We don't want to have deal with bug reports today for bugs we fixed tomorrow, but we also don't want to force users to refresh, so this time is longer than the expected maximum session length.
|
|
290
294
|
// NOTE: Even if we want to deploy now, we can't deploy IMMEDIATELY. Give users at least 10 minutes to accept that that page will forcefully refresh.
|
|
291
295
|
notifyRefreshDelay: forceDeployNowURL.value ? timeInMinute * 10 : timeInHour * 12,
|
|
@@ -379,7 +383,7 @@ export class DeployPage extends qreact.Component {
|
|
|
379
383
|
✅ Everything is up to date - no changes to deploy
|
|
380
384
|
</div>
|
|
381
385
|
) || (
|
|
382
|
-
FunctionDiffView({ pendingFunctions, liveFunctions })
|
|
386
|
+
FunctionDiffView({ pendingFunctions: pendingFunctions.functionSpecs, liveFunctions })
|
|
383
387
|
)}
|
|
384
388
|
</div>;
|
|
385
389
|
}
|
|
@@ -118,7 +118,7 @@ async function registerNodeForMachineCleanup(nodeId: string) {
|
|
|
118
118
|
console.log(green(`Registering node for machine cleanup at ${nodeIdPath}`));
|
|
119
119
|
await fs.promises.writeFile(nodeIdPath, nodeId);
|
|
120
120
|
} else {
|
|
121
|
-
console.log(`Not registering node for machine cleanup because we are not in the service folder: ${currentPath}`);
|
|
121
|
+
console.log(`Not registering node for machine cleanup because we are not in the service folder (${SERVICE_FOLDER_NAME}), and are instead in: ${currentPath}`);
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
124
|
|
|
@@ -358,6 +358,7 @@ export class MachineServiceControllerBase {
|
|
|
358
358
|
|
|
359
359
|
public async deployFunctions(config: {
|
|
360
360
|
functionSpecs: FunctionSpec[];
|
|
361
|
+
prefixes: string[];
|
|
361
362
|
notifyRefreshDelay: number;
|
|
362
363
|
deployOnlyCode?: boolean;
|
|
363
364
|
deployOnlyUI?: boolean;
|
|
@@ -368,6 +369,7 @@ export class MachineServiceControllerBase {
|
|
|
368
369
|
};
|
|
369
370
|
await deployFunctions({
|
|
370
371
|
functionSpecs: config.functionSpecs,
|
|
372
|
+
prefixes: config.prefixes,
|
|
371
373
|
notifyRefreshDelay: config.notifyRefreshDelay,
|
|
372
374
|
deployOnlyCode: config.deployOnlyCode,
|
|
373
375
|
deployOnlyUI: config.deployOnlyUI,
|
|
@@ -410,6 +412,7 @@ const DeployProgressController = SocketFunction.register(
|
|
|
410
412
|
);
|
|
411
413
|
export async function deployFunctionsWithProgress(config: {
|
|
412
414
|
functionSpecs: FunctionSpec[];
|
|
415
|
+
prefixes: string[];
|
|
413
416
|
notifyRefreshDelay: number;
|
|
414
417
|
deployOnlyCode?: boolean;
|
|
415
418
|
deployOnlyUI?: boolean;
|
|
@@ -1,13 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { blue, green, red } from "socket-function/src/formatting/logColors";
|
|
3
|
-
import { getStorageDir, getSubFolder } from "../fs";
|
|
1
|
+
import { blue, green } from "socket-function/src/formatting/logColors";
|
|
4
2
|
import { ClientWatcher } from "../1-path-client/pathValueClientWatcher";
|
|
5
|
-
import {
|
|
6
|
-
import { debugPathValuePath, PathValue, PathWatcherCallback, ReadLock, WatchConfig, WriteState } from "../0-path-value-core/pathValueCore";
|
|
7
|
-
import fs from "fs";
|
|
8
|
-
import { measureWrap } from "socket-function/src/profiling/measure";
|
|
3
|
+
import { debugPathValuePath, PathValue } from "../0-path-value-core/pathValueCore";
|
|
9
4
|
import { pathValueSerializer } from "../-h-path-value-serialize/PathValueSerializer";
|
|
10
|
-
import { LOCAL_DOMAIN_PATH } from "../0-path-value-core/
|
|
5
|
+
import { LOCAL_DOMAIN_PATH } from "../0-path-value-core/PathRouter";
|
|
11
6
|
|
|
12
7
|
|
|
13
8
|
|
|
@@ -5,8 +5,6 @@ import { css } from "typesafecss";
|
|
|
5
5
|
import { getSyncedController } from "../library-components/SyncedController";
|
|
6
6
|
import { DebugLog, DebugLogController, getLogHistoryEquals, getLogHistoryIncludes } from "../0-path-value-core/auditLogs";
|
|
7
7
|
import { remoteWatcher } from "../1-path-client/RemoteWatcher";
|
|
8
|
-
import { pathValueAuthority2 } from "../0-path-value-core/NodePathAuthorities";
|
|
9
|
-
import { getParentPathStr } from "../path";
|
|
10
8
|
import { getBrowserUrlNode, getOwnNodeId } from "../-f-node-discovery/NodeDiscovery";
|
|
11
9
|
import { nextId, sort } from "socket-function/src/misc";
|
|
12
10
|
import { t } from "../2-proxy/schema2";
|
|
@@ -14,6 +12,7 @@ import { InputLabelURL } from "../library-components/InputLabel";
|
|
|
14
12
|
import { URLParam } from "../library-components/URLParam";
|
|
15
13
|
import { Table } from "../5-diagnostics/Table";
|
|
16
14
|
import { ObjectDisplay } from "./logs/ObjectDisplay";
|
|
15
|
+
import { PathRouter } from "../0-path-value-core/PathRouter";
|
|
17
16
|
|
|
18
17
|
/**
|
|
19
18
|
TODO:
|
|
@@ -92,7 +91,7 @@ class AuditLogControllerBase {
|
|
|
92
91
|
let { path, includeDescendants } = config;
|
|
93
92
|
let authorityNodeId = remoteWatcher.getExistingWatchRemoteNodeId(path);
|
|
94
93
|
if (!authorityNodeId) {
|
|
95
|
-
authorityNodeId = await
|
|
94
|
+
authorityNodeId = await PathRouter.getReadyAuthority(path)?.nodeId;
|
|
96
95
|
}
|
|
97
96
|
let logs: DebugLog[] = [];
|
|
98
97
|
let remoteLogs: DebugLog[] = [];
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { qreact } from "../4-dom/qreact";
|
|
2
|
+
import { css } from "../4-dom/css";
|
|
3
|
+
import { t } from "../2-proxy/schema2";
|
|
4
|
+
import { callState, ensureSubscribed } from "./FunctionCallInfoState";
|
|
5
|
+
import { formatNumber, formatPercent, formatTime } from "socket-function/src/formatting/format";
|
|
6
|
+
import { measureBlock } from "socket-function/src/profiling/measure";
|
|
7
|
+
import { StatsValue, getStatsTop } from "socket-function/src/profiling/stats";
|
|
8
|
+
import { isCurrentUserSuperUser } from "../user-implementation/userData";
|
|
9
|
+
|
|
10
|
+
module.hotreload = true;
|
|
11
|
+
|
|
12
|
+
function formatTimeStats(stats: StatsValue): string {
|
|
13
|
+
if (stats.count === 0) return formatTime(0);
|
|
14
|
+
|
|
15
|
+
let avgTime = stats.sum / stats.count;
|
|
16
|
+
let top = getStatsTop(stats);
|
|
17
|
+
|
|
18
|
+
if (!top.topHeavy) {
|
|
19
|
+
return formatTime(avgTime);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
let bottomAvg = (stats.sum - top.value) / (stats.count - top.count) || 0;
|
|
23
|
+
let topAvg = top.value / top.count;
|
|
24
|
+
let topPercent = formatPercent(top.countFraction);
|
|
25
|
+
|
|
26
|
+
return `${formatTime(bottomAvg)} (top ${topPercent} = ${formatTime(topAvg)})`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export class FunctionCallInfo extends qreact.Component {
|
|
30
|
+
showDetailedStats() {
|
|
31
|
+
if (!isCurrentUserSuperUser()) return undefined;
|
|
32
|
+
let state = callState();
|
|
33
|
+
|
|
34
|
+
let avgInternalReruns = state.totalCalls > 0 && state.totalInternalReruns / state.totalCalls || 0;
|
|
35
|
+
let avgFullReruns = state.totalCalls > 0 && state.totalFullReruns / state.totalCalls || 0;
|
|
36
|
+
let percentMultipleInternalRuns = state.totalCalls > 0 && state.callsWithMultipleInternalRuns / state.totalCalls || 0;
|
|
37
|
+
let percentCascadingRuns = state.totalCalls > 0 && state.callsWithCascadingRuns / state.totalCalls || 0;
|
|
38
|
+
let avgCascadingReruns = state.callsWithCascadingRuns > 0 && state.totalInternalRerunsForCascading / state.callsWithCascadingRuns || 0;
|
|
39
|
+
let percentMultipleFullRuns = state.totalCalls > 0 && state.callsWithMultipleFullRuns / state.totalCalls || 0;
|
|
40
|
+
|
|
41
|
+
console.log("=== Function Call Statistics ===");
|
|
42
|
+
console.log([
|
|
43
|
+
`${formatNumber(state.totalCalls)} ⚡`,
|
|
44
|
+
[
|
|
45
|
+
`${formatNumber(avgInternalReruns)} ♻️`,
|
|
46
|
+
percentMultipleInternalRuns > 0 && `(${formatPercent(percentMultipleInternalRuns)} 🔦)`,
|
|
47
|
+
percentCascadingRuns > 0 && `(${formatPercent(percentCascadingRuns)} / ${formatNumber(avgCascadingReruns)} / MAX ${state.maxInternalReruns} 📈)`
|
|
48
|
+
].filter(v => v).join(" "),
|
|
49
|
+
percentMultipleFullRuns > 0 && `${formatNumber(avgFullReruns)} (${formatPercent(percentMultipleFullRuns)}) ⚠️`,
|
|
50
|
+
`${formatTimeStats(state.evalTimeStats)} 💫 / ${formatTimeStats(state.totalTimeStats)} 🕒`
|
|
51
|
+
].filter(v => v).join(" | "));
|
|
52
|
+
console.log("");
|
|
53
|
+
console.log("=== Per-Function Statistics ===");
|
|
54
|
+
|
|
55
|
+
let perFunctionStats = state.perFunctionStats;
|
|
56
|
+
if (perFunctionStats) {
|
|
57
|
+
for (let functionId in perFunctionStats) {
|
|
58
|
+
let stats = perFunctionStats[functionId];
|
|
59
|
+
let avgInternal = stats.totalInternalReruns / stats.totalCalls;
|
|
60
|
+
let avgFull = stats.totalFullReruns / stats.totalCalls;
|
|
61
|
+
let pctInternal = stats.callsWithMultipleInternalRuns / stats.totalCalls;
|
|
62
|
+
let pctCascading = stats.callsWithCascadingRuns / stats.totalCalls;
|
|
63
|
+
let avgCascading = stats.callsWithCascadingRuns > 0 && stats.totalInternalRerunsForCascading / stats.callsWithCascadingRuns || 0;
|
|
64
|
+
let pctFull = stats.callsWithMultipleFullRuns / stats.totalCalls;
|
|
65
|
+
|
|
66
|
+
console.log([
|
|
67
|
+
`${functionId}: ${formatNumber(stats.totalCalls)} ⚡`,
|
|
68
|
+
[
|
|
69
|
+
`${formatNumber(avgInternal)} ♻️`,
|
|
70
|
+
pctInternal > 0 && `(${formatPercent(pctInternal)} 🔦)`,
|
|
71
|
+
pctCascading > 0 && `(${formatPercent(pctCascading)} / ${formatNumber(avgCascading)} / MAX ${stats.maxInternalReruns} 📈)`
|
|
72
|
+
].filter(v => v).join(" "),
|
|
73
|
+
pctFull > 0 && `${formatNumber(avgFull)} (${formatPercent(pctFull)}) ⚠️`,
|
|
74
|
+
`${formatTimeStats(stats.evalTimeStats)} 💫 / ${formatTimeStats(stats.totalTimeStats)} 🕒`
|
|
75
|
+
].filter(v => v).join(" | "));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
render() {
|
|
81
|
+
ensureSubscribed();
|
|
82
|
+
let state = callState();
|
|
83
|
+
|
|
84
|
+
let avgInternalReruns = state.totalCalls > 0 && state.totalInternalReruns / state.totalCalls || 0;
|
|
85
|
+
let avgFullReruns = state.totalCalls > 0 && state.totalFullReruns / state.totalCalls || 0;
|
|
86
|
+
let percentMultipleInternalRuns = state.totalCalls > 0 && state.callsWithMultipleInternalRuns / state.totalCalls || 0;
|
|
87
|
+
let percentCascadingRuns = state.totalCalls > 0 && state.callsWithCascadingRuns / state.totalCalls || 0;
|
|
88
|
+
let avgCascadingReruns = state.callsWithCascadingRuns > 0 && state.totalInternalRerunsForCascading / state.callsWithCascadingRuns || 0;
|
|
89
|
+
let percentMultipleFullRuns = state.totalCalls > 0 && state.callsWithMultipleFullRuns / state.totalCalls || 0;
|
|
90
|
+
|
|
91
|
+
return <div className={css.button.vbox(4).pad2(4).alignItems("end")} onClick={() => this.showDetailedStats()}>
|
|
92
|
+
<div className={css.hbox(10)}>
|
|
93
|
+
<span title="Committed synced function calls">
|
|
94
|
+
{formatNumber(state.totalCalls)}⚡
|
|
95
|
+
</span>
|
|
96
|
+
<div className={css.hbox(7)}>
|
|
97
|
+
<span title="Number of function evaluations">
|
|
98
|
+
{formatNumber(avgInternalReruns)}♻️
|
|
99
|
+
</span>
|
|
100
|
+
{percentMultipleInternalRuns > 0 && <span title="Cases where the first call did not have all the synced data">
|
|
101
|
+
(🔦{formatPercent(percentMultipleInternalRuns)})
|
|
102
|
+
</span>}
|
|
103
|
+
{percentCascadingRuns > 0 && <span title="The initial sync did not provide all the data, requiring cascading syncing.">
|
|
104
|
+
(📈{formatPercent(percentCascadingRuns)} / {formatNumber(avgCascadingReruns)} / MAX {state.maxInternalReruns})
|
|
105
|
+
</span>}
|
|
106
|
+
</div>
|
|
107
|
+
{percentMultipleFullRuns > 0 && <span title="Rejected calls requiring full reruns. Unless you are changing data another user is actively changing, this is a bug!" className={css.hsl(60, 100, 80).pad2(2, 1).hslcolor(0, 0, 0)}>
|
|
108
|
+
{formatNumber(avgFullReruns)} ({formatPercent(percentMultipleFullRuns)}) ⚠️
|
|
109
|
+
</span>}
|
|
110
|
+
</div>
|
|
111
|
+
<div>
|
|
112
|
+
<span title="Average time to evaluate the application function (excluding proxy overhead)">
|
|
113
|
+
{formatTimeStats(state.evalTimeStats)}💫
|
|
114
|
+
</span>
|
|
115
|
+
{" / "}
|
|
116
|
+
<span title="Average time to evaluate from start to finish, including rejections, etc. Top % shows the top % count, and if top % is shown the other amount has the top values removed.">
|
|
117
|
+
{formatTimeStats(state.totalTimeStats)}🕒
|
|
118
|
+
</span>
|
|
119
|
+
</div>
|
|
120
|
+
<div className={css.hbox(20)}>
|
|
121
|
+
<div className={css.hbox(5)}>
|
|
122
|
+
<span title="Remote watched paths (syncing from other nodes)">
|
|
123
|
+
{formatNumber(state.remotePathCount)}🔥
|
|
124
|
+
</span>
|
|
125
|
+
{" / "}
|
|
126
|
+
<span title="Local watched paths">
|
|
127
|
+
{formatNumber(state.localPathCount)}🏠
|
|
128
|
+
</span>
|
|
129
|
+
{" / "}
|
|
130
|
+
<span title="Total values stored in memory">
|
|
131
|
+
{formatNumber(state.totalValueCount)}📦
|
|
132
|
+
</span>
|
|
133
|
+
{" / "}
|
|
134
|
+
<span title="Watchers">
|
|
135
|
+
{formatNumber(state.proxyWatcherCount)}🕵🏻♀️
|
|
136
|
+
</span>
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
</div>;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { Querysub } from "../4-querysub/QuerysubController";
|
|
2
|
+
import { onPredictionFinished } from "../4-querysub/querysubPrediction";
|
|
3
|
+
import { lazy } from "socket-function/src/caching";
|
|
4
|
+
import { t } from "../2-proxy/schema2";
|
|
5
|
+
import { StatsValue, createStatsValue, addToStatsValue } from "socket-function/src/profiling/stats";
|
|
6
|
+
import { authorityStorage } from "../0-path-value-core/pathValueCore";
|
|
7
|
+
import { pathWatcher } from "../0-path-value-core/PathWatcher";
|
|
8
|
+
import { proxyWatcher } from "../2-proxy/PathValueProxyWatcher";
|
|
9
|
+
|
|
10
|
+
interface CallStatsData {
|
|
11
|
+
totalCalls: number;
|
|
12
|
+
totalInternalReruns: number;
|
|
13
|
+
totalFullReruns: number;
|
|
14
|
+
callsWithMultipleInternalRuns: number;
|
|
15
|
+
callsWithCascadingRuns: number;
|
|
16
|
+
totalInternalRerunsForCascading: number;
|
|
17
|
+
maxInternalReruns: number;
|
|
18
|
+
callsWithMultipleFullRuns: number;
|
|
19
|
+
evalTimeStats: StatsValue;
|
|
20
|
+
timeTakenStats: StatsValue;
|
|
21
|
+
totalTimeStats: StatsValue;
|
|
22
|
+
localPathCount: number;
|
|
23
|
+
remotePathCount: number;
|
|
24
|
+
totalValueCount: number;
|
|
25
|
+
proxyWatcherCount: number;
|
|
26
|
+
perFunctionStats: {
|
|
27
|
+
[functionId: string]: {
|
|
28
|
+
totalCalls: number;
|
|
29
|
+
totalInternalReruns: number;
|
|
30
|
+
totalFullReruns: number;
|
|
31
|
+
callsWithMultipleInternalRuns: number;
|
|
32
|
+
callsWithCascadingRuns: number;
|
|
33
|
+
totalInternalRerunsForCascading: number;
|
|
34
|
+
maxInternalReruns: number;
|
|
35
|
+
callsWithMultipleFullRuns: number;
|
|
36
|
+
evalTimeStats: StatsValue;
|
|
37
|
+
timeTakenStats: StatsValue;
|
|
38
|
+
totalTimeStats: StatsValue;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let statsData: CallStatsData = {
|
|
44
|
+
totalCalls: 0,
|
|
45
|
+
totalInternalReruns: 0,
|
|
46
|
+
totalFullReruns: 0,
|
|
47
|
+
callsWithMultipleInternalRuns: 0,
|
|
48
|
+
callsWithCascadingRuns: 0,
|
|
49
|
+
totalInternalRerunsForCascading: 0,
|
|
50
|
+
maxInternalReruns: 0,
|
|
51
|
+
callsWithMultipleFullRuns: 0,
|
|
52
|
+
evalTimeStats: createStatsValue(),
|
|
53
|
+
timeTakenStats: createStatsValue(),
|
|
54
|
+
totalTimeStats: createStatsValue(),
|
|
55
|
+
localPathCount: 0,
|
|
56
|
+
remotePathCount: 0,
|
|
57
|
+
totalValueCount: 0,
|
|
58
|
+
proxyWatcherCount: 0,
|
|
59
|
+
perFunctionStats: {},
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
let callStateSchema = Querysub.createLocalSchema("callState", {
|
|
63
|
+
sequenceNumber: t.number,
|
|
64
|
+
localPathCount: t.number,
|
|
65
|
+
remotePathCount: t.number,
|
|
66
|
+
totalValueCount: t.number,
|
|
67
|
+
proxyWatcherCount: t.number,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
export function callState(): CallStatsData {
|
|
71
|
+
callStateSchema().sequenceNumber;
|
|
72
|
+
return statsData;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export let ensureSubscribed = lazy(() => {
|
|
76
|
+
onPredictionFinished((data) => {
|
|
77
|
+
statsData.totalCalls++;
|
|
78
|
+
statsData.totalInternalReruns += data.result.totalInternalLoopCount;
|
|
79
|
+
statsData.totalFullReruns += data.result.outerLoopCount;
|
|
80
|
+
addToStatsValue(statsData.evalTimeStats, data.result.evalTime);
|
|
81
|
+
addToStatsValue(statsData.timeTakenStats, data.result.timeTaken);
|
|
82
|
+
addToStatsValue(statsData.totalTimeStats, data.result.totalTime);
|
|
83
|
+
|
|
84
|
+
if (data.result.totalInternalLoopCount > 1) {
|
|
85
|
+
statsData.callsWithMultipleInternalRuns++;
|
|
86
|
+
}
|
|
87
|
+
if (data.result.totalInternalLoopCount > 2) {
|
|
88
|
+
statsData.callsWithCascadingRuns++;
|
|
89
|
+
statsData.totalInternalRerunsForCascading += data.result.totalInternalLoopCount;
|
|
90
|
+
if (data.result.totalInternalLoopCount > statsData.maxInternalReruns) {
|
|
91
|
+
statsData.maxInternalReruns = data.result.totalInternalLoopCount;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (data.result.outerLoopCount > 1) {
|
|
95
|
+
statsData.callsWithMultipleFullRuns++;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (!(data.functionId in statsData.perFunctionStats)) {
|
|
99
|
+
statsData.perFunctionStats[data.functionId] = {
|
|
100
|
+
totalCalls: 0,
|
|
101
|
+
totalInternalReruns: 0,
|
|
102
|
+
totalFullReruns: 0,
|
|
103
|
+
callsWithMultipleInternalRuns: 0,
|
|
104
|
+
callsWithCascadingRuns: 0,
|
|
105
|
+
totalInternalRerunsForCascading: 0,
|
|
106
|
+
maxInternalReruns: 0,
|
|
107
|
+
callsWithMultipleFullRuns: 0,
|
|
108
|
+
evalTimeStats: createStatsValue(),
|
|
109
|
+
timeTakenStats: createStatsValue(),
|
|
110
|
+
totalTimeStats: createStatsValue(),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
let fnStats = statsData.perFunctionStats[data.functionId];
|
|
115
|
+
fnStats.totalCalls++;
|
|
116
|
+
fnStats.totalInternalReruns += data.result.totalInternalLoopCount;
|
|
117
|
+
fnStats.totalFullReruns += data.result.outerLoopCount;
|
|
118
|
+
addToStatsValue(fnStats.evalTimeStats, data.result.evalTime);
|
|
119
|
+
addToStatsValue(fnStats.timeTakenStats, data.result.timeTaken);
|
|
120
|
+
addToStatsValue(fnStats.totalTimeStats, data.result.totalTime);
|
|
121
|
+
|
|
122
|
+
if (data.result.totalInternalLoopCount > 1) {
|
|
123
|
+
fnStats.callsWithMultipleInternalRuns++;
|
|
124
|
+
}
|
|
125
|
+
if (data.result.totalInternalLoopCount > 2) {
|
|
126
|
+
fnStats.callsWithCascadingRuns++;
|
|
127
|
+
fnStats.totalInternalRerunsForCascading += data.result.totalInternalLoopCount;
|
|
128
|
+
if (data.result.totalInternalLoopCount > fnStats.maxInternalReruns) {
|
|
129
|
+
fnStats.maxInternalReruns = data.result.totalInternalLoopCount;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (data.result.outerLoopCount > 1) {
|
|
133
|
+
fnStats.callsWithMultipleFullRuns++;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
Querysub.commit(() => {
|
|
137
|
+
let schema = callStateSchema();
|
|
138
|
+
schema.sequenceNumber = schema.sequenceNumber + 1;
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
function updateSyncStats() {
|
|
143
|
+
let watcherStats = pathWatcher.getWatcherStats();
|
|
144
|
+
let valueCount = authorityStorage.getValueCount();
|
|
145
|
+
let proxyWatcherCount = proxyWatcher.getAllWatchers().size;
|
|
146
|
+
|
|
147
|
+
statsData.localPathCount = watcherStats.localPathCount;
|
|
148
|
+
statsData.remotePathCount = watcherStats.remotePathCount;
|
|
149
|
+
statsData.totalValueCount = valueCount;
|
|
150
|
+
statsData.proxyWatcherCount = proxyWatcherCount;
|
|
151
|
+
|
|
152
|
+
Querysub.commit(() => {
|
|
153
|
+
let schema = callStateSchema();
|
|
154
|
+
schema.localPathCount = watcherStats.localPathCount;
|
|
155
|
+
schema.remotePathCount = watcherStats.remotePathCount;
|
|
156
|
+
schema.totalValueCount = valueCount;
|
|
157
|
+
schema.proxyWatcherCount = proxyWatcherCount;
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
updateSyncStats();
|
|
161
|
+
setInterval(updateSyncStats, 15000);
|
|
162
|
+
});
|
|
@@ -246,7 +246,7 @@ class MachineThreadInfoBase {
|
|
|
246
246
|
}
|
|
247
247
|
|
|
248
248
|
}
|
|
249
|
-
const MachineThreadInfoController = getSyncedController(SocketFunction.register(
|
|
249
|
+
export const MachineThreadInfoController = getSyncedController(SocketFunction.register(
|
|
250
250
|
"MachineThreadInfoController-019c88cb-a16f-7219-9a5e-08919bd1475b",
|
|
251
251
|
new MachineThreadInfoBase(),
|
|
252
252
|
() => ({
|