querysub 0.393.0 → 0.395.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/package.json +1 -1
- package/src/-a-archives/archivesJSONT.ts +71 -8
- package/src/0-path-value-core/pathValueCore.ts +20 -1
- package/src/5-diagnostics/GenericFormat.tsx +1 -1
- package/src/deployManager/components/MachinesListPage.tsx +1 -2
- package/src/diagnostics/logs/IndexedLogs/BufferIndex.ts +12 -3
- package/src/diagnostics/logs/IndexedLogs/BufferIndexHelpers.ts +8 -3
- package/src/diagnostics/logs/IndexedLogs/BufferUnitIndex.ts +24 -9
- package/src/diagnostics/logs/IndexedLogs/BufferUnitSet.ts +0 -1
- package/src/diagnostics/logs/IndexedLogs/FindProgressTracker.ts +21 -5
- package/src/diagnostics/logs/IndexedLogs/IndexedLogs.ts +10 -4
- package/src/diagnostics/logs/IndexedLogs/LogViewer3.tsx +95 -124
- package/src/diagnostics/logs/IndexedLogs/RenderSearchStats.tsx +127 -0
- package/src/diagnostics/logs/IndexedLogs/bufferSearchFindMatcher.ts +3 -0
- package/src/diagnostics/logs/IndexedLogs/moveIndexLogsToPublic.ts +9 -4
- package/src/diagnostics/logs/TimeRangeSelector.tsx +11 -2
- package/src/diagnostics/logs/errorNotifications2/ErrorNotificationPage.tsx +1 -4
- package/src/diagnostics/logs/errorNotifications2/errorNotifications.ts +1 -1
- package/src/diagnostics/logs/lifeCycleAnalysis/LifeCyclePage.tsx +946 -0
- package/src/diagnostics/logs/lifeCycleAnalysis/lifeCycleMatching.ts +49 -0
- package/src/diagnostics/logs/lifeCycleAnalysis/lifeCycleSearch.tsx +553 -0
- package/src/diagnostics/logs/lifeCycleAnalysis/lifeCycles.tsx +125 -89
- package/src/diagnostics/managementPages.tsx +17 -1
- package/src/functional/{limitProcessing.ts → throttleProcessing.ts} +1 -1
- package/src/library-components/StartEllipsis.tsx +13 -0
- package/src/misc.ts +4 -0
- package/src/diagnostics/logs/lifeCycleAnalysis/test.wat +0 -106
- package/src/diagnostics/logs/lifeCycleAnalysis/test.wat.d.ts +0 -2
- package/src/diagnostics/logs/lifeCycleAnalysis/testHoist.ts +0 -5
package/.cursorrules
CHANGED
|
@@ -8,6 +8,8 @@ Use double quotes.
|
|
|
8
8
|
|
|
9
9
|
When running a command in the current project, don't "cd" to it. It's redundant, and won't work.
|
|
10
10
|
|
|
11
|
+
Use the tool calls in order to modify files. Don't try to run terminal commands to modify files.
|
|
12
|
+
|
|
11
13
|
Don't use redundant comments. If it's a single line and the function name says the same thing that the comment is going to say, you don't need the comment.
|
|
12
14
|
|
|
13
15
|
When you're inline passing a lambda as an argument, never specify the type. The type should always be inferred. Specifying the type is bad, and it's hard coding, and we don't like hard coding.
|
|
@@ -32,10 +34,16 @@ Follow the rule of minimum scoping. If something can be a local variable, it sho
|
|
|
32
34
|
|
|
33
35
|
Try not to use "null", and instead always use "undefined".
|
|
34
36
|
|
|
37
|
+
Use square brackets for arrays, not a generic.
|
|
38
|
+
USE: T[]
|
|
39
|
+
NEVER: Array<T>
|
|
40
|
+
|
|
35
41
|
Never try to add dynamic pluralization in the UI, just use an s. If you add dynamic pluralization, if the code ever gets localized, all of your changes have to be undone, and you just made localization much harder.
|
|
36
42
|
|
|
37
43
|
Never use the ternary operator. Instead, do this: "x ? y : z" => "x && y || z".
|
|
38
44
|
|
|
45
|
+
Never use <h2>, <h3>, etc, they have bad styling.
|
|
46
|
+
|
|
39
47
|
If are inside an async Event Handlers, you need to use... Querysub.onCommitFinished(() => ...). and put the async code inside the callback. Then when you set state, you need to put the state setting code inside of Querysub.commit(() => ...).
|
|
40
48
|
|
|
41
49
|
The site automatically builds and hotreloads. Just save the files. DO NOT try to run any build scripts, because it automatically builds on save. DO NOT RUN "npm run build". DO NOT TRY TO RUN UNIT TESTS. DO NOT TRY TO RUN TESTS.
|
package/package.json
CHANGED
|
@@ -13,6 +13,13 @@ export type ArchiveT<T> = {
|
|
|
13
13
|
|
|
14
14
|
export function archiveJSONT<T>(archives: () => Archives): ArchiveT<T> {
|
|
15
15
|
archives = lazy(archives);
|
|
16
|
+
|
|
17
|
+
let valuesCache = new Map<string, {
|
|
18
|
+
createTime: number;
|
|
19
|
+
size: number;
|
|
20
|
+
value: Buffer;
|
|
21
|
+
}>();
|
|
22
|
+
|
|
16
23
|
async function get(key: string) {
|
|
17
24
|
let buffer = await archives().get(key);
|
|
18
25
|
if (!buffer) return undefined;
|
|
@@ -28,15 +35,71 @@ export function archiveJSONT<T>(archives: () => Archives): ArchiveT<T> {
|
|
|
28
35
|
return (await archives().find("")).map(value => value.toString());
|
|
29
36
|
}
|
|
30
37
|
async function values() {
|
|
31
|
-
let
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
38
|
+
let infos = await archives().findInfo("");
|
|
39
|
+
|
|
40
|
+
let needsUpdate = false;
|
|
41
|
+
let currentKeys = new Set(infos.map(info => info.path));
|
|
42
|
+
let cachedKeys = new Set(valuesCache.keys());
|
|
43
|
+
|
|
44
|
+
if (currentKeys.size !== cachedKeys.size) {
|
|
45
|
+
needsUpdate = true;
|
|
46
|
+
} else {
|
|
47
|
+
for (let info of infos) {
|
|
48
|
+
let cached = valuesCache.get(info.path);
|
|
49
|
+
if (!cached || cached.createTime !== info.createTime || cached.size !== info.size) {
|
|
50
|
+
needsUpdate = true;
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
37
53
|
}
|
|
38
|
-
}
|
|
39
|
-
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (needsUpdate) {
|
|
57
|
+
let maxRetries = 10;
|
|
58
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
59
|
+
infos = await archives().findInfo("");
|
|
60
|
+
|
|
61
|
+
valuesCache.clear();
|
|
62
|
+
let allFound = true;
|
|
63
|
+
|
|
64
|
+
await Promise.all(infos.map(async info => {
|
|
65
|
+
let buffer = await archives().get(info.path);
|
|
66
|
+
if (!buffer) {
|
|
67
|
+
allFound = false;
|
|
68
|
+
} else {
|
|
69
|
+
valuesCache.set(info.path, {
|
|
70
|
+
createTime: info.createTime,
|
|
71
|
+
size: info.size,
|
|
72
|
+
value: buffer
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}));
|
|
76
|
+
|
|
77
|
+
if (!allFound) continue;
|
|
78
|
+
|
|
79
|
+
let newInfos = await archives().findInfo("");
|
|
80
|
+
if (newInfos.length !== infos.length) continue;
|
|
81
|
+
function anyChanged() {
|
|
82
|
+
for (let i = 0; i < newInfos.length; i++) {
|
|
83
|
+
if (
|
|
84
|
+
newInfos[i].path !== infos[i].path ||
|
|
85
|
+
newInfos[i].createTime !== infos[i].createTime ||
|
|
86
|
+
newInfos[i].size !== infos[i].size
|
|
87
|
+
) {
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (!anyChanged()) break;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (needsUpdate && valuesCache.size === 0) {
|
|
96
|
+
throw new Error(`Failed to get consistent snapshot of values after ${maxRetries} attempts`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return Array.from(valuesCache.values()).map(cached =>
|
|
101
|
+
JSON.parse(cached.value.toString()) as T
|
|
102
|
+
);
|
|
40
103
|
}
|
|
41
104
|
async function entries(): Promise<[string, T][]> {
|
|
42
105
|
let keysArray = await keys();
|
|
@@ -29,6 +29,7 @@ import { PromiseObj } from "../promise";
|
|
|
29
29
|
import { ClientWatcher } from "../1-path-client/pathValueClientWatcher";
|
|
30
30
|
import { auditLog, isDebugLogEnabled } from "./auditLogs";
|
|
31
31
|
import { logDisk } from "../diagnostics/logs/diskLogger";
|
|
32
|
+
import { isDiskAudit } from "../config";
|
|
32
33
|
|
|
33
34
|
|
|
34
35
|
let yargObj = isNodeTrue() && yargs(process.argv)
|
|
@@ -1341,6 +1342,12 @@ class PathWatcher {
|
|
|
1341
1342
|
if (!obj) continue;
|
|
1342
1343
|
obj.watchers.delete(callback);
|
|
1343
1344
|
|
|
1345
|
+
if (isOwnNodeId(callback)) {
|
|
1346
|
+
auditLog("local UNWATCH PARENT", { path });
|
|
1347
|
+
} else {
|
|
1348
|
+
auditLog("non-local UNWATCH PARENT", { path, watcher: callback });
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1344
1351
|
if (obj.watchers.size === 0) {
|
|
1345
1352
|
watchersObj.delete(path);
|
|
1346
1353
|
this.parentWatchers.delete(path);
|
|
@@ -1372,6 +1379,13 @@ class PathWatcher {
|
|
|
1372
1379
|
let watchers = this.watchers.get(path);
|
|
1373
1380
|
if (!watchers) continue;
|
|
1374
1381
|
watchers.watchers.delete(callback);
|
|
1382
|
+
|
|
1383
|
+
if (isOwnNodeId(callback)) {
|
|
1384
|
+
auditLog("local UNWATCH", { path });
|
|
1385
|
+
} else {
|
|
1386
|
+
auditLog("non-local UNWATCH", { path, watcher: callback });
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1375
1389
|
if (watchers.watchers.size === 0) {
|
|
1376
1390
|
this.watchers.delete(path);
|
|
1377
1391
|
|
|
@@ -1555,6 +1569,11 @@ class PathWatcher {
|
|
|
1555
1569
|
callback(changes, parentPaths ?? []);
|
|
1556
1570
|
}
|
|
1557
1571
|
} else {
|
|
1572
|
+
if (isDiskAudit()) {
|
|
1573
|
+
for (let change of changes) {
|
|
1574
|
+
auditLog("non-local TRIGGER", { path: change.path, time: change.time.time, watcher });
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
1558
1577
|
if (!isCoreQuiet) {
|
|
1559
1578
|
console.log(`(${Date.now()}) Sending values to client: ${changes.length} (${watcher})`);
|
|
1560
1579
|
}
|
|
@@ -1570,7 +1589,7 @@ class PathWatcher {
|
|
|
1570
1589
|
if (isDebugLogEnabled()) {
|
|
1571
1590
|
for (let pathValue of changes) {
|
|
1572
1591
|
|
|
1573
|
-
auditLog("SEND VALUE", { path: pathValue.path, time: pathValue.time.time, nodeId: debugNodeId(watcher), transparent: pathValue.isTransparent, canGC: pathValue.canGCValue });
|
|
1592
|
+
auditLog("SEND VALUE", { path: pathValue.path, time: pathValue.time.time, watcher, nodeId: debugNodeId(watcher), transparent: pathValue.isTransparent, canGC: pathValue.canGCValue });
|
|
1574
1593
|
}
|
|
1575
1594
|
}
|
|
1576
1595
|
await PathValueController.nodes[watcher].forwardWrites(
|
|
@@ -44,7 +44,7 @@ let formatters: { [formatter in StringFormatters]: (value: unknown) => preact.Co
|
|
|
44
44
|
number: (value) => d(value, formatNumber(Number(value))),
|
|
45
45
|
percent: (value) => d(value, formatPercent(Number(value))),
|
|
46
46
|
timeSpan: (value) => d(value, formatTime(Number(value))),
|
|
47
|
-
date: (value) => d(value, <span title={formatDateTimeDetailed(Number(value))}>{
|
|
47
|
+
date: (value) => d(value, <span title={formatDateTimeDetailed(Number(value))}>{formatDateTime(Number(value))}</span>),
|
|
48
48
|
error: (value) => d(value, <span class={errorMessage}>{String(value)}</span>),
|
|
49
49
|
toSpaceCase: (value) => d(value, toSpaceCase(String(value))),
|
|
50
50
|
"<Selector>": (value) => d(value, <Selector {...JSON.parse(String(value).slice("<Selector>".length))} />),
|
|
@@ -92,11 +92,10 @@ export class MachinesListPage extends qreact.Component {
|
|
|
92
92
|
this.state.isDeleteMode = false;
|
|
93
93
|
this.state.isDeleting = false;
|
|
94
94
|
});
|
|
95
|
-
}
|
|
95
|
+
} finally {
|
|
96
96
|
Querysub.commit(() => {
|
|
97
97
|
this.state.isDeleting = false;
|
|
98
98
|
});
|
|
99
|
-
alert(`Failed to delete machines: ${error instanceof Error ? error.message : String(error)}`);
|
|
100
99
|
}
|
|
101
100
|
});
|
|
102
101
|
}}>
|
|
@@ -334,8 +334,13 @@ export class BufferIndex {
|
|
|
334
334
|
results.totalBlockCount += indexEntries.length;
|
|
335
335
|
results.localBlockCount += indexEntries.length;
|
|
336
336
|
|
|
337
|
-
// Iterate
|
|
338
|
-
|
|
337
|
+
// Iterate based on search direction
|
|
338
|
+
const iterateForward = !!params.searchFromStart;
|
|
339
|
+
const startIdx = iterateForward ? 0 : indexEntries.length - 1;
|
|
340
|
+
const endIdx = iterateForward ? indexEntries.length : -1;
|
|
341
|
+
const step = iterateForward ? 1 : -1;
|
|
342
|
+
|
|
343
|
+
for (let i = startIdx; iterateForward ? i < endIdx : i > endIdx; i += step) {
|
|
339
344
|
if (matchCount >= params.limit || !config.keepIterating()) break;
|
|
340
345
|
await config.results.limitGroup?.wait();
|
|
341
346
|
const blockIndex = i;
|
|
@@ -380,7 +385,11 @@ export class BufferIndex {
|
|
|
380
385
|
results.localBlockCheckedCount++;
|
|
381
386
|
|
|
382
387
|
// Scan all buffers in this block
|
|
383
|
-
|
|
388
|
+
const bufferStartIdx = iterateForward ? 0 : buffers.length - 1;
|
|
389
|
+
const bufferEndIdx = iterateForward ? buffers.length : -1;
|
|
390
|
+
const bufferStep = iterateForward ? 1 : -1;
|
|
391
|
+
|
|
392
|
+
for (let bufferIndex = bufferStartIdx; iterateForward ? bufferIndex < bufferEndIdx : bufferIndex > bufferEndIdx; bufferIndex += bufferStep) {
|
|
384
393
|
if (matchCount >= params.limit || !config.keepIterating()) break;
|
|
385
394
|
await config.results.limitGroup?.wait();
|
|
386
395
|
|
|
@@ -4,7 +4,7 @@ import { formatNumber, formatPercent } from "socket-function/src/formatting/form
|
|
|
4
4
|
import { red } from "socket-function/src/formatting/logColors";
|
|
5
5
|
import { MaybePromise } from "socket-function/src/types";
|
|
6
6
|
import { TimeFilePathWithSize } from "./IndexedLogs";
|
|
7
|
-
import {
|
|
7
|
+
import { ThrottleGroup } from "../../../functional/throttleProcessing";
|
|
8
8
|
|
|
9
9
|
export const INDEX_EXTENSION = ".index";
|
|
10
10
|
|
|
@@ -17,6 +17,7 @@ export type SearchParams = {
|
|
|
17
17
|
pathOverrides?: TimeFilePathWithSize[];
|
|
18
18
|
only?: "local" | "public";
|
|
19
19
|
forceReadProduction?: boolean;
|
|
20
|
+
searchFromStart?: boolean;
|
|
20
21
|
};
|
|
21
22
|
|
|
22
23
|
export type Unit = number;
|
|
@@ -130,6 +131,8 @@ export type IndexedLogResults = {
|
|
|
130
131
|
totalBackblazeFiles: number;
|
|
131
132
|
localFilesSearched: number;
|
|
132
133
|
backblazeFilesSearched: number;
|
|
134
|
+
totalBackblazeLogs: number;
|
|
135
|
+
backblazeLogsSearched: number;
|
|
133
136
|
|
|
134
137
|
totalBlockCount: number;
|
|
135
138
|
blockCheckedCount: number;
|
|
@@ -158,11 +161,11 @@ export type IndexedLogResults = {
|
|
|
158
161
|
totalSearchTime: number;
|
|
159
162
|
|
|
160
163
|
cancel?: boolean;
|
|
161
|
-
limitGroup?:
|
|
164
|
+
limitGroup?: ThrottleGroup;
|
|
162
165
|
};
|
|
163
166
|
export function createEmptyIndexedLogResults(): IndexedLogResults {
|
|
164
167
|
return {
|
|
165
|
-
matchCount: 0, reads: [], totalLocalFiles: 0, totalBackblazeFiles: 0, localFilesSearched: 0, backblazeFilesSearched: 0, totalBlockCount: 0, blockCheckedCount: 0, remoteBlockCount: 0, localBlockCount: 0, remoteBlockCheckedCount: 0, localBlockCheckedCount: 0, blocksCheckedCompressedSize: 0, blocksCheckedDecompressedSize: 0, blockErrors: [], fileErrors: [], remoteIndexesSearched: 0, remoteIndexSize: 0, localIndexesSearched: 0, localIndexSize: 0, timeToFirstMatch: -1, fileFindTime: 0, indexSearchTime: 0, blockSearchTime: 0, totalSearchTime: 0, cancel: undefined, limitGroup: undefined,
|
|
168
|
+
matchCount: 0, reads: [], totalLocalFiles: 0, totalBackblazeFiles: 0, localFilesSearched: 0, backblazeFilesSearched: 0, totalBackblazeLogs: 0, backblazeLogsSearched: 0, totalBlockCount: 0, blockCheckedCount: 0, remoteBlockCount: 0, localBlockCount: 0, remoteBlockCheckedCount: 0, localBlockCheckedCount: 0, blocksCheckedCompressedSize: 0, blocksCheckedDecompressedSize: 0, blockErrors: [], fileErrors: [], remoteIndexesSearched: 0, remoteIndexSize: 0, localIndexesSearched: 0, localIndexSize: 0, timeToFirstMatch: -1, fileFindTime: 0, indexSearchTime: 0, blockSearchTime: 0, totalSearchTime: 0, cancel: undefined, limitGroup: undefined,
|
|
166
169
|
};
|
|
167
170
|
}
|
|
168
171
|
|
|
@@ -202,6 +205,8 @@ export function mergeIndexedLogResults(existing: IndexedLogResults, incoming: In
|
|
|
202
205
|
reads: Array.from(readsByKey.values()),
|
|
203
206
|
localFilesSearched: existing.localFilesSearched + incoming.localFilesSearched,
|
|
204
207
|
backblazeFilesSearched: existing.backblazeFilesSearched + incoming.backblazeFilesSearched,
|
|
208
|
+
totalBackblazeLogs: existing.totalBackblazeLogs + incoming.totalBackblazeLogs,
|
|
209
|
+
backblazeLogsSearched: existing.backblazeLogsSearched + incoming.backblazeLogsSearched,
|
|
205
210
|
totalBlockCount: existing.totalBlockCount + incoming.totalBlockCount,
|
|
206
211
|
blockCheckedCount: existing.blockCheckedCount + incoming.blockCheckedCount,
|
|
207
212
|
blocksCheckedCompressedSize: existing.blocksCheckedCompressedSize + incoming.blocksCheckedCompressedSize,
|
|
@@ -381,7 +381,7 @@ export class BufferUnitIndex {
|
|
|
381
381
|
}
|
|
382
382
|
}, `buildHashTableWithLinkedLists`);
|
|
383
383
|
|
|
384
|
-
console.log(`Hash table filled slots: ${filledSlots} / ${hashTableCapacity} (${formatPercent(filledSlots / hashTableCapacity)} utilization)`);
|
|
384
|
+
console.log(`Hash table filled slots: ${filledSlots} / ${hashTableCapacity} (${formatPercent(filledSlots / hashTableCapacity)} utilization, higher means hash function is good, and no probing is used, so 100% is fine)`);
|
|
385
385
|
|
|
386
386
|
// Step 5: Flatten linked lists and encode to binary
|
|
387
387
|
// Build data section and hash table by traversing linked lists
|
|
@@ -532,13 +532,19 @@ export class BufferUnitIndex {
|
|
|
532
532
|
|
|
533
533
|
const searchBlock = async (blockIndex: number) => {
|
|
534
534
|
if (!candidateBlocksSet.has(blockIndex)) return;
|
|
535
|
-
//
|
|
535
|
+
// Check if we should stop iterating based on match counts and direction
|
|
536
536
|
let stopIterating = () => {
|
|
537
|
-
let
|
|
538
|
-
|
|
539
|
-
|
|
537
|
+
let relevantCount = 0;
|
|
538
|
+
if (params.searchFromStart) {
|
|
539
|
+
for (let i = 0; i <= blockIndex; i++) {
|
|
540
|
+
relevantCount += matchCounts[i];
|
|
541
|
+
}
|
|
542
|
+
} else {
|
|
543
|
+
for (let i = blockIndex; i < blockCount; i++) {
|
|
544
|
+
relevantCount += matchCounts[i];
|
|
545
|
+
}
|
|
540
546
|
}
|
|
541
|
-
return
|
|
547
|
+
return relevantCount >= params.limit || !keepIterating();
|
|
542
548
|
};
|
|
543
549
|
if (stopIterating()) return;
|
|
544
550
|
|
|
@@ -561,7 +567,12 @@ export class BufferUnitIndex {
|
|
|
561
567
|
let bufferCount = await this.getBufferCountFromBlock(blockReader);
|
|
562
568
|
|
|
563
569
|
// Check each buffer for a match
|
|
564
|
-
|
|
570
|
+
const iterateForward = !!params.searchFromStart;
|
|
571
|
+
const startIdx = iterateForward ? 0 : bufferCount - 1;
|
|
572
|
+
const endIdx = iterateForward ? bufferCount : -1;
|
|
573
|
+
const step = iterateForward ? 1 : -1;
|
|
574
|
+
|
|
575
|
+
for (let i = startIdx; iterateForward ? i < endIdx : i > endIdx; i += step) {
|
|
565
576
|
if (stopIterating()) break;
|
|
566
577
|
await results.limitGroup?.wait();
|
|
567
578
|
|
|
@@ -582,9 +593,13 @@ export class BufferUnitIndex {
|
|
|
582
593
|
{ parallelCount: BufferUnitIndexParallelSearchCount },
|
|
583
594
|
searchBlock
|
|
584
595
|
);
|
|
585
|
-
//
|
|
596
|
+
// Sort blocks by search direction
|
|
586
597
|
let searchOrder = Array.from(candidateBlocksSet);
|
|
587
|
-
|
|
598
|
+
if (params.searchFromStart) {
|
|
599
|
+
sort(searchOrder, x => x);
|
|
600
|
+
} else {
|
|
601
|
+
sort(searchOrder, x => -x);
|
|
602
|
+
}
|
|
588
603
|
await Promise.all(searchOrder.map(runSearchBlock));
|
|
589
604
|
|
|
590
605
|
}, `searchBlocks`);
|
|
@@ -19,8 +19,14 @@ export class FindProgressTracker<T> {
|
|
|
19
19
|
if (time < this.config.params.startTime) return false;
|
|
20
20
|
if (time >= this.config.params.endTime) return false;
|
|
21
21
|
|
|
22
|
-
if (this.
|
|
23
|
-
|
|
22
|
+
if (this.config.params.searchFromStart) {
|
|
23
|
+
if (this.results.length >= this.config.params.limit && time > this.results[this.results.length - 1].time) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
} else {
|
|
27
|
+
if (this.results.length >= this.config.params.limit && time < this.results[0].time) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
24
30
|
}
|
|
25
31
|
|
|
26
32
|
let newObj = { time, result };
|
|
@@ -29,7 +35,11 @@ export class FindProgressTracker<T> {
|
|
|
29
35
|
this.results.splice(index, 0, newObj);
|
|
30
36
|
|
|
31
37
|
if (this.results.length > this.config.params.limit) {
|
|
32
|
-
|
|
38
|
+
if (this.config.params.searchFromStart) {
|
|
39
|
+
this.results = this.results.slice(0, this.config.params.limit);
|
|
40
|
+
} else {
|
|
41
|
+
this.results = this.results.slice(-this.config.params.limit);
|
|
42
|
+
}
|
|
33
43
|
}
|
|
34
44
|
|
|
35
45
|
this.config.onResult(result);
|
|
@@ -37,8 +47,14 @@ export class FindProgressTracker<T> {
|
|
|
37
47
|
}
|
|
38
48
|
|
|
39
49
|
public isSourceRelevant(source: { startTime: number; endTime: number; }): boolean {
|
|
40
|
-
if (this.
|
|
41
|
-
|
|
50
|
+
if (this.config.params.searchFromStart) {
|
|
51
|
+
if (this.results.length >= this.config.params.limit && source.startTime > this.results[this.results.length - 1].time) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
} else {
|
|
55
|
+
if (this.results.length >= this.config.params.limit && source.endTime < this.results[0].time) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
42
58
|
}
|
|
43
59
|
return source.startTime <= this.config.params.endTime && source.endTime >= this.config.params.startTime;
|
|
44
60
|
}
|
|
@@ -22,7 +22,7 @@ import { SocketFunction } from "socket-function/SocketFunction";
|
|
|
22
22
|
import { assertIsManagementUser } from "../../managementPages";
|
|
23
23
|
import { ignoreErrors } from "../../../errors";
|
|
24
24
|
import { blue } from "socket-function/src/formatting/logColors";
|
|
25
|
-
import {
|
|
25
|
+
import { ThrottleGroup } from "../../../functional/throttleProcessing";
|
|
26
26
|
import { getAllNodeIds } from "../../../-f-node-discovery/NodeDiscovery";
|
|
27
27
|
import { NodeCapabilitiesController } from "../../../-g-core-values/NodeCapabilities";
|
|
28
28
|
import { getLoggers2Async } from "../diskLogger";
|
|
@@ -427,7 +427,7 @@ export class IndexedLogs<T> {
|
|
|
427
427
|
allResults.set("", results);
|
|
428
428
|
|
|
429
429
|
|
|
430
|
-
results.limitGroup = new
|
|
430
|
+
results.limitGroup = new ThrottleGroup({
|
|
431
431
|
maxTimePerBeforeWait: 500,
|
|
432
432
|
waitTime: 250,
|
|
433
433
|
});
|
|
@@ -518,14 +518,19 @@ export class IndexedLogs<T> {
|
|
|
518
518
|
}
|
|
519
519
|
fileFindTime = Date.now() - fileFindTime;
|
|
520
520
|
|
|
521
|
-
//
|
|
522
|
-
|
|
521
|
+
// Sort by time based on search direction
|
|
522
|
+
if (config.params.searchFromStart) {
|
|
523
|
+
sort(paths, x => x.startTime);
|
|
524
|
+
} else {
|
|
525
|
+
sort(paths, x => - x.startTime);
|
|
526
|
+
}
|
|
523
527
|
|
|
524
528
|
let results = config.results;
|
|
525
529
|
let localPaths = paths.filter(x => x.logCount === undefined);
|
|
526
530
|
let remotePaths = paths.filter(x => x.logCount !== undefined);
|
|
527
531
|
results.totalLocalFiles = localPaths.length;
|
|
528
532
|
results.totalBackblazeFiles = remotePaths.length;
|
|
533
|
+
results.totalBackblazeLogs = remotePaths.reduce((sum, x) => sum + (x.logCount ?? 0), 0);
|
|
529
534
|
results.fileFindTime = fileFindTime;
|
|
530
535
|
|
|
531
536
|
let progressTracker = new FindProgressTracker<T>({
|
|
@@ -551,6 +556,7 @@ export class IndexedLogs<T> {
|
|
|
551
556
|
let archives = remote ? backblazeLogs : localLogs;
|
|
552
557
|
if (remote) {
|
|
553
558
|
results.backblazeFilesSearched++;
|
|
559
|
+
results.backblazeLogsSearched += path.logCount ?? 0;
|
|
554
560
|
} else {
|
|
555
561
|
results.localFilesSearched++;
|
|
556
562
|
}
|