querysub 0.356.0 → 0.357.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 +8 -0
- package/bin/movelogs.js +4 -0
- package/package.json +12 -6
- package/scripts/postinstall.js +23 -0
- package/src/-a-archives/archiveCache.ts +10 -12
- package/src/-a-archives/archives.ts +29 -0
- package/src/-a-archives/archivesBackBlaze.ts +60 -12
- package/src/-a-archives/archivesDisk.ts +27 -8
- package/src/-a-archives/archivesLimitedCache.ts +21 -0
- package/src/-a-archives/archivesMemoryCache.ts +350 -0
- package/src/-a-archives/archivesPrivateFileSystem.ts +22 -0
- package/src/-g-core-values/NodeCapabilities.ts +3 -0
- package/src/0-path-value-core/auditLogs.ts +5 -1
- package/src/0-path-value-core/pathValueCore.ts +7 -7
- package/src/4-dom/qreact.tsx +1 -0
- package/src/4-querysub/Querysub.ts +1 -5
- package/src/config.ts +5 -0
- package/src/diagnostics/MachineThreadInfo.tsx +235 -0
- package/src/diagnostics/NodeViewer.tsx +3 -2
- package/src/diagnostics/logs/FastArchiveAppendable.ts +79 -42
- package/src/diagnostics/logs/FastArchiveController.ts +102 -63
- package/src/diagnostics/logs/FastArchiveViewer.tsx +36 -8
- package/src/diagnostics/logs/IndexedLogs/BufferIndex.ts +461 -0
- package/src/diagnostics/logs/IndexedLogs/BufferIndexCPP.cpp +327 -0
- package/src/diagnostics/logs/IndexedLogs/BufferIndexCPP.d.ts +18 -0
- package/src/diagnostics/logs/IndexedLogs/BufferIndexCPP.js +1 -0
- package/src/diagnostics/logs/IndexedLogs/BufferIndexHelpers.ts +140 -0
- package/src/diagnostics/logs/IndexedLogs/BufferIndexLogsOptimizationConstants.ts +22 -0
- package/src/diagnostics/logs/IndexedLogs/BufferIndexWAT.wat +1145 -0
- package/src/diagnostics/logs/IndexedLogs/BufferIndexWAT.wat.d.ts +178 -0
- package/src/diagnostics/logs/IndexedLogs/BufferListStreamer.ts +206 -0
- package/src/diagnostics/logs/IndexedLogs/BufferUnitIndex.ts +719 -0
- package/src/diagnostics/logs/IndexedLogs/BufferUnitSet.ts +146 -0
- package/src/diagnostics/logs/IndexedLogs/FilePathSelector.tsx +408 -0
- package/src/diagnostics/logs/IndexedLogs/FindProgressTracker.ts +45 -0
- package/src/diagnostics/logs/IndexedLogs/IndexedLogs.ts +598 -0
- package/src/diagnostics/logs/IndexedLogs/LogStreamer.ts +47 -0
- package/src/diagnostics/logs/IndexedLogs/LogViewer3.tsx +702 -0
- package/src/diagnostics/logs/IndexedLogs/TimeFileTree.ts +236 -0
- package/src/diagnostics/logs/IndexedLogs/binding.gyp +23 -0
- package/src/diagnostics/logs/IndexedLogs/moveIndexLogsToPublic.ts +221 -0
- package/src/diagnostics/logs/IndexedLogs/moveLogsEntry.ts +10 -0
- package/src/diagnostics/logs/LogViewer2.tsx +120 -55
- package/src/diagnostics/logs/TimeRangeSelector.tsx +5 -2
- package/src/diagnostics/logs/diskLogger.ts +32 -48
- package/src/diagnostics/logs/errorNotifications/ErrorNotificationController.ts +3 -2
- package/src/diagnostics/logs/errorNotifications/errorDigests.tsx +1 -0
- package/src/diagnostics/logs/lifeCycleAnalysis/LifeCyclePages.tsx +150 -0
- package/src/diagnostics/logs/lifeCycleAnalysis/lifeCycles.tsx +132 -15
- package/src/diagnostics/logs/lifeCycleAnalysis/test.ts +180 -0
- package/src/diagnostics/logs/lifeCycleAnalysis/test.wat +106 -0
- package/src/diagnostics/logs/lifeCycleAnalysis/test.wat.d.ts +2 -0
- package/src/diagnostics/logs/lifeCycleAnalysis/testHoist.ts +5 -0
- package/src/diagnostics/logs/logViewerExtractField.ts +2 -3
- package/src/diagnostics/managementPages.tsx +10 -0
- package/src/diagnostics/trackResources.ts +1 -1
- package/src/misc/lz4_wasm_nodejs.d.ts +34 -0
- package/src/misc/lz4_wasm_nodejs.js +178 -0
- package/src/misc/lz4_wasm_nodejs_bg.js +94 -0
- package/src/misc/lz4_wasm_nodejs_bg.wasm +0 -0
- package/src/misc/lz4_wasm_nodejs_bg.wasm.d.ts +15 -0
- package/src/storage/CompressedStream.ts +13 -0
- package/src/storage/LZ4.ts +32 -0
- package/src/storage/ZSTD.ts +10 -0
- package/src/wat/watCompiler.ts +1716 -0
- package/src/wat/watGrammar.pegjs +93 -0
- package/src/wat/watHandler.ts +179 -0
- package/src/wat/watInstructions.txt +707 -0
- package/src/zip.ts +3 -89
- package/src/diagnostics/logs/lifeCycleAnalysis/spec.md +0 -125
|
@@ -1,16 +1,133 @@
|
|
|
1
|
-
//todonext
|
|
2
|
-
// Welp... no logs are showing up. That's a problem..
|
|
3
|
-
// Ah, okay, we don't store logs locally. Because... we only log to backblaze? Alright, fair enough...
|
|
4
1
|
/*
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
|
|
16
|
-
|
|
2
|
+
todonext
|
|
3
|
+
|
|
4
|
+
OKAY! CORE CONCEPTS
|
|
5
|
+
- Index needs to be fast searched, so it's uncompressed form has to be small
|
|
6
|
+
- Nesting compression is fine, as long as it's small enough that each search decompresses very little
|
|
7
|
+
- The enemy is storing every single position, we get around this by:
|
|
8
|
+
- In-exact matches, only storing block indexes.
|
|
9
|
+
- Requires full search to verify, but... in practice has low false hit rate
|
|
10
|
+
- Input key (unit) is only inexact matched.
|
|
11
|
+
- Input query almost always has more than 1 byte of uniqueness. This means if even part is only 50% accurate, we can still get very high hit rates (8 bytes means 255/256 hit rate!)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
todonext
|
|
15
|
+
|
|
16
|
+
IMPORTANT! Now I am properly calling shutdown, so none of the streamed logs should ever break. The code should be waiting until everything's fully flushed before it allows the shutdown handler to finish running. If we see any more errors, we need to investigate them.
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
2) If we have the warning about the pending files being too old, also add to that warning a button that will then call client forcemovelogs to public.
|
|
20
|
+
- After we call it, call getPaths again
|
|
21
|
+
2.0) If the file paths are frozen, in the warning about having pending files which are too old, Don't add a button to let them move the files now, but instead, and change the whole messaging of the warning in general, to just say frozen files are too old, and then a button which will then clear the frozen files instead. And when you click it, it'll also call git path to get the latest files.
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
3) Start the servers again, and deploy all of our code
|
|
25
|
+
4) Make it easy to enable or disable an entire server, regardless of what services are on it.
|
|
26
|
+
|
|
27
|
+
2) Create lot of remote server logs
|
|
28
|
+
- Via our refresh loop
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
2.0) SUPPORT reading pending from multiple servers
|
|
32
|
+
- The main controller has to find a node on each other machine, and call it. Only one node per machine though, so it shouldn't be too difficult.
|
|
33
|
+
|
|
34
|
+
2) Add a UI toggle to read public logs (only shows up on a non-public server though, as otherwise it wouldn't make sense)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
6) Long query search optimization?
|
|
40
|
+
- Try pasting in large strings (200+ characters), and see if it's THAT slow. 10s is probably okay (if 20 characters is 1s) when searching ~100GB base logs.
|
|
41
|
+
- If we find long queries are causing too much lag, We can do a thing where after a certain number of characters we start reading in the blocks, and if the actual match percentage in those blocks is too low, then we start using more characters to try to filter the blocks we read in.
|
|
42
|
+
- I think we might want to actually do an index of on the units? Maybe just on SOME blocks? Because it might not match because of an ordering issue, but if we look for the actual unit, then we'll know for sure if it was a false positive or not.
|
|
43
|
+
- We also might want to make a mode where we always check all of the units for all the blocks, and then we output how often there were false positives, our hit rate. Before we were just looking at the number of blocks that had the actual full result, but it might be that every single block was correct, that it had all the units. It's just the ordering that was wrong, which the hashing algorithm can't fix. And it also might be the case that adding more specific characters won't really fix it if it's just a thing of two very large strings that sometimes are in different places (As in, it could be that if you search for the exact result you want, it still might be ambiguous and you still might have to load blocks which don't have that result)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
LogViewer/FastArchiveAppendable updates
|
|
48
|
+
- I think LogViewer just goes away
|
|
49
|
+
- The error notifications... will probably just scan the logs?
|
|
50
|
+
- At least we can make the suppression check function significantly faster by having wildcard segments, and doing an initial scan for existence (I think we can reuse BufferIndexHelpers)
|
|
51
|
+
- ANd check anywhere else using FastARchiveAppendable
|
|
52
|
+
- Delete all the old logviewer/fastarchiveappendable code
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
// 0) Add LZ4 compression to socket-function by default
|
|
57
|
+
// - Allow setting "compress" to "none" or "zip" or "zip0" or "zip3", etc, for levels.
|
|
58
|
+
// - REQUIRES feature checking the remote, to make sure it is new enough to accept this.
|
|
59
|
+
// - A generic thing which gets the version is probably fine.
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
// todonext
|
|
63
|
+
// 1) Fix missing __NAME__
|
|
64
|
+
// "Received PathValue for path" misses name?
|
|
65
|
+
// - Maybe the missing name only happens when we rate limit?
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
// todonext;
|
|
71
|
+
// 0) Write the schema
|
|
72
|
+
// 1) Use isTrackingAuditLogs flag in auditting code to also log to disk
|
|
73
|
+
// 2) Update PathWatcher.watchPath, and all locations that log path counts to also logs counts, with many audit log calls instead of one
|
|
74
|
+
// 3) Add threadId in our initial authorization state, as it's very useful for debugging
|
|
75
|
+
// - Or just something that's going to be unique. We actually do have to verify that it is somewhat unique, as if clients intentionally make it always collide between different clients, it will break our logging, which is problem...
|
|
76
|
+
// 4) Track caller threadId and machineId where possible in auditLogs
|
|
77
|
+
// 5) Set up one entirely hard-coded check for when a path starts synchronizing, just so we can verify the data is getting through.
|
|
78
|
+
// 7) Decide how we're going to store it, and setup the controller
|
|
79
|
+
// 8) Get the AI to set up some basic UI to manage it.
|
|
80
|
+
// - For now, we'll run the phases one after the other. Controlled by the caller. Caching is going to come much later.
|
|
81
|
+
// - The first phase I think we can run when we receive the logs directly. This will make progress nice. And then the second phase will run automatically in the finish function. We'll have to add additional progress for that, which shouldn't be too difficult.
|
|
82
|
+
// - Having the finish function fork off into an async is probably fine, although we will have to expose the cancellation promise to the finish function?
|
|
83
|
+
// - Or do we even need cancellation? Are we ever going to even keep this code? So if we have a server precaching the values, we still need the pending values to be parsed somewhere. Hmm... That's annoying. Are we just not going to use fast archives for this?
|
|
84
|
+
// - MAYBE We can have the Fast Archives support external caching, so it'll give us the name of the file, and we'll tell it if it's cached or not. Actually, it can give us the name of all the files, and we'll tell it if we have a cached result for it. And if we do, we'll load the cache result, and it won't do any of the parsing of that file.
|
|
85
|
+
// 9) Stress test it, by automating something to load a page repeatedly (which should cause a lot of path logs). We should try at least 10K page refreshes, and nothing should break...
|
|
86
|
+
// - If my estimates are correct, and a page load of a large book results in ~5K logs, that will use ~2.5MB of uncompressed space, (~100KB compressed). Which... is acceptable. 10K page loads is 1GB, so a million would cost 1 USD/month to store. AND that's if we keep storing all audits in the logs, which we don't really have to do...
|
|
87
|
+
// - Processing it, on the other hand, will be kind of slow. Looks like we decompress about ten MB a second. But... there's not much we can do about that... unless... we searched on the compressed data directly? Hmm... or at least optimized based on it.
|
|
88
|
+
// 10) Add log file overview page, so we can keep an eye on the size of logs
|
|
89
|
+
// 10.1) Start storing the log count in the log file names
|
|
90
|
+
// - WHICH, requires breaking all of our old logs, but... that's not too big of deal
|
|
91
|
+
// - ONLY for the non-pending logs
|
|
92
|
+
// 11) Pull requests our lz4-wasm code. It's purely AI generated, but it might be of some interest.
|
|
93
|
+
// - As in, supporting streaming and decoding from a stream
|
|
94
|
+
// - REMEMBER to delete all of our test files and test code, and also really clean up the pull request before we make it.
|
|
95
|
+
/*
|
|
96
|
+
Two phases, and second phase has limitted, as some of our life cycles might explode quadratically.
|
|
97
|
+
*/
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
// Searching in previous state
|
|
101
|
+
// Using variables from logs?
|
|
102
|
+
// Using variables from lifecycle?
|
|
103
|
+
// The FORM we match will be pretty much always the same (not depending on variables). If we absolutely need to we can do some late filtering in the second phase, but I don't think we'll need to. However the life cycle it becomes a part of, that will depend on the state.
|
|
104
|
+
// OH! The start lifecycle entry will create a lifecycle, THEN we match. The later matches might not be as restrictive as the start life cycle. SOO...
|
|
105
|
+
// start = [path, clientId]
|
|
106
|
+
// watch = [path]
|
|
107
|
+
// AND SO, This is what we can do to kind of expand our paths. So really, it's more of a debug thing, where the start is something that provides a key for what we're debugging. And then after it, we'll have different lines which can match whichever data we want.
|
|
108
|
+
// - The only restriction is the other lines have to happen after the start and before the end.
|
|
109
|
+
// - The end will be the first end matched as well
|
|
110
|
+
// - AND Optionally, you can make it so that the start ends the previous one
|
|
111
|
+
// - And you can also just not provide an end. There's no reason the life cycle needs to end.
|
|
112
|
+
// - I think technically if you add a start and it keeps triggering and you don't tell it that it should end the previous one, then there'll be a lot of overlapping and some of the life cycles will get quite large. But we can handle that by throttling and lazy evaluation, so it shouldn't actually be an issue.
|
|
113
|
+
// todonext;
|
|
114
|
+
// // Okay, so it's looking like the first thing we're going to do is match the start, and then once we find the start, if we want to expand that life cycle, then we do a second phase search.
|
|
115
|
+
// todonext;
|
|
116
|
+
// // HMM... So actually what kind of variables do we need? I guess if we want to map between IDs. But then can't we just Match some line That gives us the mapping. And then, presumably, that'll be early on in the life cycle....
|
|
117
|
+
// todonext;
|
|
118
|
+
// // OH! Okay, so we want to allow some logs in the life cycle to match before the start? But that's all. They just match before the start. And I think we have to define how long they can match before the start. Obviously, we can't search forever. And then they're just normal lines after that. They can set life cycle variables, and we can access life cycle variables.
|
|
119
|
+
// todonext;
|
|
120
|
+
// // Yes, so... The variables are going to be a lot simple. It's just the lifecycle will have variables associated with it, which lines in the life cycle can set.
|
|
121
|
+
// todonext;
|
|
122
|
+
// // Let's not have any regex parsing either. Lifecycles entries can just say, I care about these variables and we expect them to be a part of the log object, and then we add them to the lifecycle.
|
|
123
|
+
// // - Which is really more for UI organization, as we can say these are important. And prevents the bug of some random log having to have happen to having a thread ID, but we have a thread ID and we mean the client thread ID, etc., etc. We just make it explicit per line, and then we don't run into that bug ever.
|
|
124
|
+
|
|
125
|
+
// TODO: Eventually, if we need it, we can have entries find other life cycles, either matching many, the latest, etc, and take variables from them PURELY FOR DISPLAY PURPOSES. But right at this moment, that's not needed.
|
|
126
|
+
|
|
127
|
+
type LifeCycle = {
|
|
128
|
+
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
type LifeCycleEntry = {
|
|
132
|
+
|
|
133
|
+
};
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
import { formatNumber, formatPercent, formatTime } from "socket-function/src/formatting/format";
|
|
4
|
+
import { LogDatum, getLoggers, getLoggers2, logDisk } from "../diskLogger";
|
|
5
|
+
import { FastArchiveAppendableControllerBase, getFileMetadataHash } from "../FastArchiveController";
|
|
6
|
+
import { SocketFunction } from "socket-function/SocketFunction";
|
|
7
|
+
import { Querysub } from "../../../4-querysub/QuerysubController";
|
|
8
|
+
import { sort, timeInDay, timeInHour } from "socket-function/src/misc";
|
|
9
|
+
import { getDomain, isPublic } from "../../../config";
|
|
10
|
+
//import { createLogScanner } from "../FastArchiveAppendable";
|
|
11
|
+
import { urlCache } from "../errorNotifications/ErrorNotificationController";
|
|
12
|
+
import fs from "fs";
|
|
13
|
+
import { blue, green, magenta, red } from "socket-function/src/formatting/logColors";
|
|
14
|
+
import { Zip } from "socket-function/src/Zip";
|
|
15
|
+
import { shuffle } from "../../../misc/random";
|
|
16
|
+
import { BufferIndex } from "../IndexedLogs/BufferIndex";
|
|
17
|
+
import { createLogScanner } from "../FastArchiveAppendable";
|
|
18
|
+
import { LZ4 } from "../../../storage/LZ4";
|
|
19
|
+
import { measureBlock, measureCode } from "socket-function/src/profiling/measure";
|
|
20
|
+
import { addAdditionalExtensions, compileTransform2 } from "../../../../../typenode";
|
|
21
|
+
import { allocateBuffer, watHandler, WatModuleExports } from "../../../wat/watHandler";
|
|
22
|
+
import { testWATCompiler } from "../../../wat/watCompiler";
|
|
23
|
+
import { populateUnits } from "../IndexedLogs/BufferIndexCPP";
|
|
24
|
+
import { BufferUnitIndex } from "../IndexedLogs/BufferUnitIndex";
|
|
25
|
+
import { IndexedLogResults, IndexedLogs } from "../IndexedLogs/IndexedLogs";
|
|
26
|
+
import { getArchivesBackblaze } from "../../../-a-archives/archivesBackBlaze";
|
|
27
|
+
import { shutdown } from "../../periodic";
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
// export type IndexedLogResults<T> = {
|
|
31
|
+
// results: T[];
|
|
32
|
+
|
|
33
|
+
// // NOTE: A lot of the metadata won't be accurate if multiple searches happen at the same time. However, for debugging, it should be sufficient.
|
|
34
|
+
// reads: {
|
|
35
|
+
// cached: boolean;
|
|
36
|
+
// remote: boolean;
|
|
37
|
+
// count: number;
|
|
38
|
+
// size: number;
|
|
39
|
+
|
|
40
|
+
// totalSize: number;
|
|
41
|
+
// totalCount: number;
|
|
42
|
+
// }[];
|
|
43
|
+
|
|
44
|
+
// localFilesSearched: number;
|
|
45
|
+
// backblazeFilesSearched: number;
|
|
46
|
+
|
|
47
|
+
// totalBlockCount: number;
|
|
48
|
+
// blockCheckedCount: number;
|
|
49
|
+
// blocksCheckedCompressedSize: number;
|
|
50
|
+
// blocksCheckedDecompressedSize: number;
|
|
51
|
+
|
|
52
|
+
// indexesSearched: number;
|
|
53
|
+
// indexSize: number;
|
|
54
|
+
|
|
55
|
+
// fileFindTime: number;
|
|
56
|
+
// indexSearchTime: number;
|
|
57
|
+
// blockSearchTime: number;
|
|
58
|
+
// };
|
|
59
|
+
function displayNiceResults(results: IndexedLogResults) {
|
|
60
|
+
let totalSizeRead = 0;
|
|
61
|
+
let cachedSize = 0;
|
|
62
|
+
let uncachedSize = 0;
|
|
63
|
+
let uncachedCount = 0;
|
|
64
|
+
let uncachedRemoteSize = 0;
|
|
65
|
+
let uncachedRemoteCount = 0;
|
|
66
|
+
let totalSize = 0;
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
for (let read of results.reads) {
|
|
70
|
+
totalSizeRead += read.size;
|
|
71
|
+
if (read.cached) {
|
|
72
|
+
cachedSize += read.size;
|
|
73
|
+
} else {
|
|
74
|
+
uncachedSize += read.size;
|
|
75
|
+
uncachedCount += read.count;
|
|
76
|
+
totalSize += read.size;
|
|
77
|
+
}
|
|
78
|
+
if (read.remote && !read.cached) {
|
|
79
|
+
uncachedRemoteSize += read.size;
|
|
80
|
+
uncachedRemoteCount += read.count;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
// file => index => block
|
|
86
|
+
let parts = [
|
|
87
|
+
`${magenta(formatNumber(results.matchCount))} ${green("results")}`,
|
|
88
|
+
`${blue(formatTime(results.timeToFirstMatch))} until first match`,
|
|
89
|
+
`${blue(formatTime(results.fileFindTime))} file`,
|
|
90
|
+
`${blue(formatTime(results.indexSearchTime))} index`,
|
|
91
|
+
`${blue(formatTime(results.blockSearchTime))} block`,
|
|
92
|
+
`disk read ${magenta(formatNumber(uncachedSize) + "B")} (${magenta(formatPercent(uncachedRemoteSize / totalSizeRead))} (${magenta(formatNumber(uncachedRemoteCount))}) remote) / ${magenta(formatNumber(totalSize) + "B")} total`,
|
|
93
|
+
`${magenta(formatNumber(results.localFilesSearched + results.backblazeFilesSearched))} files`,
|
|
94
|
+
`${magenta(formatNumber(results.indexesSearched))} indexes (${magenta(formatNumber(results.indexSize) + "B")}, ${magenta(formatPercent(results.indexSize / totalSize))})`,
|
|
95
|
+
`${magenta(formatNumber(results.blockCheckedCount))} / ${magenta(formatNumber(results.totalBlockCount))} blocks (${magenta(formatNumber(results.blocksCheckedCompressedSize) + "B")} unpacked to ${magenta(formatNumber(results.blocksCheckedDecompressedSize) + "B")})`,
|
|
96
|
+
];
|
|
97
|
+
|
|
98
|
+
if (results.fileErrors.length > 0) {
|
|
99
|
+
for (let error of results.fileErrors) {
|
|
100
|
+
console.error(error);
|
|
101
|
+
}
|
|
102
|
+
parts.push(`${red(formatNumber(results.fileErrors.length))} files failed`);
|
|
103
|
+
}
|
|
104
|
+
if (results.blockErrors.length > 0) {
|
|
105
|
+
for (let error of results.blockErrors) {
|
|
106
|
+
console.error(error);
|
|
107
|
+
}
|
|
108
|
+
parts.push(`${red(formatNumber(results.blockErrors.length))} blocks failed`);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
console.log(parts.join(" | "));
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async function main() {
|
|
115
|
+
|
|
116
|
+
Querysub.COMPRESS_NETWORK;
|
|
117
|
+
let loggers = getLoggers2();
|
|
118
|
+
let logger = loggers?.logLogs;
|
|
119
|
+
if (!logger) throw new Error("Loggers not available?");
|
|
120
|
+
await logger.moveLogsToPublic(true);
|
|
121
|
+
for (let i = 0; i < 2; i++) {
|
|
122
|
+
let matches: LogDatum[] = [];
|
|
123
|
+
let results = await logger.find({
|
|
124
|
+
params: {
|
|
125
|
+
findBuffer: Buffer.from("new non-local WATCH PARENT*.,querysubtest._com.,PathFunctionRunner.,audio.,Data.,libraryCharacters."),
|
|
126
|
+
limit: 1000,
|
|
127
|
+
startTime: 0,
|
|
128
|
+
endTime: Date.now(),
|
|
129
|
+
disableWildCards: false,
|
|
130
|
+
only: "public",
|
|
131
|
+
},
|
|
132
|
+
onResult: (match: LogDatum) => {
|
|
133
|
+
matches.push(match);
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
sort(matches, x => -x.time);
|
|
137
|
+
displayNiceResults(results);
|
|
138
|
+
console.log(`${green("Found log from")} ${magenta(formatTime(Date.now() - (matches.at(0)?.time || 0)))} ago`);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// await logger.TEST_deleteAllLogs();
|
|
142
|
+
// let logs: string[] = [];
|
|
143
|
+
// for (let i = 0; i < 1000 * 100; i++) {
|
|
144
|
+
// let log = `Hello, world! ${i}`;
|
|
145
|
+
// logs.push(log);
|
|
146
|
+
// logDisk("log", log);
|
|
147
|
+
// }
|
|
148
|
+
// await logger.TEST_flushNow();
|
|
149
|
+
// let results = await logger.find({
|
|
150
|
+
// findBuffer: Buffer.from(logs[99999]),
|
|
151
|
+
// limit: 1000,
|
|
152
|
+
// startTime: 0,
|
|
153
|
+
// endTime: Date.now(),
|
|
154
|
+
// });
|
|
155
|
+
// console.log(results.results[0]);
|
|
156
|
+
// displayNiceResults(results);
|
|
157
|
+
// await logger.moveLogsToPublic(true);
|
|
158
|
+
|
|
159
|
+
// let results2 = await logger.find({
|
|
160
|
+
// findBuffer: Buffer.from(logs[99999]),
|
|
161
|
+
// limit: 1000,
|
|
162
|
+
// startTime: 0,
|
|
163
|
+
// endTime: Date.now(),
|
|
164
|
+
// only: "backblaze",
|
|
165
|
+
// });
|
|
166
|
+
// displayNiceResults(results2);
|
|
167
|
+
|
|
168
|
+
await shutdown();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
async function measureMain() {
|
|
172
|
+
await measureCode(main);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
//testWATCompiler().catch(console.error).finally(() => process.exit());
|
|
177
|
+
|
|
178
|
+
//test().catch(console.error).finally(() => process.exit());
|
|
179
|
+
|
|
180
|
+
measureMain().catch(console.error).finally(() => process.exit());
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
(module
|
|
2
|
+
;; Import memory from JavaScript (with memory64 support for >4GB).
|
|
3
|
+
;; Callers use allocateBuffer(exports, size) from supportWat.ts to
|
|
4
|
+
;; request scratch regions; memory will be grown automatically as needed.
|
|
5
|
+
(import "env" "memory" (memory i64 1))
|
|
6
|
+
|
|
7
|
+
;; Export the heap base so the allocator knows where static data ends.
|
|
8
|
+
;; With no static data section here, the heap starts at byte 0.
|
|
9
|
+
(global (export "__heap_base") i32 (i32.const 0))
|
|
10
|
+
|
|
11
|
+
;; Add function: adds two i32 integers
|
|
12
|
+
(func $add (param $a i32) (param $b i32) (result i32)
|
|
13
|
+
local.get $a
|
|
14
|
+
local.get $b
|
|
15
|
+
i32.add
|
|
16
|
+
)
|
|
17
|
+
(export "add" (func $add))
|
|
18
|
+
|
|
19
|
+
;; Multiply function: multiplies two i32 integers
|
|
20
|
+
(func $multiply (param $a i32) (param $b i32) (result i32)
|
|
21
|
+
local.get $a
|
|
22
|
+
local.get $b
|
|
23
|
+
i32.mul
|
|
24
|
+
)
|
|
25
|
+
(export "multiply" (func $multiply))
|
|
26
|
+
|
|
27
|
+
;; stddev(offset: i32, count: i32) -> f64
|
|
28
|
+
;;
|
|
29
|
+
;; Computes the population standard deviation of `count` f64 values
|
|
30
|
+
;; stored contiguously in memory starting at byte `offset`.
|
|
31
|
+
;; Each value occupies 8 bytes (little-endian IEEE 754 double).
|
|
32
|
+
;; Returns 0.0 when count == 0.
|
|
33
|
+
(func $stddev (param $offset i32) (param $count i32) (result f64)
|
|
34
|
+
(local $i i32)
|
|
35
|
+
(local $sum f64)
|
|
36
|
+
(local $mean f64)
|
|
37
|
+
(local $diff f64)
|
|
38
|
+
(local $variance_sum f64)
|
|
39
|
+
|
|
40
|
+
;; Guard: return 0 if count == 0
|
|
41
|
+
(if (i32.eqz (local.get $count))
|
|
42
|
+
(then (return (f64.const 0)))
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
;; Pass 1: compute sum
|
|
46
|
+
(local.set $i (i32.const 0))
|
|
47
|
+
(local.set $sum (f64.const 0))
|
|
48
|
+
(block $break1
|
|
49
|
+
(loop $loop1
|
|
50
|
+
(br_if $break1 (i32.ge_u (local.get $i) (local.get $count)))
|
|
51
|
+
(local.set $sum
|
|
52
|
+
(f64.add
|
|
53
|
+
(local.get $sum)
|
|
54
|
+
(f64.load
|
|
55
|
+
(i32.add
|
|
56
|
+
(local.get $offset)
|
|
57
|
+
(i32.mul (local.get $i) (i32.const 8))
|
|
58
|
+
)
|
|
59
|
+
)
|
|
60
|
+
)
|
|
61
|
+
)
|
|
62
|
+
(local.set $i (i32.add (local.get $i) (i32.const 1)))
|
|
63
|
+
(br $loop1)
|
|
64
|
+
)
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
;; mean = sum / count
|
|
68
|
+
(local.set $mean
|
|
69
|
+
(f64.div (local.get $sum) (f64.convert_i32_u (local.get $count)))
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
;; Pass 2: compute sum of squared deviations
|
|
73
|
+
(local.set $i (i32.const 0))
|
|
74
|
+
(local.set $variance_sum (f64.const 0))
|
|
75
|
+
(block $break2
|
|
76
|
+
(loop $loop2
|
|
77
|
+
(br_if $break2 (i32.ge_u (local.get $i) (local.get $count)))
|
|
78
|
+
(local.set $diff
|
|
79
|
+
(f64.sub
|
|
80
|
+
(f64.load
|
|
81
|
+
(i32.add
|
|
82
|
+
(local.get $offset)
|
|
83
|
+
(i32.mul (local.get $i) (i32.const 8))
|
|
84
|
+
)
|
|
85
|
+
)
|
|
86
|
+
(local.get $mean)
|
|
87
|
+
)
|
|
88
|
+
)
|
|
89
|
+
(local.set $variance_sum
|
|
90
|
+
(f64.add
|
|
91
|
+
(local.get $variance_sum)
|
|
92
|
+
(f64.mul (local.get $diff) (local.get $diff))
|
|
93
|
+
)
|
|
94
|
+
)
|
|
95
|
+
(local.set $i (i32.add (local.get $i) (i32.const 1)))
|
|
96
|
+
(br $loop2)
|
|
97
|
+
)
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
;; return sqrt(variance_sum / count)
|
|
101
|
+
(f64.sqrt
|
|
102
|
+
(f64.div (local.get $variance_sum) (f64.convert_i32_u (local.get $count)))
|
|
103
|
+
)
|
|
104
|
+
)
|
|
105
|
+
(export "stddev" (func $stddev))
|
|
106
|
+
)
|
|
@@ -2,7 +2,7 @@ import { ScanFnc } from "./FastArchiveViewer";
|
|
|
2
2
|
|
|
3
3
|
export function createLogViewerExtractField(
|
|
4
4
|
fieldName: string,
|
|
5
|
-
onFieldValue: (value: string) => void,
|
|
5
|
+
onFieldValue: (value: string, unpackedSize: number) => void,
|
|
6
6
|
): ScanFnc {
|
|
7
7
|
let fieldNameBuffer = Buffer.from(`${JSON.stringify(fieldName)}:"`);
|
|
8
8
|
let quoteChar = Buffer.from(`"`)[0];
|
|
@@ -19,7 +19,7 @@ export function createLogViewerExtractField(
|
|
|
19
19
|
let start = i + j + 1;
|
|
20
20
|
for (let k = start; k < posEnd; k++) {
|
|
21
21
|
if (data[k] === quoteChar) {
|
|
22
|
-
onFieldValue(data.slice(start, k).toString());
|
|
22
|
+
onFieldValue(data.slice(start, k).toString(), posEnd - start);
|
|
23
23
|
break;
|
|
24
24
|
}
|
|
25
25
|
if (data[k] === escapeChar) {
|
|
@@ -31,7 +31,6 @@ export function createLogViewerExtractField(
|
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
|
-
onFieldValue("");
|
|
35
34
|
return false;
|
|
36
35
|
};
|
|
37
36
|
}
|
|
@@ -91,6 +91,16 @@ export async function registerManagementPages2(config: {
|
|
|
91
91
|
componentName: "LogViewer2",
|
|
92
92
|
getModule: () => import("./logs/LogViewer2"),
|
|
93
93
|
});
|
|
94
|
+
inputPages.push({
|
|
95
|
+
title: "Logs3",
|
|
96
|
+
componentName: "LogViewer3",
|
|
97
|
+
getModule: () => import("./logs/IndexedLogs/LogViewer3"),
|
|
98
|
+
});
|
|
99
|
+
inputPages.push({
|
|
100
|
+
title: "Life Cycles",
|
|
101
|
+
componentName: "LifeCyclePages",
|
|
102
|
+
getModule: () => import("./logs/lifeCycleAnalysis/LifeCyclePages"),
|
|
103
|
+
});
|
|
94
104
|
inputPages.push({
|
|
95
105
|
title: "Error Digests",
|
|
96
106
|
componentName: "ErrorDigestPage",
|
|
@@ -86,7 +86,7 @@ function logResourcesNow() {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
registerMeasureInfo(() => {
|
|
89
|
-
return
|
|
89
|
+
return `MEM ${formatNumber(getUsedHeapSize())}B+${formatNumber(getBufferUsage())}B/${formatNumber(getHeapSize())}B `;
|
|
90
90
|
});
|
|
91
91
|
|
|
92
92
|
registerPeriodic(logResourcesNow);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Streaming LZ4 compressor (frame format with linked blocks).
|
|
6
|
+
* Concatenate all output chunks to form a complete LZ4 frame.
|
|
7
|
+
*/
|
|
8
|
+
export class Lz4StreamCompressor {
|
|
9
|
+
free(): void;
|
|
10
|
+
[Symbol.dispose](): void;
|
|
11
|
+
compress(input: Uint8Array): Uint8Array;
|
|
12
|
+
constructor();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* One-shot block compression with size prepended.
|
|
17
|
+
*/
|
|
18
|
+
export function compress(input: Uint8Array): Uint8Array;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* One-shot block decompression with size prepended.
|
|
22
|
+
*/
|
|
23
|
+
export function decompress(input: Uint8Array): Uint8Array;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Decompress an LZ4 stream (frame format).
|
|
27
|
+
* Auto-injects end marker if missing. On error, returns partial data and sets a warning.
|
|
28
|
+
*/
|
|
29
|
+
export function decompress_stream(input: Uint8Array): Uint8Array;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Get and clear the last warning from decompression.
|
|
33
|
+
*/
|
|
34
|
+
export function get_last_warning(): string | undefined;
|