querysub 0.391.0 → 0.392.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.391.0",
3
+ "version": "0.392.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",
@@ -57,7 +57,7 @@
57
57
  "pako": "^2.1.0",
58
58
  "peggy": "^5.0.6",
59
59
  "querysub": "^0.357.0",
60
- "socket-function": "^1.1.2",
60
+ "socket-function": "^1.1.4",
61
61
  "terser": "^5.31.0",
62
62
  "typesafecss": "^0.28.0",
63
63
  "yaml": "^2.5.0",
@@ -2,12 +2,12 @@ import { SocketFunction } from "socket-function/SocketFunction";
2
2
  import { measureBlock, measureFnc, measureWrap } from "socket-function/src/profiling/measure";
3
3
  import { errorToUndefined, errorToUndefinedSilent, ignoreErrors, logErrors, timeoutToUndefined, timeoutToUndefinedSilent } from "../errors";
4
4
  import { PromiseObj } from "../promise";
5
- import { getAllNodeIds, getBrowserUrlNode, getOwnNodeId, isNodeDiscoveryLogging, isOwnNodeId, onNodeDiscoveryReady, triggerNodeChange, watchDeltaNodeIds, watchNodeIds } from "../-f-node-discovery/NodeDiscovery";
5
+ import { getAllNodeIds, getBrowserUrlNode, getOwnNodeId, isNodeDiscoveryLogging, isNodeIdLocal, isOwnNodeId, onNodeDiscoveryReady, triggerNodeChange, watchDeltaNodeIds, watchNodeIds } from "../-f-node-discovery/NodeDiscovery";
6
6
  import { PathValueController } from "./PathValueController";
7
7
  import { MAX_ACCEPTED_AUTHORITY_STARTUP_TIME, PathValueSnapshot, STARTUP_CUTOFF_TIME, authorityStorage, matchesParentRangeFilterPart } from "./pathValueCore";
8
8
  import { pathValueArchives } from "./pathValueArchives";
9
9
  import { deepCloneJSON, isNode, sha256Hash, sort, timeInMinute, timeInSecond } from "socket-function/src/misc";
10
- import { delay, runInfinitePoll } from "socket-function/src/batching";
10
+ import { delay, runInSerial, runInfinitePoll } from "socket-function/src/batching";
11
11
  import { blue, green, magenta, red, yellow } from "socket-function/src/formatting/logColors";
12
12
  import debugbreak from "debugbreak";
13
13
  import { getNodeIdFromLocation, getNodeIdIP, getNodeIdLocation } from "socket-function/src/nodeCache";
@@ -22,6 +22,7 @@ import { IdentityController_getCurrentReconnectNodeIdAssert, IdentityController_
22
22
  import { getBufferFraction, getBufferInt, getShortNumber } from "../bits";
23
23
  import { devDebugbreak, getDomain, isDevDebugbreak } from "../config";
24
24
  import { waitForFirstTimeSync } from "socket-function/time/trueTimeShim";
25
+ import { testTCPIsListening } from "socket-function/src/networking";
25
26
 
26
27
  export const LOCAL_DOMAIN = "LOCAL";
27
28
  export const LOCAL_DOMAIN_PATH = getPathStr1(LOCAL_DOMAIN);
@@ -36,6 +37,7 @@ const MAX_RECONNECT_TIME = timeInMinute * 15;
36
37
  const RECONNECT_POLL_INTERVAL = 10000;
37
38
 
38
39
  // Poll nodes that appear dead. Without this, if the internet goes down, we might forever ignore nodes.
40
+ // NOTE: During development this might seem excessive, however, after about an hour this should ramp up to the full poll interval of a minute, which should be fairly reasonable.
39
41
  const INITIAL_RECOVERY_POLL_INTERVAL = timeInSecond * 5;
40
42
  const INITIAL_RECOVERY_RUNS = 100;
41
43
  const RECOVERY_POLL_INTERVAL = timeInMinute;
@@ -213,7 +215,7 @@ class NodePathAuthorities {
213
215
  let obj = this.authorities.get(nodeId);
214
216
  if (!obj) {
215
217
  // Might as well use this to add the node, if we don't know about it yet.
216
- ingestNewNodeIds([nodeId], []);
218
+ void ingestNewNodeIds([nodeId], []);
217
219
  return;
218
220
  }
219
221
  obj.authorityPaths = await PathController.nodes[nodeId].getAuthorityPaths();
@@ -225,7 +227,7 @@ class NodePathAuthorities {
225
227
  let firstPromise = new PromiseObj<unknown>();
226
228
  logErrors(firstPromise.promise);
227
229
 
228
- const ingestNewNodeIds = (newNodeIds: string[], removedNodeIds: string[]) => {
230
+ const ingestNewNodeIds = runInSerial(async (newNodeIds: string[], removedNodeIds: string[]) => {
229
231
  for (let nodeId of removedNodeIds) {
230
232
  this.authorities.delete(nodeId);
231
233
  }
@@ -249,6 +251,18 @@ class NodePathAuthorities {
249
251
  return;
250
252
  }
251
253
 
254
+ // Do an initial test by just opening a TCP connection. This will help filter out a lot of dead nodes immediately. Which, in turn, avoids having to create our initial connection signature, which saves a lot of time.
255
+ if (isNode()) {
256
+ let nodeIdObj = getNodeIdLocation(nodeId);
257
+ if (!nodeIdObj) {
258
+ console.error(`Bad nodeId ${nodeId}`);
259
+ return;
260
+ }
261
+ let isListening = await testTCPIsListening(nodeIdObj.address, nodeIdObj.port);
262
+ if (!isListening) return;
263
+ }
264
+
265
+ console.log(blue(`Checking for status of node ${nodeId}`));
252
266
  let time = Date.now();
253
267
  let createTime = await timeoutToUndefinedSilent(POLL_RATE, PathController.nodes[nodeId].getCreateTime());
254
268
  if (createTime === undefined) {
@@ -258,6 +272,7 @@ class NodePathAuthorities {
258
272
  console.log(yellow(`Node didn't respond to getCreateTime`), { nodeId });
259
273
  }
260
274
  }
275
+ console.log(yellow(`Node ${nodeId} is not available`));
261
276
  this.previouslyNotAvailableNodes.add(nodeId);
262
277
  return;
263
278
  }
@@ -311,7 +326,7 @@ class NodePathAuthorities {
311
326
  if (isCurrentFirst) {
312
327
  firstPromise.resolve(promise);
313
328
  }
314
- };
329
+ });
315
330
 
316
331
  let time = Date.now();
317
332
  watchDeltaNodeIds(obj => ingestNewNodeIds(obj.newNodeIds, obj.removedNodeIds));
@@ -340,7 +355,7 @@ class NodePathAuthorities {
340
355
  nonExistentNodes.push(node);
341
356
  }
342
357
  // Pretend all dead nodes are new
343
- ingestNewNodeIds(nonExistentNodes, []);
358
+ await ingestNewNodeIds(nonExistentNodes, []);
344
359
  });
345
360
 
346
361
  let readyCount = 0;
@@ -23,6 +23,8 @@ import { TypedConfigEditor } from "../../library-components/TypedConfigEditor";
23
23
  import { managementPageURL } from "../../diagnostics/managementPages";
24
24
  import { getLogViewerParams } from "../../diagnostics/logs/IndexedLogs/LogViewerParams";
25
25
  import { getScreenName } from "../machineApplyMainCode";
26
+ import { getOwnThreadId } from "../../-f-node-discovery/NodeDiscovery";
27
+ import { decodeNodeId } from "../../-a-auth/certs";
26
28
 
27
29
 
28
30
 
@@ -338,12 +340,12 @@ export class ServiceDetailPage extends qreact.Component {
338
340
  <div
339
341
  className={css.hbox(12)}
340
342
  >
341
- <div className={css.vbox(5)}>
343
+ <div className={css.hbox(5)}>
342
344
  <div>
343
345
  {screenName}
344
346
  </div>
345
347
  <div>
346
- {machineId} ({machineInfo.info["getExternalIP"]})
348
+ {serviceInfo?.nodeId || machineId} ({machineInfo.info["getExternalIP"]})
347
349
  </div>
348
350
  </div>
349
351
  {isDisabled && (
@@ -59,6 +59,8 @@ export type MachineInfo = {
59
59
  // Only times launched for the current applyNodeId, but... still very useful.
60
60
  totalTimesLaunched: number;
61
61
  // Might take a while to set (15 minutes or more). It's better to look in the nodes list and find the one that seems to match (maybe looking at the startup path to find it?)
62
+ // TODO: Make this work correctly when we deploy multiple instances (the node needs to know which index it is so it can write to a unique file).
63
+ // - We could probably set environment variables in the screen?
62
64
  nodeId: string;
63
65
  }>;
64
66
  };
@@ -1,64 +1,20 @@
1
1
  /*
2
2
  todonext
3
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
4
 
13
5
 
14
- todonext
15
-
16
-
17
-
18
- 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.
19
-
20
-
21
-
22
-
23
- //todonext
24
-
25
-
26
-
27
- 3) "guessed node id" is never working? At least, on the machine's page it is ALWAYS empty, even though it should be almost always detected...
28
-
29
- 4) Verify it works again, when we have multiple servers
30
-
31
- Invalid addition, you tried to add 1 + Infinity, operands must be valid numbers
32
-
33
-
34
-
35
- 0) Add LZ4 compression to socket-function by default
36
- - Setup local tester for it to start
37
- - with non-synced endpoint, just surely socket-function
38
- - purely nodejs, just talking to itself
39
- - Allow setting "compress" to "none" or "lz4" or "zip" or "zip0" or "zip3", etc, for levels.
40
- - default is "lz4"
41
- - REQUIRES feature checking the remote, to make sure it is new enough to accept this.
42
- - A generic thing which gets the version is probably fine.
43
- - When decoding, I think we should just check the first byte. It should be a magic number which tells us which compression it's using.
44
- - LZ4 compression is fast enough that this should cause basically no overhead, and in many cases greatly reduce the bandwidth (which will increase the speed).
45
- - We're gonna have to investigate how we're sending buffers anyway. I think this should be easy, but we
46
- 0.1) Verify the size difference with some local testing
47
- - ALSO, verify the processing overhead is acceptable.
48
- 1) Deploy, which SHOULD be backwards compatible with everything?
6
+ 2) Publish socket-function and update to use the latest
7
+ 1) Deploy everything and make sure the servers run
49
8
 
50
9
 
51
10
  -1) Change PathValueSerialize to use LZ4
52
- - I think we already have a compression flag here, so it should be easy enough to just support it to change it to support LZ4.
53
- - I think we want to disable the server, and then when we launch the server locally, it should have to read from disk.
54
- -2) It would probably be valuable to test the synchronization speed between two different servers. It seems like when the remote is running and we start a local server, it really takes a long time for it to get ready. As in minutes.
55
- - This might have already been fixed by us improving the compression speed to not use gzip, maybe, but we should test it again, and if not, we should see what's slow
11
+ - I think we already have a compression flag here, so it should be easy enough to just change it to support and use LZ4 by default
12
+ -3) Send progress/timing when sending very large messages?
13
+ - Maybe related to the remote => local synchronization. Maybe we're doing multi- many calls, in which case we can't detect it. But if we're doing just one call... Then the socket function system should realize.
14
+ - And even if it's the synchronization code which is doing many calls, then it should probably log progress and timing (on both ends)
15
+ -2) Fix synchronization speed from remote to local.
16
+ - Last time it seemed very slow
56
17
  - We might need to jump into the server and look at its profiles there by forcing them to omit, which isn't too hard, but it is kind of annoying.
57
-
58
- -3) During server startup (when there is a remote server), we spend a lot of time in identityHook.
59
- - BUT... Our check to see if the async call that we're doing underneath is taking more than 200 milliseconds, is never firing. Even though apparently plenty of calls are taking over a second in total, so what why is it slow? Are some of the synchronous functions we're calling slow?
60
- - Basically, there's nowhere that could be slow, and we're timing it, and it times as being fast. However, in the profiles, it shows up as being slow.
61
- - It could also be an asynchronous issue, so some other timing is getting alias to it. That is feasible...
62
18
  */
63
19
 
64
20
 
@@ -73,6 +29,9 @@ Invalid addition, you tried to add 1 + Infinity, operands must be valid numbers
73
29
  // - I mean, we have to implement it without caching anyways to start, so we can just do that, and then cache it later if we see the need...
74
30
  // - WELL, we need SOME kind of caching... Maybe... we DO use a strict time range, and then... if we've scanned a pending file in the past, we can cache that, because we know we've got all of it's values. Hmm...
75
31
  // - Use lifecycles to debug rejections. To a point, until it is likely we are out of sync, then we should write the sync verification code.
32
+ // - Maybe it isn't necessarily rejections, but definitely if we're running stuff locally and remotely it breaks. Could it be the case that we can't run the path value server both locally and remotely? And if so, we really should prevent this in some way.
33
+ // - Annoyingly enough, we're actually going to have to add a case where we can scan the local logs as well as the remote logs to debug running it locally...
34
+ // - ALTHOUGH, It does fail just if we have the local running server, But we're on the remote site. So we might be able to just debug it from that life cycle, from the remote life cycles.
76
35
 
77
36
 
78
37
  // todonext;
@@ -1,32 +1,2 @@
1
- // NOTE: Even if we wanted to use the production version, we couldn't because it's not compatible with the client-side code, because they decided to do a file read to load in their WebAssembly.
2
- import lz4_stream from "../misc/lz4_wasm_nodejs";
3
- import { measureFnc } from "socket-function/src/profiling/measure";
4
- export class LZ4 {
5
- @measureFnc
6
- static compress(data: Buffer): Buffer {
7
- return this.compressUntracked(data);
8
- }
9
- static compressUntracked(data: Buffer): Buffer {
10
- try {
11
- return Buffer.from(lz4_stream.compress(data));
12
- } catch (e) {
13
- // Rethrow non errors as properly wrapped errors
14
- if (!(e && e instanceof Error)) {
15
- throw new Error(`Error compressing LZ4: ${e}`);
16
- }
17
- throw e;
18
- }
19
- }
20
- @measureFnc
21
- static decompress(data: Buffer): Buffer {
22
- try {
23
- return Buffer.from(lz4_stream.decompress(data));
24
- } catch (e) {
25
- // Rethrow non errors as properly wrapped errors
26
- if (!(e && e instanceof Error)) {
27
- throw new Error(`Error decompressing LZ4: ${e}`);
28
- }
29
- throw e;
30
- }
31
- }
32
- }
1
+ import { LZ4 } from "socket-function/src/lz4/LZ4";
2
+ export { LZ4 };
package/test.ts CHANGED
@@ -6,12 +6,39 @@ import "./inject";
6
6
  import { Querysub } from "./src/4-querysub/QuerysubController";
7
7
  import { getErrorLogs, getLoggers2Async } from "./src/diagnostics/logs/diskLogger";
8
8
  import { watchAllValues } from "./src/diagnostics/logs/errorNotifications2/logWatcher";
9
+ import { SocketFunction } from "socket-function/SocketFunction";
10
+ import fs from "fs";
11
+ import { getControllerNodeId, getControllerNodeIdList } from "./src/-g-core-values/NodeCapabilities";
12
+ import { delay } from "socket-function/src/batching";
13
+ import { timeInSecond } from "socket-function/src/misc";
9
14
 
15
+ const path = "D:/repos/qs-cyoa/database-storage/disklogs/1757030400000-1757116800000.log";
16
+ class TestControllerBase {
17
+ async test() {
18
+ return await fs.promises.readFile(path, "utf8");
19
+ }
20
+ }
21
+
22
+ const TestController = SocketFunction.register("TestController-019ca5fa-52ef-73bf-b918-4d9cde51b618", new TestControllerBase(), () => ({
23
+ test: {
24
+ compress: true,
25
+ },
26
+ }));
10
27
  async function main() {
11
28
  await Querysub.hostService("testwatcher");
12
- let errorLogs = await getErrorLogs();
13
- for await (let error of watchAllValues(errorLogs)) {
14
- process.stdout.write(JSON.stringify(error) + "\n");
29
+
30
+ while (true) {
31
+ try {
32
+ let otherNode = await getControllerNodeId(TestController);
33
+ if (!otherNode) throw new Error("No other node found");
34
+ let result = await TestController.nodes[otherNode].test();
35
+ let correct = await fs.promises.readFile(path, "utf8");
36
+ if (result !== correct) throw new Error("Result does not match correct");
37
+ console.log(`Received ${result.length} bytes from ${otherNode}`);
38
+ } catch (e: any) {
39
+ console.error(e);
40
+ }
41
+ await delay(timeInSecond * 1);
15
42
  }
16
43
  }
17
44