querysub 0.398.0 → 0.399.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "querysub",
3
- "version": "0.398.0",
3
+ "version": "0.399.0",
4
4
  "main": "index.js",
5
5
  "license": "MIT",
6
6
  "note1": "note on node-forge fork, see https://github.com/digitalbazaar/forge/issues/744 for details",
@@ -517,7 +517,7 @@ export class ArchivesBackblaze {
517
517
 
518
518
  // If it's a 503 and it's been a minute since we last reset, then Wait and reset.
519
519
  if (
520
- (err.stack.includes(`503`)
520
+ (err.stack.includes(`"status": 503`)
521
521
  || err.stack.includes(`"service_unavailable"`)
522
522
  || err.stack.includes(`"internal_error"`)
523
523
  || err.stack.includes(`ENOBUFS`)
@@ -1,4 +1,4 @@
1
- import { list, sort, timeInDay, timeInHour, timeInMinute } from "socket-function/src/misc";
1
+ import { list, sort, timeInDay, timeInHour, timeInMinute, timeInSecond } from "socket-function/src/misc";
2
2
  import { MaybePromise } from "socket-function/src/types";
3
3
  import { decodeNodeId } from "../../-a-auth/certs";
4
4
  import { getOwnNodeId, getOwnNodeIdAssert } from "../../-f-node-discovery/NodeDiscovery";
@@ -18,7 +18,7 @@ import { logDisk } from "../../diagnostics/logs/diskLogger";
18
18
 
19
19
  /** Clean up old files after a while */
20
20
  const DEAD_CREATE_THRESHOLD = timeInHour * 12;
21
- const ARCHIVE_PROPAGATION_TIME = 5000;
21
+ const ARCHIVE_PROPAGATION_TIME = timeInSecond * 5;
22
22
  // NOTE: There isn't a reason for transaction to not apply. If applying throws, we throw,
23
23
  // and can throw infinite times, but if it doesn't throw, it SHOULD be applied. We retry
24
24
  // a few times though, just in case the storage system was having some issues. After enough
@@ -374,6 +374,7 @@ class TransactionLocker {
374
374
  }
375
375
 
376
376
  private lastFilesRead: FileInfo[] | undefined;
377
+ private lastFilesReadTime: number | undefined;
377
378
  private async readDataState(): Promise<{
378
379
  rawDataFiles: FileInfo[];
379
380
  /** Confirmed FileInfos are === the FileInfos in rawDataFiles */
@@ -387,14 +388,15 @@ class TransactionLocker {
387
388
  }> {
388
389
  let bufferCache = new Map<string, Buffer>();
389
390
  const tryToRead = async () => {
391
+ let time = Date.now();
390
392
  let files = await this.storage.getKeys();
391
- if (this.lastFilesRead) {
393
+ if (this.lastFilesRead && this.lastFilesReadTime) {
392
394
  let prevFiles = new Set(this.lastFilesRead.map(a => a.file));
395
+ let suspiciousThreshold = this.lastFilesReadTime - ARCHIVE_PROPAGATION_TIME * 10;
393
396
  let newFiles = files.filter(a => !prevFiles.has(a.file));
394
- let pastTime = Date.now() - ARCHIVE_PROPAGATION_TIME * 10;
395
- let veryBadFiles = newFiles.filter(x => x.createTime < pastTime);
397
+ let veryBadFiles = newFiles.filter(x => x.createTime < suspiciousThreshold);
396
398
  if (veryBadFiles.length > 0) {
397
- console.error(`Old files suddenly appeared. This isn't possible, if they are old, they should have appeared when they were created! This likely means that our getKeys() failed to actually read all of the files. This is bad and can result in us deleting seemingly broken files for missing a confirmation, when they in fact had a confirmation.`, {
399
+ console.error(`Old read was not exhaustive, because we just found files which existed well before it, but that it did not read. This likely means our propagation assumptions are wrong, and propagation is much slower than anticipated. OR, getKeys is flakey and randomly misses files? Either way, this will BREAK THE DATABASE! Any node experiencing this might start deleting valid database files, which is very bad!`, {
398
400
  newlyAppearingOldFiles: veryBadFiles.map(x => x.file),
399
401
  prevFiles: this.lastFilesRead.map(x => x.file),
400
402
  newFiles: files.map(x => x.file),
@@ -402,6 +404,7 @@ class TransactionLocker {
402
404
  }
403
405
  }
404
406
  this.lastFilesRead = files;
407
+ this.lastFilesReadTime = time;
405
408
 
406
409
  let transactions: (Transaction & {
407
410
  seqNum: number;
@@ -980,7 +980,6 @@ class AuthorityPathValueStorage {
980
980
  if (!isCoreQuiet) {
981
981
  console.log(`GCing everything older than ${debugPathValuePath(values[0])}`);
982
982
  for (let value of removed) {
983
- console.log(` ${debugPathValuePath(value)}`);
984
983
  auditLog("GCing", { path: value.path });
985
984
  }
986
985
  }
@@ -990,7 +989,6 @@ class AuthorityPathValueStorage {
990
989
  for (let i = values.length - 1; i > firstGoldenIndex; i--) {
991
990
  let gced = values.pop();
992
991
  if (!isCoreQuiet && gced) {
993
- console.log(`GCing ${debugPathValuePath(gced)}`);
994
992
  auditLog("GCing", { path: gced.path });
995
993
  }
996
994
  }
@@ -1935,21 +1933,22 @@ class WriteValidStorage {
1935
1933
  debugger;
1936
1934
  }
1937
1935
  let timeToReject = now - valueGroup[0].time.time;
1938
- console.log(red(`!!! VALUE REJECTED DUE TO USING MISSING / REJECTED READ!!!(rejected after ${timeToReject}ms at ${Date.now()})`));
1939
- console.log(red(`${debugTime(valueGroup[0].time)} (write)`));
1940
- console.log(red(` rejected as the server could not find: `));
1936
+ let message = `!!! VALUE REJECTED DUE TO USING MISSING / REJECTED READ!!!(rejected after ${timeToReject}ms at ${Date.now()})`;
1937
+ message += `\n${debugTime(valueGroup[0].time)} (write)`;
1938
+ message += `\n rejected as the server could not find: `;
1941
1939
  if (lock.readIsTransparent) {
1942
- console.log(red(`${debugTime(lock.startTime)} to ${debugTime(lock.endTime)} ${getPathFromStr(lock.path).join(".")} `));
1940
+ message += `\n${debugTime(lock.startTime)} to ${debugTime(lock.endTime)} ${getPathFromStr(lock.path).join(".")} `;
1943
1941
  } else {
1944
- console.log(red(`${debugTime(lock.startTime)} ${getPathFromStr(lock.path).join(".")} `));
1942
+ message += `\n${debugTime(lock.startTime)} ${getPathFromStr(lock.path).join(".")} `;
1945
1943
  }
1946
1944
  if (lock.readIsTransparent) {
1947
- console.log(red(` (read was undefined, so presumably a value exists which the writer missed)`));
1945
+ message += `\n (read was undefined, so presumably a value exists which the writer missed)`;
1948
1946
  }
1949
- console.log(yellow(`Full list of writes rejected: `));
1947
+ message += `\nFull list of writes rejected: `;
1950
1948
  for (let pathValue of valueGroup) {
1951
- console.log(yellow(debugPathValue(pathValue)));
1949
+ message += `\n${debugPathValue(pathValue)}`;
1952
1950
  }
1951
+ console.log(red(message));
1953
1952
 
1954
1953
  if (debugRejections) {
1955
1954
  debugbreak(2);
@@ -1978,17 +1977,18 @@ class WriteValidStorage {
1978
1977
  let changed = valueGroup.filter(x => x.valid);
1979
1978
  if (changed.length > 0) {
1980
1979
  let timeToReject = now - changed[0].time.time;
1981
- console.log(red(`!!! LOCK CONTENTION FIXED VIA REJECTION OF VALUE!!!(rejected after ${timeToReject}ms)`));
1980
+ let redMessage = `!!! LOCK CONTENTION FIXED VIA REJECTION OF VALUE!!!(rejected after ${timeToReject}ms)`;
1982
1981
  for (let pathValue of changed) {
1983
- console.log(red(debugPathValue(pathValue)));
1982
+ redMessage += `\n${debugPathValue(pathValue)}`;
1984
1983
  }
1985
- console.log(red(` (write rejected due to original read not noticing value at: ${lock.path})`));
1986
- console.log(red(` (original read from: ${debugTime(lock.startTime)}`));
1987
- console.log(red(` (at time: ${debugTime(lock.endTime)}`));
1988
- console.log(red(` (current time: ${Date.now()})`));
1984
+ redMessage += `\n (write rejected due to original read not noticing value at: ${lock.path})`;
1985
+ redMessage += `\n (original read from: ${debugTime(lock.startTime)}`;
1986
+ redMessage += `\n (at time: ${debugTime(lock.endTime)}`;
1987
+ redMessage += `\n (current time: ${Date.now()})`;
1989
1988
  for (let lockFailed of inRange) {
1990
- console.log(red(` (conflict write at: ${debugTime(lockFailed.time)}`));
1989
+ redMessage += `\n (conflict write at: ${debugTime(lockFailed.time)}`;
1991
1990
  }
1991
+ console.log(red(redMessage));
1992
1992
  if (debugRejections) {
1993
1993
  debugbreak(2);
1994
1994
  debugger;
@@ -593,10 +593,10 @@ const ensureGitSynced = measureWrap(async function ensureGitSynced(config: {
593
593
  repoUrl: string;
594
594
  gitRef: string;
595
595
  }) {
596
- if (!await fsExistsAsync(config.gitFolder + ".git")) {
597
- await runPromise(`git clone ${config.repoUrl} ${config.gitFolder}`);
598
- }
599
596
  try {
597
+ if (!await fsExistsAsync(config.gitFolder + ".git")) {
598
+ await runPromise(`git clone ${config.repoUrl} ${config.gitFolder}`);
599
+ }
600
600
  await setGitRef(config);
601
601
  } catch (e: any) {
602
602
  console.warn(`Failed to set git ref, trying to delete and clone again (${config.gitFolder}): ${e.stack}`);
@@ -419,14 +419,26 @@ export class BufferIndex {
419
419
  keepIterating: () => boolean;
420
420
  onResult: (match: Buffer) => void;
421
421
  results: IndexedLogResults;
422
- }): Promise<void> {
422
+ }): Promise<{
423
+ blockSearchTime: number;
424
+ indexSearchTime: number;
425
+ }> {
423
426
  let { index, dataReader, params, results } = config;
427
+ let startTime = Date.now();
428
+ let indexEndTime = startTime;
429
+ function createResult() {
430
+ let endTime = Date.now();
431
+ return {
432
+ indexSearchTime: indexEndTime - startTime,
433
+ blockSearchTime: endTime - indexEndTime,
434
+ };
435
+ }
424
436
 
425
437
  const matchesPattern = createMatchesPattern(params.findBuffer, !!params.disableWildCards);
426
438
 
427
439
  let allSearchUnits = getSearchUnits(params.findBuffer, !!params.disableWildCards);
428
440
  if (allSearchUnits.length === 0) {
429
- return;
441
+ return createResult();
430
442
  }
431
443
 
432
444
  let type = index[0];
@@ -441,12 +453,13 @@ export class BufferIndex {
441
453
  if (index.length === 0) {
442
454
  index = await BufferIndex.rebuildLocalIndexFromData(dataReader);
443
455
  if (index.length === 0) {
444
- return;
456
+ return createResult();
445
457
  }
446
458
  }
447
459
 
448
460
  // Fix partial index before processing
449
461
  index = await BufferIndex.fixPartialIndex({ index, dataReader, results });
462
+ indexEndTime = Date.now();
450
463
 
451
464
  await BufferIndex.findLocal({ index, dataReader, params, keepIterating: config.keepIterating, onResult: config.onResult, results, allSearchUnits, matchesPattern });
452
465
  } else if (type === BULK_TYPE) {
@@ -465,9 +478,11 @@ export class BufferIndex {
465
478
  let dataLength = await dataReader.getLength();
466
479
  if (dataLength < 32) {
467
480
  // If it's a small file, nothing of value will be lost by ignoring it. And almost all of our errors are coming from extremely small files.
468
- return;
481
+ return createResult();
469
482
  }
470
483
  throw new Error(`Unknown type in index file: ${type}`);
471
484
  }
485
+
486
+ return createResult();
472
487
  }
473
488
  }
@@ -134,6 +134,8 @@ export type IndexedLogResults = {
134
134
  totalBackblazeLogs: number;
135
135
  backblazeLogsSearched: number;
136
136
 
137
+ backblazeUncompressedSize: number;
138
+
137
139
  totalBlockCount: number;
138
140
  blockCheckedCount: number;
139
141
 
@@ -165,7 +167,7 @@ export type IndexedLogResults = {
165
167
  };
166
168
  export function createEmptyIndexedLogResults(): IndexedLogResults {
167
169
  return {
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,
170
+ 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, backblazeUncompressedSize: 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,
169
171
  };
170
172
  }
171
173
 
@@ -211,6 +213,7 @@ export function mergeIndexedLogResults(existing: IndexedLogResults, incoming: In
211
213
  blockCheckedCount: existing.blockCheckedCount + incoming.blockCheckedCount,
212
214
  blocksCheckedCompressedSize: existing.blocksCheckedCompressedSize + incoming.blocksCheckedCompressedSize,
213
215
  blocksCheckedDecompressedSize: existing.blocksCheckedDecompressedSize + incoming.blocksCheckedDecompressedSize,
216
+ backblazeUncompressedSize: existing.backblazeUncompressedSize + incoming.backblazeUncompressedSize,
214
217
  blockErrors: [...existing.blockErrors, ...incoming.blockErrors],
215
218
  fileErrors: [...existing.fileErrors, ...incoming.fileErrors],
216
219
  remoteIndexesSearched: existing.remoteIndexesSearched + incoming.remoteIndexesSearched,
@@ -1,7 +1,9 @@
1
1
  import { timeInHour, timeInMinute, timeInSecond } from "socket-function/src/misc";
2
2
 
3
3
  // NOTE: This is the block size BEFORE compression. The actual download size is probably going to be around 1/20th of this.
4
- export const DEFAULT_BLOCK_SIZE = 1024 * 1024;
4
+ // BUT, This is also going to be the amount of data we need to scan generally per result, as the results are often, at least in the cases that we're optimizing for, spread out over many files.
5
+ // NOTE: This used to be 1024 * 1024, which in practice seemed to give us about a 170X factor from the full data to the index size. If this change to 1024 * 256 moves it below a 100X factor we should increase the size again (small block sizes mean more blocks, which means the index file has to store more data, making it less efficient).
6
+ export const DEFAULT_BLOCK_SIZE = 1024 * 256;
5
7
  export const DEFAULT_TARGET_UNITS_PER_BUCKET = 16;
6
8
 
7
9
  // Worst case scenario, the logs the user wants are very spread out, in which case having too high of a threshold will require decoding more data (the threshold amount per result).
@@ -512,7 +512,11 @@ export class BufferUnitIndex {
512
512
  }): Promise<void> {
513
513
  const { params, index, reader, keepIterating, results, allSearchUnits } = config;
514
514
 
515
+ let indexTime = Date.now();
515
516
  let candidateBlocksList = allSearchUnits.map(units => this.findBlocks({ units, index })).flat();
517
+ indexTime = Date.now() - indexTime;
518
+ results.indexSearchTime += indexTime;
519
+ results.blockSearchTime -= indexTime;
516
520
  let candidateBlocksSet = new Set(candidateBlocksList);
517
521
 
518
522
 
@@ -10,7 +10,7 @@ import { getArchivesBackblaze, getArchivesBackblazePrivateImmutable } from "../.
10
10
  import { getMachineId, getOwnThreadId } from "../../../-a-auth/certs";
11
11
  import { ArchivesMemoryCacheStats, createArchivesMemoryCache } from "../../../-a-archives/archivesMemoryCache";
12
12
  import { registerShutdownHandler } from "../../periodic";
13
- import { measureBlock, measureFnc } from "socket-function/src/profiling/measure";
13
+ import { measureBlock, measureFnc, measureWrap } from "socket-function/src/profiling/measure";
14
14
  import { isNode } from "typesafecss";
15
15
  import { getOwnMachineId, isNodeIdOnOwnMachineId, isOwnNodeId } from "../../../-f-node-discovery/NodeDiscovery";
16
16
  import { TimeFilePath, TimeFileTree } from "./TimeFileTree";
@@ -27,7 +27,8 @@ import { getAllNodeIds } from "../../../-f-node-discovery/NodeDiscovery";
27
27
  import { NodeCapabilitiesController } from "../../../-g-core-values/NodeCapabilities";
28
28
  import { getLoggers2Async } from "../diskLogger";
29
29
  import { watchAllValues } from "../errorNotifications2/logWatcher";
30
- //
30
+
31
+ // Ensure it's available so that the controller is listening on all servers
31
32
  watchAllValues;
32
33
 
33
34
  export type TimeFilePathWithSize = TimeFilePath & {
@@ -92,11 +93,11 @@ export class IndexedLogs<T> {
92
93
  });
93
94
  return archives;
94
95
  });
95
- private getPublicLogs = lazy((): Archives => {
96
+ private getPublicLogsBase(loadPublic: boolean): Archives {
96
97
  let basePublic: Archives = getArchivesHome(getDomain());
97
98
  // NOTE: The local disk is so fast that reading in 10 megabytes is nothing, And if we read in too small of a value, the overhead per read ends up making this take forever.
98
99
  let extraReadSize = 1024 * 1024 * 10;
99
- if (isPublic()) {
100
+ if (loadPublic) {
100
101
  basePublic = getArchivesBackblaze(getDomain());
101
102
  // NOTE: While the latency to back plays is high, now we're reading in parallel, so it shouldn't be as big of an issue.
102
103
  extraReadSize = 1024 * 1024 * 1;
@@ -111,6 +112,12 @@ export class IndexedLogs<T> {
111
112
  sizeCache: this.fileSizeCache,
112
113
  });
113
114
  return archives;
115
+ };
116
+ private getPublicLogs = lazy((): Archives => {
117
+ return this.getPublicLogsBase(isPublic());
118
+ });
119
+ private getRealPublicLogs = lazy((): Archives => {
120
+ return this.getPublicLogsBase(true);
114
121
  });
115
122
 
116
123
  private getTimeBlock(time: number): { startTime: number, endTime: number } {
@@ -374,7 +381,10 @@ export class IndexedLogs<T> {
374
381
  onResults?: (results: IndexedLogResults) => Promise<boolean>;
375
382
  }): Promise<IndexedLogResults> {
376
383
 
377
- if (config.params.forceReadProduction && !isPublic()) {
384
+ let { params } = config;
385
+ if (params.pathOverrides && config.params.only === "public") {
386
+ // Fine, if they provided path overrides, and they are all public, just read them, as they'll resolve the same no matter where we read from
387
+ } else if (config.params.forceReadProduction && !isPublic()) {
378
388
  let machineNodes = await this.getMachineNodes();
379
389
  if (machineNodes.length === 0) throw new Error(`Cannot find any public nodes to read from`);
380
390
  return await this.clientFind({
@@ -391,13 +401,14 @@ export class IndexedLogs<T> {
391
401
  for (let result of allResults.values()) {
392
402
  results = mergeIndexedLogResults(results, result);
393
403
  }
404
+
394
405
  return results;
395
406
  };
396
407
  let allResults = new Map<string, IndexedLogResults>();
397
408
  let allDone: Promise<void>[] = [];
398
409
 
399
410
  // Read other nodes if on a public server
400
- if (config.params.only !== "local" && isPublic()) {
411
+ if (config.params.only !== "public" && isPublic()) {
401
412
  let machineNodes = await this.getMachineNodes();
402
413
  allDone.push(...machineNodes.map(async (machineNode) => {
403
414
  try {
@@ -501,9 +512,13 @@ export class IndexedLogs<T> {
501
512
  onResult: (match: T) => void;
502
513
  results: IndexedLogResults;
503
514
  }): Promise<void> {
515
+ let results = config.results;
504
516
  let startTime = Date.now();
505
517
  let localLogs = this.getLocalLogs();
506
518
  let backblazeLogs = this.getPublicLogs();
519
+ if (!isPublic() && config.params.forceReadProduction) {
520
+ backblazeLogs = this.getRealPublicLogs();
521
+ }
507
522
 
508
523
  let fileFindTime = Date.now();
509
524
  let paths = config.params.pathOverrides ?? await this.getPaths({
@@ -518,6 +533,10 @@ export class IndexedLogs<T> {
518
533
  }
519
534
  fileFindTime = Date.now() - fileFindTime;
520
535
 
536
+ for (let path of paths) {
537
+ results.backblazeUncompressedSize += path.uncompressedSize ?? 0;
538
+ }
539
+
521
540
  // Sort by time based on search direction
522
541
  if (config.params.searchFromStart) {
523
542
  sort(paths, x => x.startTime);
@@ -525,7 +544,6 @@ export class IndexedLogs<T> {
525
544
  sort(paths, x => - x.startTime);
526
545
  }
527
546
 
528
- let results = config.results;
529
547
  let localPaths = paths.filter(x => x.logCount === undefined);
530
548
  let remotePaths = paths.filter(x => x.logCount !== undefined);
531
549
  results.totalLocalFiles = localPaths.length;
@@ -547,10 +565,10 @@ export class IndexedLogs<T> {
547
565
  });
548
566
 
549
567
 
550
- const searchPath = async (path: TimeFilePathWithSize) => {
568
+ const searchPath = measureWrap(async (path: TimeFilePathWithSize) => {
551
569
  if (!progressTracker.isSourceRelevant(path)) return;
552
570
  // Wait, so we don't lock up the main thread?
553
- await delay(0);
571
+ //await delay(0);
554
572
 
555
573
  let remote = path.logCount !== undefined;
556
574
  let archives = remote ? backblazeLogs : localLogs;
@@ -578,9 +596,7 @@ export class IndexedLogs<T> {
578
596
  return data;
579
597
  },
580
598
  };
581
- let totalSearchTime = Date.now();
582
- let blockSearchTimeBefore = results.blockSearchTime;
583
- await BufferIndex.find({
599
+ let timeResult = await BufferIndex.find({
584
600
  index,
585
601
  dataReader,
586
602
  params: {
@@ -594,22 +610,21 @@ export class IndexedLogs<T> {
594
610
  },
595
611
  results,
596
612
  });
597
- totalSearchTime = Date.now() - totalSearchTime;
598
- let blockSearchTimeAdded = results.blockSearchTime - blockSearchTimeBefore;
599
- results.indexSearchTime += totalSearchTime - blockSearchTimeAdded;
613
+ results.indexSearchTime += timeResult.indexSearchTime;
614
+ results.blockSearchTime += timeResult.blockSearchTime;
600
615
 
601
616
  } catch (e: any) {
602
617
  results.fileErrors.push({ error: String(e?.stack || e), path: path.fullPath });
603
618
  console.warn(`Error in reading log file ${path.fullPath} logs: ${e}`);
604
619
  }
605
- };
620
+ });
621
+
606
622
  let localDone = (async () => {
607
623
  for (let path of localPaths) {
608
624
  await searchPath(path);
609
625
  }
610
626
  })();
611
- // No parallel count when running locally, as running it in parallel makes timing more difficult.
612
- let parallelCount = isPublic() ? 32 : 1;
627
+ let parallelCount = 32;
613
628
  let remoteParallel = runInParallel({ parallelCount }, searchPath);
614
629
  await Promise.all(remotePaths.map(remoteParallel));
615
630
  await localDone;
@@ -38,7 +38,7 @@ import { startTimeParam, endTimeParam } from "../TimeRangeSelector";
38
38
  import { formatSearchString } from "./LogViewerParams";
39
39
 
40
40
  let excludePendingResults = new URLParam("excludePendingResults", false);
41
- let limitURL = new URLParam("limit", 100);
41
+ let limitURL = new URLParam("limit", 16);
42
42
 
43
43
  let savedPathsURL = new URLParam("savedPaths", "");
44
44
  let selectedFieldsURL = new URLParam("selectedFields", {} as Record<string, boolean>);
@@ -298,7 +298,7 @@ export class LogViewer3 extends qreact.Component {
298
298
  limit: limitURL.value,
299
299
  findBuffer: searchBuffer,
300
300
  pathOverrides: paths,
301
- only: excludePendingResults.value ? "local" : undefined,
301
+ only: excludePendingResults.value ? "public" : undefined,
302
302
  forceReadProduction: readProductionLogsURL.value,
303
303
  searchFromStart: range.searchFromStart,
304
304
  },
@@ -67,21 +67,23 @@ export class RenderSearchStats extends qreact.Component<{
67
67
 
68
68
  const fileItems = [
69
69
  `${formatTime(stats.fileFindTime)} | ${formatNumber(stats.localFilesSearched + stats.backblazeFilesSearched)} / ${formatNumber(stats.totalLocalFiles + stats.totalBackblazeFiles)} | ${formatNumber(totalSize)}B`,
70
- `remote ${formatNumber(stats.backblazeFilesSearched)} / ${formatNumber(stats.totalBackblazeFiles)} | ${formatNumber(remoteTotalSize)}B | ${formatNumber(stats.backblazeLogsSearched)} logs`,
70
+ `remote ${formatNumber(stats.backblazeFilesSearched)} / ${formatNumber(stats.totalBackblazeFiles)} | ${formatNumber(stats.backblazeUncompressedSize)}B uncomp | ${formatNumber(stats.backblazeUncompressedSize / remoteTotalSize)}X | ${formatNumber(stats.backblazeLogsSearched)} logs`,
71
71
  `pending ${formatNumber(stats.localFilesSearched)} / ${formatNumber(stats.totalLocalFiles)} | ${formatNumber(localTotalSize)}B`,
72
72
  ];
73
73
 
74
74
  const totalIndexesSearched = stats.remoteIndexesSearched + stats.localIndexesSearched;
75
75
  const totalIndexSize = stats.remoteIndexSize + stats.localIndexSize;
76
76
  const indexItems = [
77
- `${formatTime(stats.indexSearchTime)} | ${formatNumber(totalIndexesSearched)} | ${formatNumber(totalIndexSize)}B | ${formatNumber(totalSize / totalIndexSize)}X`,
78
- `remote ${formatNumber(stats.remoteIndexesSearched)} | ${formatNumber(stats.remoteIndexSize)}B | ${formatNumber(remoteTotalSize / stats.remoteIndexSize)}X`,
79
- `local ${formatNumber(stats.localIndexesSearched)} | ${formatNumber(stats.localIndexSize)}B | ${formatNumber(localTotalSize / stats.localIndexSize)}X`,
77
+ `${formatTime(stats.indexSearchTime)} | ${formatNumber(totalIndexesSearched)} | ${formatNumber(totalIndexSize)}B`,
78
+ `remote ${formatNumber(stats.remoteIndexSize)}`,
79
+ `local ${formatNumber(stats.localIndexesSearched)} | ${formatNumber(stats.localIndexSize)}B`,
80
80
  ];
81
81
 
82
82
  const blockItems = [
83
- <div title={`Scanned size = ${formatNumber(stats.blocksCheckedCompressedSize)}B, Decompressed size = ${formatNumber(stats.blocksCheckedDecompressedSize)}B, Compression ratio = ${formatNumber(stats.blocksCheckedDecompressedSize / stats.blocksCheckedCompressedSize)}X`}>{formatTime(stats.blockSearchTime)} | {formatNumber(stats.blockCheckedCount)} | {formatNumber(stats.blocksCheckedCompressedSize)}B | {formatNumber(stats.blocksCheckedDecompressedSize / stats.blocksCheckedCompressedSize)}X</div>,
84
- `total scanned ${formatNumber(stats.totalBlockCount)} (${formatPercent(stats.blockCheckedCount / stats.totalBlockCount)})`,
83
+ <div title={`Scanned size = ${formatNumber(stats.blocksCheckedCompressedSize)}B, Decompressed size = ${formatNumber(stats.blocksCheckedDecompressedSize)}B, Compression ratio = ${formatNumber(stats.blocksCheckedDecompressedSize / stats.blocksCheckedCompressedSize)}X`}>
84
+ {formatTime(stats.blockSearchTime)} | {formatNumber(stats.blockCheckedCount)} | {formatNumber(stats.blocksCheckedDecompressedSize)}B uncomp | {formatNumber(stats.blocksCheckedDecompressedSize / stats.blocksCheckedCompressedSize)}X
85
+ </div>,
86
+ `scanned ${formatNumber(stats.blockCheckedCount)} (${formatPercent(stats.blockCheckedCount / stats.totalBlockCount)})`,
85
87
  `remote ${formatNumber(stats.remoteBlockCheckedCount)} / ${formatNumber(stats.remoteBlockCount)} (${formatPercent(stats.remoteBlockCheckedCount / stats.remoteBlockCount)}) | local ${formatNumber(stats.localBlockCheckedCount)} / ${formatNumber(stats.localBlockCount)} (${formatPercent(stats.localBlockCheckedCount / stats.localBlockCount)})`,
86
88
  ];
87
89
  let cacheItems = [
@@ -137,16 +137,16 @@ export class PrimitiveDisplay extends qreact.Component<{
137
137
  render() {
138
138
  let value = this.props.value;
139
139
  if (typeof value === "number") {
140
- return <span className={css.boldStyle.hslcolor(265, 70, 60)}>{value}</span>;
140
+ return <span className={css.boldStyle.hslcolor(265, 70, 70)}>{value}</span>;
141
141
  }
142
142
  if (typeof value === "boolean") {
143
- return <span className={css.boldStyle.hslcolor(207, 70, 60)}>{JSON.stringify(value)}</span>;
143
+ return <span className={css.boldStyle.hslcolor(207, 70, 70)}>{JSON.stringify(value)}</span>;
144
144
  }
145
145
 
146
146
  if (typeof value === "string") {
147
147
  let colors = parseAnsiColors(value);
148
148
  if (colors.length === 1 && !colors[0].color) {
149
- return <span className={css.boldStyle.hslcolor(30, 70, 50)}>"{value}"</span>;
149
+ return <span className={css.boldStyle.hslcolor(30, 70, 70)}>"{value}"</span>;
150
150
  }
151
151
  return (
152
152
  <span className={css.display("inline-flex").rowGap(4).columnGap(1).wrap}>
@@ -155,7 +155,7 @@ export class PrimitiveDisplay extends qreact.Component<{
155
155
  return <span
156
156
  className={
157
157
  (hue !== undefined && css.boldStyle.pad2(4, 1).hsla(hue, 70, 50, 0.5) || "")
158
- + (hue === undefined && css.boldStyle.hslcolor(30, 70, 50))
158
+ + (hue === undefined && css.boldStyle.hslcolor(30, 70, 70))
159
159
  }
160
160
  >{text}</span>;
161
161
  })}
@@ -27,8 +27,10 @@ import { StartEllipsis } from "../../../library-components/StartEllipsis";
27
27
  import { LifeCycleEntryReadMode } from "./LifeCycleEntryReadMode";
28
28
  import { LifeCycleEntryEditor } from "./LifeCycleEntryEditor";
29
29
  import { LifeCycleRenderer, LifeCycleInstanceRenderer } from "./LifeCycleRenderer";
30
+ import { readProductionLogsURL } from "../IndexedLogs/LogViewerParams";
31
+ import { isPublic } from "../../../config";
30
32
  export let lifecycleIdURL = new URLParam("lifecycleid", "");
31
- export let limitURL = new URLParam("lifecyclelimit", 100);
33
+ export let limitURL = new URLParam("lifecyclelimit", 16);
32
34
  export let additionalSearchURL = new URLParam("lifecyclesearch", "");
33
35
 
34
36
  export class LifeCyclePage extends qreact.Component {
@@ -94,6 +96,12 @@ export class LifeCyclePage extends qreact.Component {
94
96
  number
95
97
  url={limitURL}
96
98
  />
99
+ {!isPublic() && <InputLabelURL
100
+ checkbox
101
+ label="Read Production Logs"
102
+ url={readProductionLogsURL}
103
+ />}
104
+
97
105
  <TimeRangeSelector />
98
106
  </div>
99
107
 
@@ -221,6 +229,11 @@ export class LifeCyclePage extends qreact.Component {
221
229
  <span key={key} className={css.colorhsl(0, 70, 40)}>{key}</span>
222
230
  ))}
223
231
  </div>
232
+ <Button hue={200} onClick={() => {
233
+ console.log(invalid.datum);
234
+ }}>
235
+ Log
236
+ </Button>
224
237
  </div>
225
238
  ))}
226
239
  </div>
@@ -5,7 +5,7 @@ import { getLoggers2Async, LogDatum } from "../diskLogger";
5
5
  import { IndexedLogResults, createEmptyIndexedLogResults, mergeIndexedLogResults } from "../IndexedLogs/BufferIndexHelpers";
6
6
  import { errorToUndefined } from "../../../errors";
7
7
  import { unique, maybeUndefined } from "../../../misc";
8
- import { formatSearchString } from "../IndexedLogs/LogViewerParams";
8
+ import { formatSearchString, readProductionLogsURL } from "../IndexedLogs/LogViewerParams";
9
9
  import { createMatchesPatternCached } from "../IndexedLogs/bufferSearchFindMatcher";
10
10
  import { getPathStr } from "../../../path";
11
11
  import { LifeCycle, LifeCycleEntry, LifeCyclesController } from "./lifeCycles";
@@ -229,6 +229,7 @@ export function createLifeCycleSearch(
229
229
  limit: limit,
230
230
  findBuffer: searchBuffer,
231
231
  searchFromStart: range.searchFromStart,
232
+ forceReadProduction: readProductionLogsURL.value,
232
233
  },
233
234
  onResult: (match: LogDatum) => {
234
235
  results.push(match);
@@ -423,6 +424,7 @@ export function createLifeCycleSearch(
423
424
  limit: searchLimit,
424
425
  findBuffer: searchBuffer,
425
426
  searchFromStart: range.searchFromStart,
427
+ forceReadProduction: readProductionLogsURL.value,
426
428
  },
427
429
  onResult: (match: LogDatum) => {
428
430
  results.push(match);