querysub 0.404.0 → 0.405.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/join.js CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  require("typenode");
4
- require("../src/archiveapps/archiveGCEntry");
4
+ require("../src/archiveapps/archiveJoinEntry");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "querysub",
3
- "version": "0.404.0",
3
+ "version": "0.405.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",
@@ -1,5 +1,5 @@
1
1
  import { sort } from "socket-function/src/misc";
2
- import { getLastPathPart, getPathDepth, getPathIndex, getPathStr1 } from "../path";
2
+ import { getLastPathPart, getPathDepth, getPathIndex, getPathStr1, hack_stripPackedPath } from "../path";
3
3
  import { AuthorityEntry, authorityLookup } from "./AuthorityLookup";
4
4
  import { PathValue } from "./pathValueCore";
5
5
  import { shuffle } from "../misc/random";
@@ -59,8 +59,9 @@ export class PathRouter {
59
59
  path: string;
60
60
  spec: AuthoritySpec;
61
61
  }): number {
62
- // NOTE: getSelfPathIdentifierTargets also hardcodes this logic, so it can hash many values quickly
62
+ // NOTE: getPathIdentifierTargets also hardcodes this logic, so it can hash many values quickly
63
63
  let { path, spec } = config;
64
+ path = hack_stripPackedPath(path);
64
65
  let override = getRoutingOverride(path);
65
66
  if (override) {
66
67
  if (!hasPrefixHash({ spec, prefixHash: override.prefixHash })) return -1;
@@ -70,7 +71,11 @@ export class PathRouter {
70
71
  let prefix = spec.prefixes.find(x => path.startsWith(x.prefix) && x.prefix !== path);
71
72
  if (prefix) {
72
73
  let key = getPathIndex(path, prefix.hashIndex);
73
- if (key === undefined) throw new Error(`Impossible, hash index ${prefix.hashIndex} is out of range for path ${path}, but it matched the prefix ${prefix.prefix}`);
74
+ if (key === undefined) {
75
+ require("debugbreak")(2);
76
+ debugger;
77
+ throw new Error(`Impossible, hash index ${prefix.hashIndex} is out of range for path ${path}, but it matched the prefix ${prefix.prefix}`);
78
+ }
74
79
  return this.getSingleKeyRoute(key);
75
80
  }
76
81
  if (spec.excludeDefault) return -1;
@@ -107,13 +112,13 @@ export class PathRouter {
107
112
  private static encodeIdentifier(config: { prefixes: string[]; rangeStart: number; rangeEnd: number } | "remaining"): string {
108
113
  if (config === "remaining") return "P!REMAINING";
109
114
  let { prefixes, rangeStart, rangeEnd } = config;
110
- return ["P", rangeStart.toString(), rangeEnd.toString(), ...prefixes.map(x => this.getPrefixHash(x))].join("!");
115
+ return ["P", rangeStart.toString(), rangeEnd.toString(), ...prefixes.map(x => this.getPrefixHash(x)), ""].join("!");
111
116
 
112
117
  }
113
118
  private static decodeIdentifier(identifier: string): { prefixHashes: string[]; rangeStart: number; rangeEnd: number } | "remaining" {
114
119
  if (!identifier.startsWith("P")) return "remaining";
115
120
  let parts = identifier.split("!");
116
- if (parts[1] === "REMAINING") return "remaining";
121
+ if (parts[1].startsWith("REMAINING")) return "remaining";
117
122
  return {
118
123
  rangeStart: parseFloat(parts[1]),
119
124
  rangeEnd: parseFloat(parts[2]),
@@ -125,7 +130,7 @@ export class PathRouter {
125
130
  // NOTE: Encodes all the data, even if it matches our spec or not. If you don't want this, you have to filter first
126
131
  // - If this becomes an issue we COULD filter, as we can do it quickly, but I don't think it is required, as all the present usecases prefilter anyways.
127
132
  @measureFnc
128
- public static getSelfPathIdentifierTargets(values: PathValue[]): Map<string, PathValue[]> {
133
+ public static getPathIdentifierTargets(values: PathValue[], ourSpec: AuthoritySpec): Map<string, PathValue[]> {
129
134
  // NOTE: The file size limit is 1024 bytes. But we also have our folder, etc, so we want to add enough buffer
130
135
  // - Shorter hashes means we can store more, but there's a point when the collisions make it less useful.
131
136
  const MAX_PREFIXES_PER_FILE = 50;
@@ -135,13 +140,11 @@ export class PathRouter {
135
140
  return new Map([[this.encodeIdentifier("remaining"), values]]);
136
141
  }
137
142
 
138
- let ourSpec = authorityLookup.getOurSpec();
139
-
140
143
  let prefixes = ourSpec.prefixes.slice();
141
144
  sort(prefixes, x => x.prefix.length);
142
145
  function getPrefix(path: string): string | undefined {
143
146
  for (let prefix of prefixes) {
144
- if (path.startsWith(prefix.prefix)) return prefix.prefix;
147
+ if (path.startsWith(prefix.prefix) && prefix.prefix !== path) return prefix.prefix;
145
148
  }
146
149
  return undefined;
147
150
  }
@@ -165,6 +168,9 @@ export class PathRouter {
165
168
  }));
166
169
  sort(prefixGroups, x => -x.values.length);
167
170
 
171
+ require("debugbreak")(2);
172
+ debugger;
173
+
168
174
  let groups: {
169
175
  prefixes: string[];
170
176
  values: PathValue[][];
@@ -216,7 +222,9 @@ export class PathRouter {
216
222
  let hashIndex = getPathDepth(prefix);
217
223
  for (let value of values) {
218
224
  let key = getPathIndex(value.path, hashIndex);
219
- if (key === undefined) throw new Error(`Impossible, hash index ${hashIndex} is out of range for path ${value.path}, but it matched the prefix ${prefix}`);
225
+ if (key === undefined) {
226
+ throw new Error(`Impossible, hash index ${hashIndex} is out of range for path ${value.path}, but it matched the prefix ${prefix}`);
227
+ }
220
228
  let route = this.getSingleKeyRoute(key);
221
229
  let routeIndex = Math.floor(route * splitCount);
222
230
  let routeValues = byRouteGroup.get(routeIndex);
@@ -16,7 +16,15 @@ export async function getOurAuthoritySpec(defaultToAll?: boolean): Promise<Autho
16
16
 
17
17
  if (!range) {
18
18
  if (defaultToAll) {
19
- return getAllAuthoritySpec();
19
+ return {
20
+ nodeId: "",
21
+ routeStart: 0,
22
+ routeEnd: 1,
23
+ prefixes: prefixes.map(prefix => ({
24
+ prefix,
25
+ hashIndex: getPathDepth(prefix),
26
+ })),
27
+ };
20
28
  }
21
29
  return undefined;
22
30
  }
@@ -13,6 +13,7 @@ import { createArchiveLocker2 } from "./archiveLocks/ArchiveLocks2";
13
13
  import { devDebugbreak, isNoNetwork } from "../config";
14
14
  import { wrapArchivesWithCache } from "../-a-archives/archiveCache";
15
15
  import { AuthoritySpec, PathRouter } from "./PathRouter";
16
+ import { authorityLookup } from "./AuthorityLookup";
16
17
 
17
18
  export const archives = lazy(() => wrapArchivesWithCache(getArchives("path-values/")));
18
19
  export const archivesLocks = lazy(() => getArchives("path-values-locks/"));
@@ -161,7 +162,7 @@ export class PathValueArchives {
161
162
 
162
163
  @measureFnc
163
164
  public async archiveValues(values: PathValue[]) {
164
- let parts = PathRouter.getSelfPathIdentifierTargets(values);
165
+ let parts = PathRouter.getPathIdentifierTargets(values, authorityLookup.getOurSpec());
165
166
 
166
167
  for (let [pathIdentifier, values] of parts) {
167
168
  let encodedObj = await this.encodeValuePaths(values);
@@ -7,7 +7,7 @@ import { PathValue, VALUE_GC_THRESHOLD, FILE_VALUE_COUNT_LIMIT, FILE_SIZE_LIMIT,
7
7
  import { getSingleSizeEstimate } from "../5-diagnostics/shared";
8
8
  import { logNodeStats } from "../-0-hooks/hooks";
9
9
  import debugbreak from "debugbreak";
10
- import { AuthorityEntry } from "../0-path-value-core/AuthorityLookup";
10
+ import { AuthorityEntry, authorityLookup } from "../0-path-value-core/AuthorityLookup";
11
11
  import { AuthoritySpec, PathRouter } from "../0-path-value-core/PathRouter";
12
12
  import { getOurAuthoritySpec } from "../0-path-value-core/PathRouterServerAuthoritySpec";
13
13
 
@@ -249,7 +249,7 @@ export async function runArchiveMover(config: {
249
249
 
250
250
 
251
251
  for (let [key, values] of Object.entries(result.newValues)) {
252
- let targets = PathRouter.getSelfPathIdentifierTargets(values);
252
+ let targets = PathRouter.getPathIdentifierTargets(values, authority);
253
253
  for (let [target, values] of targets) {
254
254
  await addValues(target + "/", values, key);
255
255
  }
@@ -2,7 +2,7 @@ import fs from "fs";
2
2
  import { cache, lazy } from "socket-function/src/caching";
3
3
  import { getStringKeys, sort } from "socket-function/src/misc";
4
4
  import { Args } from "socket-function/src/types";
5
- import { appendToPathStr, getPathFromStr, getPathStr, rootPathStr } from "../path";
5
+ import { appendToPathStr, getPathFromStr, getPathStr, joinPathStres, rootPathStr } from "../path";
6
6
  import { writeFunctionCall } from "./PathFunctionHelpers";
7
7
  import { CallSpec, functionSchema } from "./PathFunctionRunner";
8
8
  import { getDomain, isLocal } from "../config";
@@ -323,6 +323,7 @@ export function syncSchema<Schema>(schema?: Schema2): SyncSchemaResult<Schema> {
323
323
  createObjectAliveChecker(data, path, gcDelay);
324
324
  }
325
325
 
326
+
326
327
  let undoChecks = Schema2Fncs.getAllUndoChecks(schema);
327
328
  for (let checkObj of undoChecks) {
328
329
  // Need at least one check
@@ -368,7 +369,10 @@ export function syncSchema<Schema>(schema?: Schema2): SyncSchemaResult<Schema> {
368
369
  }
369
370
 
370
371
  // Register all root lookups as prefixes.
371
- let paths = Schema2Fncs.getLookups(schema).map(x => getPathStr(x));
372
+ let dataRoot = getProxyPath(() => functionSchema()[getDomain()].PathFunctionRunner[moduleId].Data);
373
+ let paths = Schema2Fncs.getLookups(schema).map(x =>
374
+ joinPathStres(dataRoot, getPathStr(x))
375
+ );
372
376
  // NOTE: This will break with wildcards, but... we also take only the highest level lookups, so it shouldn't be an issue
373
377
  sort(paths, x => x.length);
374
378
  let rootLookups = new Set<string>();
@@ -16,6 +16,11 @@ import { lazy } from "socket-function/src/caching";
16
16
  import { Button } from "../library-components/Button";
17
17
  import { updateRootDiscoveryLocation } from "../-f-node-discovery/NodeDiscovery";
18
18
 
19
+ setImmediate(() => {
20
+ // Modal
21
+ import("../5-diagnostics/Modal");
22
+ });
23
+
19
24
  const SWITCH_SERVER_TIMEOUT = timeInSecond * 15;
20
25
  const MAX_DISPLAY_INTERVAL = timeInMinute * 5;
21
26
  const FINAL_DELAY = timeInSecond * 30;
@@ -2,23 +2,29 @@ import "../inject";
2
2
 
3
3
  import { logErrors } from "../errors";
4
4
  import { PathValueArchives, pathValueArchives } from "../0-path-value-core/pathValueArchives";
5
- import { FILE_SIZE_LIMIT, FILE_VALUE_COUNT_LIMIT, PathValue, VALUE_GC_THRESHOLD } from "../0-path-value-core/pathValueCore";
5
+ import { PathValue, VALUE_GC_THRESHOLD } from "../0-path-value-core/pathValueCore";
6
6
  import { runInfinitePollCallAtStart } from "socket-function/src/batching";
7
7
  import { measureBlock } from "socket-function/src/profiling/measure";
8
8
  import { pathValueSerializer } from "../-h-path-value-serialize/PathValueSerializer";
9
9
  import { ArchiveTransaction, FileInfo } from "../0-path-value-core/archiveLocks/ArchiveLocks";
10
10
  import { formatNumber } from "socket-function/src/formatting/format";
11
- import { sort } from "socket-function/src/misc";
11
+ import { isNodeTrue, sort } from "socket-function/src/misc";
12
12
  import { Querysub } from "../4-querysub/QuerysubController";
13
13
  import { magenta } from "socket-function/src/formatting/logColors";
14
14
  import { PathRouter } from "../0-path-value-core/PathRouter";
15
15
  import { disablePathAuditer } from "../diagnostics/pathAuditerCallback";
16
16
  import { getOurAuthoritySpec } from "../0-path-value-core/PathRouterServerAuthoritySpec";
17
+ import yargs from "yargs";
17
18
 
18
- async function runGenesisJoinIteration() {
19
+ let yargObj = isNodeTrue() && yargs(process.argv)
20
+ .option("watch", { type: "boolean", desc: "If true, we only join genesis values, but we join in a loop, otherwise we just join absolutely everything, and then exit." })
21
+ .argv || {}
22
+ ;
23
+
24
+
25
+ async function runGenesisJoinIteration(config?: { force?: boolean }) {
19
26
  let authoritySpec = await getOurAuthoritySpec(true);
20
27
  let locker = await pathValueArchives.getArchiveLocker();
21
- let maxAge = Date.now() - VALUE_GC_THRESHOLD;
22
28
 
23
29
  let readCache = new Map<string, Buffer>();
24
30
  let reread = true;
@@ -31,15 +37,16 @@ async function runGenesisJoinIteration() {
31
37
  // Merge the newest first, so if we hit a big file, we can just ignore it,
32
38
  // and next time merge the smaller files after it.
33
39
  sort(valueFiles, x => -x.createTime);
34
- valueFiles = valueFiles.filter(x => {
35
- let obj = pathValueArchives.decodeDataPath(x.file);
36
- if (!obj.minTime) return false;
37
- if (obj.sourceType !== "genesis") return false;
38
- return x.createTime >= maxAge;
39
- });
40
+ if (!config?.force) {
41
+ valueFiles = valueFiles.filter(x => {
42
+ let obj = pathValueArchives.decodeDataPath(x.file);
43
+ if (!obj.minTime) return false;
44
+ return obj.sourceType === "genesis";
45
+ });
46
+ }
40
47
  let withinTimeRangeCount = valueFiles.length;
41
48
 
42
- if (valueFiles.length < 3) return [];
49
+ if (valueFiles.length < 3 && !config?.force) return [];
43
50
 
44
51
  await measureBlock(async function locker_readFiles() {
45
52
  let remainingFiles = valueFiles.filter(x => !readCache.has(x.file));
@@ -65,28 +72,20 @@ async function runGenesisJoinIteration() {
65
72
  let allValues: PathValue[][] = [];
66
73
  for (let valueFile of valueFiles) {
67
74
  let buffer = readCache.get(valueFile.file)!;
68
- if (totalSize + buffer.length > FILE_SIZE_LIMIT) {
69
- break;
70
- }
71
75
  let newValues = await PathValueArchives.loadValuesFromBuffer({
72
76
  path: valueFile.file,
73
77
  data: buffer,
74
78
  });
75
79
 
76
80
  let readValues = newValues.values;
77
- if (readValues.length + totalCount > FILE_VALUE_COUNT_LIMIT) {
78
- break;
79
- }
80
81
  allValues.push(readValues);
81
82
  usedFiles.push(valueFile);
82
83
  totalSize += buffer.length;
83
84
  totalCount += readValues.length;
84
85
  }
85
- if (usedFiles.length <= 1) return [];
86
86
 
87
87
  let allCombinedValues = allValues.flat();
88
88
 
89
-
90
89
  let transaction: ArchiveTransaction = {
91
90
  createFiles: [],
92
91
  deleteFiles: [],
@@ -95,7 +94,7 @@ async function runGenesisJoinIteration() {
95
94
  transaction.deleteFiles.push(file);
96
95
  }
97
96
 
98
- let targets = PathRouter.getSelfPathIdentifierTargets(allCombinedValues);
97
+ let targets = PathRouter.getPathIdentifierTargets(allCombinedValues, authoritySpec);
99
98
  for (let [target, values] of targets) {
100
99
 
101
100
  let dataObj = await pathValueArchives.encodeValuePaths(values, {
@@ -123,7 +122,17 @@ async function main() {
123
122
  disablePathAuditer();
124
123
  await Querysub.hostService("join");
125
124
 
126
- await runInfinitePollCallAtStart(VALUE_GC_THRESHOLD * 0.8, runGenesisJoinIteration);
125
+ if (yargObj.watch) {
126
+ await runInfinitePollCallAtStart(VALUE_GC_THRESHOLD * 0.8, runGenesisJoinIteration);
127
+ } else {
128
+ try {
129
+ await runGenesisJoinIteration({ force: true });
130
+ } catch (error) {
131
+ console.error(error);
132
+ } finally {
133
+ process.exit();
134
+ }
135
+ }
127
136
  }
128
137
 
129
138
  main().catch(logErrors);
package/tempnotes.txt CHANGED
@@ -12,8 +12,6 @@ BUGS:
12
12
 
13
13
 
14
14
 
15
- 4) deploy ON THE SITE, to deploy our prefixes
16
- - Do it via the site, to commit, publish, etc.
17
15
  3) gc, to split it into multiple directories
18
16
  4) Verify the site still works
19
17
 
package/test.ts CHANGED
@@ -3,6 +3,7 @@ chdir("D:/repos/qs-cyoa/");
3
3
 
4
4
  import "./inject";
5
5
 
6
+ import path from "path";
6
7
  import { list, sort } from "socket-function/src/misc";
7
8
  import { formatNumber } from "socket-function/src/formatting/format";
8
9
  import { PathValueArchives, archives, archivesLocks, archivesRecycleBin, pathValueArchives } from "./src/0-path-value-core/pathValueArchives";
@@ -19,26 +20,31 @@ import { unique } from "./src/misc";
19
20
  import { getAllAuthoritySpec, getOurAuthoritySpec } from "./src/0-path-value-core/PathRouterServerAuthoritySpec";
20
21
  import { PathRouter } from "./src/0-path-value-core/PathRouter";
21
22
  import { pathValueSerializer } from "./src/-h-path-value-serialize/PathValueSerializer";
23
+ import { getShardPrefixes } from "./src/0-path-value-core/ShardPrefixes";
22
24
 
23
25
  async function main() {
24
- let paths = await pathValueArchives.getValuePaths(getAllAuthoritySpec());
25
- paths = paths.filter(x => x.startsWith("P!REMAINING/"));
26
- for (let path of paths) {
27
- let data = await archives().get(path);
28
- if (!data) {
29
- console.log(`Missing data file: ${path}`);
30
- continue;
31
- }
32
- let loadObj = await PathValueArchives.loadValuesFromBuffer({ path, data });
26
+ let prefixes = await getShardPrefixes();
27
+ console.log(prefixes);
28
+ let deployPath = path.resolve("./deploy.ts");
29
+ await import(deployPath);
30
+ // let paths = await pathValueArchives.getValuePaths(getAllAuthoritySpec());
31
+ // paths = paths.filter(x => x.startsWith("P!REMAINING/"));
32
+ // for (let path of paths) {
33
+ // let data = await archives().get(path);
34
+ // if (!data) {
35
+ // console.log(`Missing data file: ${path}`);
36
+ // continue;
37
+ // }
38
+ // let loadObj = await PathValueArchives.loadValuesFromBuffer({ path, data });
33
39
 
34
- for (let value of loadObj.values) {
35
- if (!PathRouter.matchesAuthoritySpec(getAllAuthoritySpec(), value.path)) {
36
- throw new Error(`Value ${value.path} does not match authority spec`);
37
- }
38
- console.log(pathValueSerializer.getPathValue(value));
39
- }
40
- }
41
- return;
40
+ // for (let value of loadObj.values) {
41
+ // if (!PathRouter.matchesAuthoritySpec(getAllAuthoritySpec(), value.path)) {
42
+ // throw new Error(`Value ${value.path} does not match authority spec`);
43
+ // }
44
+ // console.log(pathValueSerializer.getPathValue(value));
45
+ // }
46
+ // }
47
+ // return;
42
48
 
43
49
  // let path = "P!REMAINING/data_37c5d323e0f9a083.1ed7a7340a015680.querysubtest.com:52026_1775097754671.579_3_1_337_1775097652829.5793_1775097652829.5793_genesis_.data";
44
50
  // let value = await archives().get(path);
@@ -54,6 +60,7 @@ async function main() {
54
60
  // return path.split("/").at(-1)!;
55
61
  // }
56
62
 
63
+ /*
57
64
  let allValuesObj = await pathValueArchives.loadValues({
58
65
  nodeId: "",
59
66
  prefixes: [],
@@ -62,6 +69,7 @@ async function main() {
62
69
  });
63
70
  let allValues = Object.values(allValuesObj.values).flat();
64
71
  console.log(`Total values loaded: ${formatNumber(allValues.length)}`);
72
+ */
65
73
 
66
74
  // const badDeleteTransaction = "transaction_ tSeqNum=887 tWriteTime=1774715868374.9143 thread=9dc0 cCount=14 dCount=3482 create=X,X,X,X,X,X,X,X,X,X,X,X,X,X delete=2@0977,3@0977,4@0977,1@0a2a,2@0a2a,3@0a2a,4@0a2... .transaction";
67
75
 
@@ -1,50 +0,0 @@
1
- import "../inject";
2
-
3
- import { Querysub } from "../4-querysub/QuerysubController";
4
- import { logErrors } from "../errors";
5
- import { timeInDay, timeInHour } from "socket-function/src/misc";
6
- import { runArchiveMover } from "../2-proxy/archiveMoveHarness";
7
- import { PathValue, compareTime } from "../0-path-value-core/pathValueCore";
8
- import { disablePathAuditer } from "../diagnostics/pathAuditerCallback";
9
-
10
- const MERGE_DELAY = timeInHour;
11
-
12
- async function mergeFiles() {
13
- await runArchiveMover({
14
- debugName: "merge",
15
- outputType: "merge",
16
- async runMover(config) {
17
- let values = config.values;
18
- let latestValues = new Map<string, PathValue>();
19
- for (let value of values) {
20
- let prev = latestValues.get(value.path);
21
- if (prev && compareTime(value.time, prev.time) < 0) continue;
22
- latestValues.set(value.path, value);
23
- }
24
-
25
- values = Array.from(latestValues.values());
26
- values = values.filter(x => !x.canGCValue);
27
-
28
- return {
29
- newValues: {
30
- "": values,
31
- },
32
- };
33
- },
34
- });
35
- }
36
-
37
- async function main() {
38
- disablePathAuditer();
39
- await Querysub.hostService("merge");
40
- await mergeFiles();
41
- process.exit();
42
-
43
- // while (true) {
44
- // await mergeFiles();
45
- // let delay = MERGE_DELAY * (1 + Math.random() * 0.1);
46
- // await new Promise(resolve => setTimeout(resolve, delay));
47
- // }
48
- }
49
-
50
- main().catch(logErrors);