@itwin/core-backend 5.14.0-dev.20 → 5.14.0-dev.22

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.
Files changed (51) hide show
  1. package/lib/cjs/ChangesetReader.d.ts +1 -1
  2. package/lib/cjs/ChangesetReader.js +2 -2
  3. package/lib/cjs/ChangesetReader.js.map +1 -1
  4. package/lib/cjs/ChangesetReaderTypes.d.ts +4 -1
  5. package/lib/cjs/ChangesetReaderTypes.d.ts.map +1 -1
  6. package/lib/cjs/ChangesetReaderTypes.js +3 -0
  7. package/lib/cjs/ChangesetReaderTypes.js.map +1 -1
  8. package/lib/cjs/ECDb.d.ts +11 -6
  9. package/lib/cjs/ECDb.d.ts.map +1 -1
  10. package/lib/cjs/ECDb.js +11 -6
  11. package/lib/cjs/ECDb.js.map +1 -1
  12. package/lib/cjs/ECSqlStatement.d.ts +2 -2
  13. package/lib/cjs/ECSqlStatement.js +2 -2
  14. package/lib/cjs/ECSqlStatement.js.map +1 -1
  15. package/lib/cjs/Element.d.ts.map +1 -1
  16. package/lib/cjs/Element.js +6 -3
  17. package/lib/cjs/Element.js.map +1 -1
  18. package/lib/cjs/IModelDb.d.ts +12 -10
  19. package/lib/cjs/IModelDb.d.ts.map +1 -1
  20. package/lib/cjs/IModelDb.js +19 -12
  21. package/lib/cjs/IModelDb.js.map +1 -1
  22. package/lib/esm/ChangesetReader.d.ts +1 -1
  23. package/lib/esm/ChangesetReader.js +2 -2
  24. package/lib/esm/ChangesetReader.js.map +1 -1
  25. package/lib/esm/ChangesetReaderTypes.d.ts +4 -1
  26. package/lib/esm/ChangesetReaderTypes.d.ts.map +1 -1
  27. package/lib/esm/ChangesetReaderTypes.js +3 -0
  28. package/lib/esm/ChangesetReaderTypes.js.map +1 -1
  29. package/lib/esm/ECDb.d.ts +11 -6
  30. package/lib/esm/ECDb.d.ts.map +1 -1
  31. package/lib/esm/ECDb.js +11 -6
  32. package/lib/esm/ECDb.js.map +1 -1
  33. package/lib/esm/ECSqlStatement.d.ts +2 -2
  34. package/lib/esm/ECSqlStatement.js +2 -2
  35. package/lib/esm/ECSqlStatement.js.map +1 -1
  36. package/lib/esm/Element.d.ts.map +1 -1
  37. package/lib/esm/Element.js +6 -3
  38. package/lib/esm/Element.js.map +1 -1
  39. package/lib/esm/IModelDb.d.ts +12 -10
  40. package/lib/esm/IModelDb.d.ts.map +1 -1
  41. package/lib/esm/IModelDb.js +19 -12
  42. package/lib/esm/IModelDb.js.map +1 -1
  43. package/lib/esm/test/ecdb/ConcurrentQuery.test.js +19 -2
  44. package/lib/esm/test/ecdb/ConcurrentQuery.test.js.map +1 -1
  45. package/lib/esm/test/ecdb/QueryReaders.test.js +105 -30
  46. package/lib/esm/test/ecdb/QueryReaders.test.js.map +1 -1
  47. package/lib/esm/test/imodel/IModelElements.test.js +5 -0
  48. package/lib/esm/test/imodel/IModelElements.test.js.map +1 -1
  49. package/lib/esm/test/standalone/ChangesetReader.test.js +111 -2
  50. package/lib/esm/test/standalone/ChangesetReader.test.js.map +1 -1
  51. package/package.json +14 -14
@@ -1,5 +1,6 @@
1
1
  import { DbResponseStatus } from "@itwin/core-common";
2
2
  import { expect } from "chai";
3
+ import * as os from "os";
3
4
  import { ConcurrentQuery } from "../../ConcurrentQuery";
4
5
  import { SnapshotDb } from "../../IModelDb";
5
6
  import { _nativeDb } from "../../core-backend";
@@ -9,6 +10,14 @@ async function delay(ms) {
9
10
  setTimeout(resolve, ms);
10
11
  });
11
12
  }
13
+ /**
14
+ * The native default for `workerThreads` is 4, capped at the machine's hardware concurrency
15
+ * (2-core CI agents report 2). An explicit request above hardware concurrency is rejected and
16
+ * falls back to that default rather than being clamped.
17
+ */
18
+ function defaultWorkerThreads() {
19
+ return Math.min(4, os.availableParallelism());
20
+ }
12
21
  describe("ConcurrentQuery", () => {
13
22
  it("default config", () => {
14
23
  const testFile = IModelTestUtils.resolveAssetFile("test.bim");
@@ -24,7 +33,7 @@ describe("ConcurrentQuery", () => {
24
33
  progressOpCount: 5000,
25
34
  requestQueueSize: 2000,
26
35
  statementCacheSizePerWorker: 40,
27
- workerThreads: 4,
36
+ workerThreads: defaultWorkerThreads(),
28
37
  };
29
38
  const config = ConcurrentQuery.resetConfig(db[_nativeDb], {});
30
39
  expect(config).deep.eq(defaultConfig);
@@ -44,12 +53,20 @@ describe("ConcurrentQuery", () => {
44
53
  progressOpCount: 6000,
45
54
  requestQueueSize: 1000,
46
55
  statementCacheSizePerWorker: 20,
47
- workerThreads: 3,
56
+ workerThreads: 1,
48
57
  };
49
58
  const config = ConcurrentQuery.resetConfig(db[_nativeDb], modifiedConfig);
50
59
  expect(config).deep.eq(modifiedConfig);
51
60
  db.close();
52
61
  });
62
+ it("workerThreads above hardware concurrency falls back to the default", () => {
63
+ const testFile = IModelTestUtils.resolveAssetFile("test.bim");
64
+ const db = SnapshotDb.openFile(testFile);
65
+ const requested = os.availableParallelism() + 8;
66
+ const config = ConcurrentQuery.resetConfig(db[_nativeDb], { workerThreads: requested });
67
+ expect(config.workerThreads).eq(defaultWorkerThreads());
68
+ db.close();
69
+ });
53
70
  it("time limit check", async () => {
54
71
  const testFile = IModelTestUtils.resolveAssetFile("test.bim");
55
72
  const db = SnapshotDb.openFile(testFile);
@@ -1 +1 @@
1
- {"version":3,"file":"ConcurrentQuery.test.js","sourceRoot":"","sources":["../../../../src/test/ecdb/ConcurrentQuery.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { DbQueryRequest, DbQueryResponse, DbResponseStatus } from \"@itwin/core-common\";\r\nimport { expect } from \"chai\";\r\nimport { ConcurrentQuery } from \"../../ConcurrentQuery\";\r\nimport { SnapshotDb } from \"../../IModelDb\";\r\nimport { _nativeDb } from \"../../core-backend\";\r\nimport { IModelTestUtils } from \"../IModelTestUtils\";\r\n\r\nasync function delay(ms: number): Promise<void> {\r\n return new Promise(resolve => {\r\n setTimeout(resolve, ms);\r\n });\r\n}\r\n\r\ndescribe(\"ConcurrentQuery\", () => {\r\n it(\"default config\", () => {\r\n const testFile = IModelTestUtils.resolveAssetFile(\"test.bim\");\r\n const db = SnapshotDb.openFile(testFile);\r\n const defaultConfig = {\r\n autoShutdownWhenIdleForSeconds: 1800,\r\n doNotUsePrimaryConnToPrepare: false,\r\n globalQuota: { time: 60, memory: 8388608 },\r\n ignoreDelay: true,\r\n ignorePriority: false,\r\n memoryMapFileSize: 0,\r\n monitorPollInterval: 5000,\r\n progressOpCount: 5000,\r\n requestQueueSize: 2000,\r\n statementCacheSizePerWorker: 40,\r\n workerThreads: 4,\r\n };\r\n const config = ConcurrentQuery.resetConfig(db[_nativeDb], {});\r\n expect(config).deep.eq(defaultConfig);\r\n db.close();\r\n });\r\n\r\n it(\"modify config\", () => {\r\n const testFile = IModelTestUtils.resolveAssetFile(\"test.bim\");\r\n const db = SnapshotDb.openFile(testFile);\r\n const modifiedConfig = {\r\n autoShutdownWhenIdleForSeconds: 100,\r\n doNotUsePrimaryConnToPrepare: true,\r\n globalQuota: { time: 10, memory: 1000000 },\r\n ignoreDelay: false,\r\n ignorePriority: true,\r\n memoryMapFileSize: 100,\r\n monitorPollInterval: 2000,\r\n progressOpCount: 6000,\r\n requestQueueSize: 1000,\r\n statementCacheSizePerWorker: 20,\r\n workerThreads: 3,\r\n };\r\n const config = ConcurrentQuery.resetConfig(db[_nativeDb], modifiedConfig);\r\n expect(config).deep.eq(modifiedConfig);\r\n db.close();\r\n });\r\n\r\n it(\"time limit check\", async () => {\r\n const testFile = IModelTestUtils.resolveAssetFile(\"test.bim\");\r\n const db = SnapshotDb.openFile(testFile);\r\n ConcurrentQuery.resetConfig(db[_nativeDb], { globalQuota: { time: 1, memory: 100000 }, progressOpCount: 1000 });\r\n // await runSingleRequest(db, `SELECT 1`);\r\n const req: DbQueryRequest = {\r\n query: `WITH sequence(n,k) AS (\r\n SELECT 1,1 UNION ALL SELECT n + 1, random() FROM sequence WHERE n < 10000000\r\n ) SELECT COUNT(*) FROM sequence s`\r\n };\r\n\r\n const resp = await ConcurrentQuery.executeQueryRequest(db[_nativeDb], req);\r\n expect(resp.status).equals(DbResponseStatus.Partial);\r\n expect(resp.stats.timeLimit).equals(1000);\r\n expect(resp.stats.memLimit).equals(100000);\r\n expect(resp.stats.cpuTime).to.be.closeTo(1000970, 500000);\r\n expect(resp.stats.totalTime).to.be.closeTo(1001, 100);\r\n expect(resp.stats.memUsed).to.be.closeTo(2, 3);\r\n // prepareTime varies on CI: the first query prepares against the (cold) shared schema-source\r\n // connection, so assert only that it is negligible relative to the ~1000ms execution rather than\r\n // pinning it to a tight tolerance (which flakes -- e.g. observed 7ms against a 0 +/- 4 bound).\r\n expect(resp.stats.prepareTime).to.be.lessThan(100);\r\n db.close();\r\n });\r\n\r\n it(\"memory limit check\", async () => {\r\n const testFile = IModelTestUtils.resolveAssetFile(\"test.bim\");\r\n const db = SnapshotDb.openFile(testFile);\r\n ConcurrentQuery.resetConfig(db[_nativeDb], { globalQuota: { time: 60, memory: 1000 }, progressOpCount: 1000 });\r\n // await runSingleRequest(db, `SELECT 1`);\r\n const req: DbQueryRequest = {\r\n query: `WITH sequence(n) AS (\r\n SELECT 1\r\n UNION ALL\r\n SELECT n + 1 FROM sequence WHERE n < 10000000\r\n )\r\n SELECT 'xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx' FROM sequence s`\r\n };\r\n\r\n const resp = await ConcurrentQuery.executeQueryRequest(db[_nativeDb], req);\r\n expect(resp.status).equals(DbResponseStatus.Partial);\r\n expect(resp.stats.timeLimit).equals(60000);\r\n expect(resp.stats.memLimit).equals(1000);\r\n expect(resp.stats.memUsed).to.be.closeTo(1037, 100);\r\n db.close();\r\n });\r\n\r\n it(\"prepare error\", async () => {\r\n const testFile = IModelTestUtils.resolveAssetFile(\"test.bim\");\r\n const db = SnapshotDb.openFile(testFile);\r\n const req: DbQueryRequest = {\r\n query: `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\r\n };\r\n\r\n const resp = await ConcurrentQuery.executeQueryRequest(db[_nativeDb], req);\r\n expect(resp.status).equals(DbResponseStatus.Error_ECSql_PreparedFailed);\r\n db.close();\r\n });\r\n\r\n it.skip(\"restart query #flaky\", async () => {\r\n const testFile = IModelTestUtils.resolveAssetFile(\"test.bim\");\r\n const db = SnapshotDb.openFile(testFile);\r\n ConcurrentQuery.resetConfig(db[_nativeDb], { globalQuota: { time: 60, memory: 10000000 }, progressOpCount: 1000 });\r\n const req0: DbQueryRequest = {\r\n query: `WITH sequence(n) AS (\r\n SELECT 1 UNION ALL SELECT n + 1 FROM sequence WHERE n < 10000000\r\n ) SELECT n FROM sequence s`,\r\n restartToken: \"Blah\",\r\n };\r\n\r\n const req1: DbQueryRequest = {\r\n query: `WITH sequence(n) AS (\r\n SELECT 1 UNION ALL SELECT n + 1 FROM sequence WHERE n < 1000\r\n ) SELECT n FROM sequence s`,\r\n restartToken: \"Blah\",\r\n };\r\n\r\n const resp1 = ConcurrentQuery.executeQueryRequest(db[_nativeDb], req0);\r\n await delay(1);\r\n const resp2 = ConcurrentQuery.executeQueryRequest(db[_nativeDb], req1);\r\n const resp = await Promise.all([resp1, resp2]);\r\n expect(resp[0].status).equals(DbResponseStatus.Cancel); // can result in DbResponseStatus.Partial instead of DbResponseStatus.Cancel\r\n expect(resp[1].status).equals(DbResponseStatus.Done);\r\n db.close();\r\n });\r\n\r\n it(\"queue limit check\", async () => {\r\n const testFile = IModelTestUtils.resolveAssetFile(\"test.bim\");\r\n const db = SnapshotDb.openFile(testFile);\r\n ConcurrentQuery.resetConfig(db[_nativeDb], { requestQueueSize: 40, globalQuota: { time: 5, memory: 100000 } });\r\n const req: DbQueryRequest = {\r\n query: `WITH sequence(n) AS (\r\n SELECT 1 UNION ALL SELECT n + 1 FROM sequence WHERE n < 10000000\r\n ) SELECT n FROM sequence s`,\r\n };\r\n\r\n const responsePromises: Promise<DbQueryResponse>[] = [];\r\n for (let i = 0; i < 60; ++i) {\r\n responsePromises.push(ConcurrentQuery.executeQueryRequest(db[_nativeDb], req));\r\n }\r\n const responses = await Promise.all(responsePromises);\r\n const queueResponses = Array.from(responses.filter((x) => x.status === DbResponseStatus.QueueFull));\r\n expect(queueResponses.length).to.be.greaterThanOrEqual(10);\r\n db.close();\r\n });\r\n\r\n it(\"timeout check\", async () => {\r\n const testFile = IModelTestUtils.resolveAssetFile(\"test.bim\");\r\n const db = SnapshotDb.openFile(testFile);\r\n ConcurrentQuery.resetConfig(db[_nativeDb], { monitorPollInterval: 1, globalQuota: { time: 5, memory: 10000000 } });\r\n const req: DbQueryRequest = {\r\n query: `WITH sequence(n) AS (\r\n SELECT 1 UNION ALL SELECT n + 1 FROM sequence WHERE n < 10000000\r\n ) SELECT n FROM sequence s`,\r\n };\r\n\r\n const responsePromises: Promise<DbQueryResponse>[] = [];\r\n for (let i = 0; i < 100; ++i) {\r\n responsePromises.push(ConcurrentQuery.executeQueryRequest(db[_nativeDb], req));\r\n }\r\n const responses = await Promise.all(responsePromises);\r\n const queueResponses = Array.from(responses.filter((x) => x.status === DbResponseStatus.Timeout));\r\n expect(queueResponses.length).to.be.greaterThanOrEqual(10);\r\n db.close();\r\n });\r\n\r\n it(\"should handle concurrent queries during shutdown without deadlock\", async () => {\r\n const testFile = IModelTestUtils.resolveAssetFile(\"test.bim\");\r\n const iModelDb = SnapshotDb.openFile(testFile);\r\n // Configure for maximum contention\r\n const config = {\r\n requestQueueSize: 1000,\r\n statementCacheSizePerWorker: 1, // Force frequent prepare calls\r\n };\r\n\r\n // Reset configuration\r\n ConcurrentQuery.resetConfig(iModelDb[_nativeDb], config);\r\n\r\n const responsePromises: Promise<DbQueryResponse>[] = [];\r\n const spamPromises: Promise<void>[] = [];\r\n let shouldStop = false;\r\n\r\n const spam = async () => {\r\n while (!shouldStop) {\r\n // Use random numbers to prevent query caching\r\n const query = `\r\n WITH sequence(n,k) AS (\r\n SELECT 1,1 UNION ALL SELECT n + 1, random() FROM sequence WHERE n < 10000000\r\n ) SELECT COUNT(*) FROM sequence s\r\n `;\r\n const request: DbQueryRequest = { query };\r\n const p = ConcurrentQuery.executeQueryRequest(iModelDb[_nativeDb], request);\r\n responsePromises.push(p);\r\n await new Promise(resolve => setImmediate(resolve));\r\n }\r\n };\r\n\r\n // Start spamming simple queries to increase contention\r\n spamPromises.push(spam());\r\n // Let queries start and establish contention\r\n await new Promise(resolve => setTimeout(resolve, 10));\r\n\r\n ConcurrentQuery.shutdown(iModelDb[_nativeDb]);\r\n\r\n shouldStop = true;\r\n\r\n // Wait for all promises to complete\r\n const results = await Promise.allSettled(responsePromises);\r\n await Promise.allSettled(spamPromises);\r\n\r\n const satisfiesShutDownResponse = results.some((result) => result.status === \"fulfilled\" && result.value.status === DbResponseStatus.ShuttingDown);\r\n\r\n expect(satisfiesShutDownResponse).to.be.true; // some queries should face shutdown\r\n\r\n // Restore original config by resetting to default\r\n ConcurrentQuery.resetConfig(iModelDb[_nativeDb], {});\r\n iModelDb.close();\r\n });\r\n});\r\n"]}
1
+ {"version":3,"file":"ConcurrentQuery.test.js","sourceRoot":"","sources":["../../../../src/test/ecdb/ConcurrentQuery.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmC,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACvF,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAC9B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAErD,KAAK,UAAU,KAAK,CAAC,EAAU;IAC7B,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE;QAC3B,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,SAAS,oBAAoB;IAC3B,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,oBAAoB,EAAE,CAAC,CAAC;AAChD,CAAC;AAED,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,EAAE,CAAC,gBAAgB,EAAE,GAAG,EAAE;QACxB,MAAM,QAAQ,GAAG,eAAe,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;QAC9D,MAAM,EAAE,GAAG,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACzC,MAAM,aAAa,GAAG;YACpB,8BAA8B,EAAE,IAAI;YACpC,4BAA4B,EAAE,KAAK;YACnC,WAAW,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE;YAC1C,WAAW,EAAE,IAAI;YACjB,cAAc,EAAE,KAAK;YACrB,iBAAiB,EAAE,CAAC;YACpB,mBAAmB,EAAE,IAAI;YACzB,eAAe,EAAE,IAAI;YACrB,gBAAgB,EAAE,IAAI;YACtB,2BAA2B,EAAE,EAAE;YAC/B,aAAa,EAAE,oBAAoB,EAAE;SACtC,CAAC;QACF,MAAM,MAAM,GAAG,eAAe,CAAC,WAAW,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,CAAC,CAAC;QAC9D,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC;QACtC,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,eAAe,EAAE,GAAG,EAAE;QACvB,MAAM,QAAQ,GAAG,eAAe,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;QAC9D,MAAM,EAAE,GAAG,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACzC,MAAM,cAAc,GAAG;YACrB,8BAA8B,EAAE,GAAG;YACnC,4BAA4B,EAAE,IAAI;YAClC,WAAW,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE;YAC1C,WAAW,EAAE,KAAK;YAClB,cAAc,EAAE,IAAI;YACpB,iBAAiB,EAAE,GAAG;YACtB,mBAAmB,EAAE,IAAI;YACzB,eAAe,EAAE,IAAI;YACrB,gBAAgB,EAAE,IAAI;YACtB,2BAA2B,EAAE,EAAE;YAC/B,aAAa,EAAE,CAAC;SACjB,CAAC;QACF,MAAM,MAAM,GAAG,eAAe,CAAC,WAAW,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,cAAc,CAAC,CAAC;QAC1E,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,cAAc,CAAC,CAAC;QACvC,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oEAAoE,EAAE,GAAG,EAAE;QAC5E,MAAM,QAAQ,GAAG,eAAe,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;QAC9D,MAAM,EAAE,GAAG,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACzC,MAAM,SAAS,GAAG,EAAE,CAAC,oBAAoB,EAAE,GAAG,CAAC,CAAC;QAChD,MAAM,MAAM,GAAG,eAAe,CAAC,WAAW,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,aAAa,EAAE,SAAS,EAAE,CAAC,CAAC;QACxF,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,oBAAoB,EAAE,CAAC,CAAC;QACxD,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kBAAkB,EAAE,KAAK,IAAI,EAAE;QAChC,MAAM,QAAQ,GAAG,eAAe,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;QAC9D,MAAM,EAAE,GAAG,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACzC,eAAe,CAAC,WAAW,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,CAAC;QAChH,0CAA0C;QAC1C,MAAM,GAAG,GAAmB;YAC1B,KAAK,EAAE;;gDAEmC;SAC3C,CAAC;QAEF,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,mBAAmB,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,GAAG,CAAC,CAAC;QAC3E,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;QACrD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC1C,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC3C,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC1D,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QACtD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC/C,6FAA6F;QAC7F,iGAAiG;QACjG,+FAA+F;QAC/F,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QACnD,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oBAAoB,EAAE,KAAK,IAAI,EAAE;QAClC,MAAM,QAAQ,GAAG,eAAe,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;QAC9D,MAAM,EAAE,GAAG,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACzC,eAAe,CAAC,WAAW,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/G,0CAA0C;QAC1C,MAAM,GAAG,GAAmB;YAC1B,KAAK,EAAE;;;;;wEAK2D;SACnE,CAAC;QAEF,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,mBAAmB,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,GAAG,CAAC,CAAC;QAC3E,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;QACrD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC3C,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACzC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QACpD,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,eAAe,EAAE,KAAK,IAAI,EAAE;QAC7B,MAAM,QAAQ,GAAG,eAAe,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;QAC9D,MAAM,EAAE,GAAG,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACzC,MAAM,GAAG,GAAmB;YAC1B,KAAK,EAAE,gCAAgC;SACxC,CAAC;QAEF,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,mBAAmB,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,GAAG,CAAC,CAAC;QAC3E,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,0BAA0B,CAAC,CAAC;QACxE,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,IAAI,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;QACzC,MAAM,QAAQ,GAAG,eAAe,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;QAC9D,MAAM,EAAE,GAAG,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACzC,eAAe,CAAC,WAAW,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,CAAC;QACnH,MAAM,IAAI,GAAmB;YAC3B,KAAK,EAAE;;yCAE4B;YACnC,YAAY,EAAE,MAAM;SACrB,CAAC;QAEF,MAAM,IAAI,GAAmB;YAC3B,KAAK,EAAE;;yCAE4B;YACnC,YAAY,EAAE,MAAM;SACrB,CAAC;QAEF,MAAM,KAAK,GAAG,eAAe,CAAC,mBAAmB,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC,CAAC;QACvE,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;QACf,MAAM,KAAK,GAAG,eAAe,CAAC,mBAAmB,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC,CAAC;QACvE,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;QAC/C,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,4EAA4E;QACpI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;QACrD,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mBAAmB,EAAE,KAAK,IAAI,EAAE;QACjC,MAAM,QAAQ,GAAG,eAAe,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;QAC9D,MAAM,EAAE,GAAG,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACzC,eAAe,CAAC,WAAW,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,gBAAgB,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;QAC/G,MAAM,GAAG,GAAmB;YAC1B,KAAK,EAAE;;yCAE4B;SACpC,CAAC;QAEF,MAAM,gBAAgB,GAA+B,EAAE,CAAC;QACxD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC;YAC5B,gBAAgB,CAAC,IAAI,CAAC,eAAe,CAAC,mBAAmB,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;QACjF,CAAC;QACD,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;QACtD,MAAM,cAAc,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAC;QACpG,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC;QAC3D,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,eAAe,EAAE,KAAK,IAAI,EAAE;QAC7B,MAAM,QAAQ,GAAG,eAAe,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;QAC9D,MAAM,EAAE,GAAG,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACzC,eAAe,CAAC,WAAW,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,mBAAmB,EAAE,CAAC,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;QACnH,MAAM,GAAG,GAAmB;YAC1B,KAAK,EAAE;;yCAE4B;SACpC,CAAC;QAEF,MAAM,gBAAgB,GAA+B,EAAE,CAAC;QACxD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC;YAC7B,gBAAgB,CAAC,IAAI,CAAC,eAAe,CAAC,mBAAmB,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;QACjF,CAAC;QACD,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;QACtD,MAAM,cAAc,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC;QAClG,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC;QAC3D,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mEAAmE,EAAE,KAAK,IAAI,EAAE;QACjF,MAAM,QAAQ,GAAG,eAAe,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;QAC9D,MAAM,QAAQ,GAAG,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAC/C,mCAAmC;QACnC,MAAM,MAAM,GAAG;YACb,gBAAgB,EAAE,IAAI;YACtB,2BAA2B,EAAE,CAAC,EAAE,+BAA+B;SAChE,CAAC;QAEF,sBAAsB;QACtB,eAAe,CAAC,WAAW,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC,CAAC;QAEzD,MAAM,gBAAgB,GAA+B,EAAE,CAAC;QACxD,MAAM,YAAY,GAAoB,EAAE,CAAC;QACzC,IAAI,UAAU,GAAG,KAAK,CAAC;QAEvB,MAAM,IAAI,GAAG,KAAK,IAAI,EAAE;YACtB,OAAO,CAAC,UAAU,EAAE,CAAC;gBACnB,8CAA8C;gBAC9C,MAAM,KAAK,GAAG;;;;WAIX,CAAC;gBACJ,MAAM,OAAO,GAAmB,EAAE,KAAK,EAAE,CAAC;gBAC1C,MAAM,CAAC,GAAG,eAAe,CAAC,mBAAmB,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,CAAC;gBAC5E,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBACzB,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;YACtD,CAAC;QACH,CAAC,CAAC;QAEF,uDAAuD;QACvD,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAC1B,6CAA6C;QAC7C,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;QAEtD,eAAe,CAAC,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;QAE9C,UAAU,GAAG,IAAI,CAAC;QAElB,oCAAoC;QACpC,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;QAC3D,MAAM,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;QAEvC,MAAM,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,KAAK,WAAW,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,gBAAgB,CAAC,YAAY,CAAC,CAAC;QAEnJ,MAAM,CAAC,yBAAyB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,oCAAoC;QAElF,kDAAkD;QAClD,eAAe,CAAC,WAAW,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,EAAE,CAAC,CAAC;QACrD,QAAQ,CAAC,KAAK,EAAE,CAAC;IACnB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { DbQueryRequest, DbQueryResponse, DbResponseStatus } from \"@itwin/core-common\";\r\nimport { expect } from \"chai\";\r\nimport * as os from \"os\";\r\nimport { ConcurrentQuery } from \"../../ConcurrentQuery\";\r\nimport { SnapshotDb } from \"../../IModelDb\";\r\nimport { _nativeDb } from \"../../core-backend\";\r\nimport { IModelTestUtils } from \"../IModelTestUtils\";\r\n\r\nasync function delay(ms: number): Promise<void> {\r\n return new Promise(resolve => {\r\n setTimeout(resolve, ms);\r\n });\r\n}\r\n\r\n/**\r\n * The native default for `workerThreads` is 4, capped at the machine's hardware concurrency\r\n * (2-core CI agents report 2). An explicit request above hardware concurrency is rejected and\r\n * falls back to that default rather than being clamped.\r\n */\r\nfunction defaultWorkerThreads(): number {\r\n return Math.min(4, os.availableParallelism());\r\n}\r\n\r\ndescribe(\"ConcurrentQuery\", () => {\r\n it(\"default config\", () => {\r\n const testFile = IModelTestUtils.resolveAssetFile(\"test.bim\");\r\n const db = SnapshotDb.openFile(testFile);\r\n const defaultConfig = {\r\n autoShutdownWhenIdleForSeconds: 1800,\r\n doNotUsePrimaryConnToPrepare: false,\r\n globalQuota: { time: 60, memory: 8388608 },\r\n ignoreDelay: true,\r\n ignorePriority: false,\r\n memoryMapFileSize: 0,\r\n monitorPollInterval: 5000,\r\n progressOpCount: 5000,\r\n requestQueueSize: 2000,\r\n statementCacheSizePerWorker: 40,\r\n workerThreads: defaultWorkerThreads(),\r\n };\r\n const config = ConcurrentQuery.resetConfig(db[_nativeDb], {});\r\n expect(config).deep.eq(defaultConfig);\r\n db.close();\r\n });\r\n\r\n it(\"modify config\", () => {\r\n const testFile = IModelTestUtils.resolveAssetFile(\"test.bim\");\r\n const db = SnapshotDb.openFile(testFile);\r\n const modifiedConfig = {\r\n autoShutdownWhenIdleForSeconds: 100,\r\n doNotUsePrimaryConnToPrepare: true,\r\n globalQuota: { time: 10, memory: 1000000 },\r\n ignoreDelay: false,\r\n ignorePriority: true,\r\n memoryMapFileSize: 100,\r\n monitorPollInterval: 2000,\r\n progressOpCount: 6000,\r\n requestQueueSize: 1000,\r\n statementCacheSizePerWorker: 20,\r\n workerThreads: 1,\r\n };\r\n const config = ConcurrentQuery.resetConfig(db[_nativeDb], modifiedConfig);\r\n expect(config).deep.eq(modifiedConfig);\r\n db.close();\r\n });\r\n\r\n it(\"workerThreads above hardware concurrency falls back to the default\", () => {\r\n const testFile = IModelTestUtils.resolveAssetFile(\"test.bim\");\r\n const db = SnapshotDb.openFile(testFile);\r\n const requested = os.availableParallelism() + 8;\r\n const config = ConcurrentQuery.resetConfig(db[_nativeDb], { workerThreads: requested });\r\n expect(config.workerThreads).eq(defaultWorkerThreads());\r\n db.close();\r\n });\r\n\r\n it(\"time limit check\", async () => {\r\n const testFile = IModelTestUtils.resolveAssetFile(\"test.bim\");\r\n const db = SnapshotDb.openFile(testFile);\r\n ConcurrentQuery.resetConfig(db[_nativeDb], { globalQuota: { time: 1, memory: 100000 }, progressOpCount: 1000 });\r\n // await runSingleRequest(db, `SELECT 1`);\r\n const req: DbQueryRequest = {\r\n query: `WITH sequence(n,k) AS (\r\n SELECT 1,1 UNION ALL SELECT n + 1, random() FROM sequence WHERE n < 10000000\r\n ) SELECT COUNT(*) FROM sequence s`\r\n };\r\n\r\n const resp = await ConcurrentQuery.executeQueryRequest(db[_nativeDb], req);\r\n expect(resp.status).equals(DbResponseStatus.Partial);\r\n expect(resp.stats.timeLimit).equals(1000);\r\n expect(resp.stats.memLimit).equals(100000);\r\n expect(resp.stats.cpuTime).to.be.closeTo(1000970, 500000);\r\n expect(resp.stats.totalTime).to.be.closeTo(1001, 100);\r\n expect(resp.stats.memUsed).to.be.closeTo(2, 3);\r\n // prepareTime varies on CI: the first query prepares against the (cold) shared schema-source\r\n // connection, so assert only that it is negligible relative to the ~1000ms execution rather than\r\n // pinning it to a tight tolerance (which flakes -- e.g. observed 7ms against a 0 +/- 4 bound).\r\n expect(resp.stats.prepareTime).to.be.lessThan(100);\r\n db.close();\r\n });\r\n\r\n it(\"memory limit check\", async () => {\r\n const testFile = IModelTestUtils.resolveAssetFile(\"test.bim\");\r\n const db = SnapshotDb.openFile(testFile);\r\n ConcurrentQuery.resetConfig(db[_nativeDb], { globalQuota: { time: 60, memory: 1000 }, progressOpCount: 1000 });\r\n // await runSingleRequest(db, `SELECT 1`);\r\n const req: DbQueryRequest = {\r\n query: `WITH sequence(n) AS (\r\n SELECT 1\r\n UNION ALL\r\n SELECT n + 1 FROM sequence WHERE n < 10000000\r\n )\r\n SELECT 'xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx' FROM sequence s`\r\n };\r\n\r\n const resp = await ConcurrentQuery.executeQueryRequest(db[_nativeDb], req);\r\n expect(resp.status).equals(DbResponseStatus.Partial);\r\n expect(resp.stats.timeLimit).equals(60000);\r\n expect(resp.stats.memLimit).equals(1000);\r\n expect(resp.stats.memUsed).to.be.closeTo(1037, 100);\r\n db.close();\r\n });\r\n\r\n it(\"prepare error\", async () => {\r\n const testFile = IModelTestUtils.resolveAssetFile(\"test.bim\");\r\n const db = SnapshotDb.openFile(testFile);\r\n const req: DbQueryRequest = {\r\n query: `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`\r\n };\r\n\r\n const resp = await ConcurrentQuery.executeQueryRequest(db[_nativeDb], req);\r\n expect(resp.status).equals(DbResponseStatus.Error_ECSql_PreparedFailed);\r\n db.close();\r\n });\r\n\r\n it.skip(\"restart query #flaky\", async () => {\r\n const testFile = IModelTestUtils.resolveAssetFile(\"test.bim\");\r\n const db = SnapshotDb.openFile(testFile);\r\n ConcurrentQuery.resetConfig(db[_nativeDb], { globalQuota: { time: 60, memory: 10000000 }, progressOpCount: 1000 });\r\n const req0: DbQueryRequest = {\r\n query: `WITH sequence(n) AS (\r\n SELECT 1 UNION ALL SELECT n + 1 FROM sequence WHERE n < 10000000\r\n ) SELECT n FROM sequence s`,\r\n restartToken: \"Blah\",\r\n };\r\n\r\n const req1: DbQueryRequest = {\r\n query: `WITH sequence(n) AS (\r\n SELECT 1 UNION ALL SELECT n + 1 FROM sequence WHERE n < 1000\r\n ) SELECT n FROM sequence s`,\r\n restartToken: \"Blah\",\r\n };\r\n\r\n const resp1 = ConcurrentQuery.executeQueryRequest(db[_nativeDb], req0);\r\n await delay(1);\r\n const resp2 = ConcurrentQuery.executeQueryRequest(db[_nativeDb], req1);\r\n const resp = await Promise.all([resp1, resp2]);\r\n expect(resp[0].status).equals(DbResponseStatus.Cancel); // can result in DbResponseStatus.Partial instead of DbResponseStatus.Cancel\r\n expect(resp[1].status).equals(DbResponseStatus.Done);\r\n db.close();\r\n });\r\n\r\n it(\"queue limit check\", async () => {\r\n const testFile = IModelTestUtils.resolveAssetFile(\"test.bim\");\r\n const db = SnapshotDb.openFile(testFile);\r\n ConcurrentQuery.resetConfig(db[_nativeDb], { requestQueueSize: 40, globalQuota: { time: 5, memory: 100000 } });\r\n const req: DbQueryRequest = {\r\n query: `WITH sequence(n) AS (\r\n SELECT 1 UNION ALL SELECT n + 1 FROM sequence WHERE n < 10000000\r\n ) SELECT n FROM sequence s`,\r\n };\r\n\r\n const responsePromises: Promise<DbQueryResponse>[] = [];\r\n for (let i = 0; i < 60; ++i) {\r\n responsePromises.push(ConcurrentQuery.executeQueryRequest(db[_nativeDb], req));\r\n }\r\n const responses = await Promise.all(responsePromises);\r\n const queueResponses = Array.from(responses.filter((x) => x.status === DbResponseStatus.QueueFull));\r\n expect(queueResponses.length).to.be.greaterThanOrEqual(10);\r\n db.close();\r\n });\r\n\r\n it(\"timeout check\", async () => {\r\n const testFile = IModelTestUtils.resolveAssetFile(\"test.bim\");\r\n const db = SnapshotDb.openFile(testFile);\r\n ConcurrentQuery.resetConfig(db[_nativeDb], { monitorPollInterval: 1, globalQuota: { time: 5, memory: 10000000 } });\r\n const req: DbQueryRequest = {\r\n query: `WITH sequence(n) AS (\r\n SELECT 1 UNION ALL SELECT n + 1 FROM sequence WHERE n < 10000000\r\n ) SELECT n FROM sequence s`,\r\n };\r\n\r\n const responsePromises: Promise<DbQueryResponse>[] = [];\r\n for (let i = 0; i < 100; ++i) {\r\n responsePromises.push(ConcurrentQuery.executeQueryRequest(db[_nativeDb], req));\r\n }\r\n const responses = await Promise.all(responsePromises);\r\n const queueResponses = Array.from(responses.filter((x) => x.status === DbResponseStatus.Timeout));\r\n expect(queueResponses.length).to.be.greaterThanOrEqual(10);\r\n db.close();\r\n });\r\n\r\n it(\"should handle concurrent queries during shutdown without deadlock\", async () => {\r\n const testFile = IModelTestUtils.resolveAssetFile(\"test.bim\");\r\n const iModelDb = SnapshotDb.openFile(testFile);\r\n // Configure for maximum contention\r\n const config = {\r\n requestQueueSize: 1000,\r\n statementCacheSizePerWorker: 1, // Force frequent prepare calls\r\n };\r\n\r\n // Reset configuration\r\n ConcurrentQuery.resetConfig(iModelDb[_nativeDb], config);\r\n\r\n const responsePromises: Promise<DbQueryResponse>[] = [];\r\n const spamPromises: Promise<void>[] = [];\r\n let shouldStop = false;\r\n\r\n const spam = async () => {\r\n while (!shouldStop) {\r\n // Use random numbers to prevent query caching\r\n const query = `\r\n WITH sequence(n,k) AS (\r\n SELECT 1,1 UNION ALL SELECT n + 1, random() FROM sequence WHERE n < 10000000\r\n ) SELECT COUNT(*) FROM sequence s\r\n `;\r\n const request: DbQueryRequest = { query };\r\n const p = ConcurrentQuery.executeQueryRequest(iModelDb[_nativeDb], request);\r\n responsePromises.push(p);\r\n await new Promise(resolve => setImmediate(resolve));\r\n }\r\n };\r\n\r\n // Start spamming simple queries to increase contention\r\n spamPromises.push(spam());\r\n // Let queries start and establish contention\r\n await new Promise(resolve => setTimeout(resolve, 10));\r\n\r\n ConcurrentQuery.shutdown(iModelDb[_nativeDb]);\r\n\r\n shouldStop = true;\r\n\r\n // Wait for all promises to complete\r\n const results = await Promise.allSettled(responsePromises);\r\n await Promise.allSettled(spamPromises);\r\n\r\n const satisfiesShutDownResponse = results.some((result) => result.status === \"fulfilled\" && result.value.status === DbResponseStatus.ShuttingDown);\r\n\r\n expect(satisfiesShutDownResponse).to.be.true; // some queries should face shutdown\r\n\r\n // Restore original config by resetting to default\r\n ConcurrentQuery.resetConfig(iModelDb[_nativeDb], {});\r\n iModelDb.close();\r\n });\r\n});\r\n"]}
@@ -75,12 +75,87 @@ describe("QueryReaders - createQueryReader() and withQueryReader() api tests", (
75
75
  after(async () => {
76
76
  iModel.close();
77
77
  });
78
+ it("formats blob results", async () => {
79
+ const env_1 = { stack: [], error: void 0, hasError: false };
80
+ try {
81
+ const ecdb = __addDisposableResource(env_1, ECDbTestHelper.createECDb(KnownTestLocations.outputDir, "ecsql-reader-blobs.ecdb", `<?xml version="1.0" encoding="utf-8"?>
82
+ <ECSchema schemaName="MySchema" alias="myschema" version="01.00.00" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.2">
83
+ <ECEntityClass typeName="BlobExample">
84
+ <ECProperty propertyName="Data" typeName="binary" />
85
+ </ECEntityClass>
86
+ </ECSchema>`), false);
87
+ const blob = new Uint8Array([1, 2, 3]);
88
+ const insertStatus = ecdb.withWriteStatement("INSERT INTO myschema.BlobExample(Data) VALUES(?)", (stmt) => {
89
+ stmt.bindBlob(1, blob);
90
+ return stmt.step();
91
+ });
92
+ assert.equal(insertStatus, DbResult.BE_SQLITE_DONE);
93
+ ecdb.saveChanges();
94
+ for (const abbreviateBlobs of [undefined, false, true]) {
95
+ const query = "SELECT Data FROM myschema.BlobExample";
96
+ const expected = abbreviateBlobs ? '{"bytes":3}' : blob;
97
+ const asyncRows = await ecdb.createQueryReader(query, undefined, { abbreviateBlobs }).toArray();
98
+ const syncRows = ecdb.withQueryReader(query, (reader) => reader.toArray(), undefined, { abbreviateBlobs });
99
+ assert.deepEqual(asyncRows, [[expected]]);
100
+ assert.deepEqual(syncRows, [[expected]]);
101
+ }
102
+ }
103
+ catch (e_1) {
104
+ env_1.error = e_1;
105
+ env_1.hasError = true;
106
+ }
107
+ finally {
108
+ __disposeResources(env_1);
109
+ }
110
+ });
111
+ it("preserves row formats and bindings", async () => {
112
+ const rootSelect = "SELECT ECInstanceId, ECClassId FROM bis.Element WHERE ECInstanceId=?";
113
+ const asyncIndexRows = await iModel.createQueryReader(rootSelect, new QueryBinder().bindId(1, "0x1")).toArray();
114
+ assert.isArray(asyncIndexRows[0]);
115
+ assert.equal(asyncIndexRows[0][0], "0x1");
116
+ assert.isTrue(Id64.isValidId64(asyncIndexRows[0][1]));
117
+ const asyncECSqlNameRows = await iModel.createQueryReader(rootSelect, new QueryBinder().bindId(1, "0x1"), { rowFormat: QueryRowFormat.UseECSqlPropertyNames }).toArray();
118
+ assert.equal(asyncECSqlNameRows[0].ECInstanceId, "0x1");
119
+ assert.isTrue(Id64.isValidId64(asyncECSqlNameRows[0].ECClassId));
120
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
121
+ const asyncJsNameRows = await iModel.createQueryReader(rootSelect, new QueryBinder().bindId(1, "0x1"), { rowFormat: QueryRowFormat.UseJsPropertyNames }).toArray();
122
+ assert.equal(asyncJsNameRows[0].id, "0x1");
123
+ assert.equal(asyncJsNameRows[0].className, "BisCore.Subject");
124
+ const syncIndexRows = iModel.withQueryReader(rootSelect, (reader) => reader.toArray(), new QueryBinder().bindId(1, "0x1"));
125
+ assert.isArray(syncIndexRows[0]);
126
+ assert.equal(syncIndexRows[0][0], "0x1");
127
+ assert.isTrue(Id64.isValidId64(syncIndexRows[0][1]));
128
+ const syncECSqlNameRows = iModel.withQueryReader(rootSelect, (reader) => reader.toArray(), new QueryBinder().bindId(1, "0x1"), { rowFormat: QueryRowFormat.UseECSqlPropertyNames });
129
+ assert.equal(syncECSqlNameRows[0].ECInstanceId, "0x1");
130
+ assert.isTrue(Id64.isValidId64(syncECSqlNameRows[0].ECClassId));
131
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
132
+ const syncJsNameRows = iModel.withQueryReader(rootSelect, (reader) => reader.toArray(), new QueryBinder().bindId(1, "0x1"), { rowFormat: QueryRowFormat.UseJsPropertyNames });
133
+ assert.equal(syncJsNameRows[0].id, "0x1");
134
+ assert.equal(syncJsNameRows[0].className, "BisCore.Subject");
135
+ const asyncReader = iModel.createQueryReader(rootSelect, new QueryBinder().bindId(1, "0x1"));
136
+ assert.isTrue(await asyncReader.step());
137
+ const asyncObjectRow = asyncReader.current.toRow();
138
+ assert.isFalse(Array.isArray(asyncObjectRow));
139
+ assert.equal(asyncObjectRow.ECInstanceId, "0x1");
140
+ const objectRow = iModel.withQueryReader(rootSelect, (reader) => {
141
+ assert.isTrue(reader.step());
142
+ return reader.current.toRow();
143
+ }, new QueryBinder().bindId(1, "0x1"));
144
+ assert.isObject(objectRow);
145
+ assert.equal(objectRow.ECInstanceId, "0x1");
146
+ const arrayRows = iModel.withQueryReader(rootSelect, (reader) => reader.toArray(), new QueryBinder().bindId(1, "0x1"));
147
+ assert.isArray(arrayRows[0]);
148
+ const idSetRows = await iModel.createQueryReader("SELECT ECInstanceId FROM bis.Element WHERE InVirtualSet(?, ECInstanceId)", new QueryBinder().bindIdSet(1, ["0x1", "0x2"])).toArray();
149
+ assert.isTrue(idSetRows.some((row) => row[0] === "0x1"));
150
+ const syncIdSetRows = iModel.withQueryReader("SELECT ECInstanceId FROM bis.Element WHERE InVirtualSet(?, ECInstanceId)", (reader) => reader.toArray(), new QueryBinder().bindIdSet(1, ["0x1", "0x2"]));
151
+ assert.sameDeepMembers(syncIdSetRows, idSetRows);
152
+ });
78
153
  describe("bind Id64 enumerable", async () => {
79
154
  const outDir = KnownTestLocations.outputDir;
80
155
  it("ecsql reader simple", async () => {
81
- const env_1 = { stack: [], error: void 0, hasError: false };
156
+ const env_2 = { stack: [], error: void 0, hasError: false };
82
157
  try {
83
- const ecdb = __addDisposableResource(env_1, ECDbTestHelper.createECDb(outDir, "test.ecdb", `<ECSchema schemaName="Test" alias="ts" version="01.00.00" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.2">
158
+ const ecdb = __addDisposableResource(env_2, ECDbTestHelper.createECDb(outDir, "test.ecdb", `<ECSchema schemaName="Test" alias="ts" version="01.00.00" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.2">
84
159
  <ECEntityClass typeName="Foo" modifier="Sealed">
85
160
  <ECProperty propertyName="n" typeName="int"/>
86
161
  </ECEntityClass>
@@ -106,18 +181,18 @@ describe("QueryReaders - createQueryReader() and withQueryReader() api tests", (
106
181
  const reader = ecdb.createQueryReader("SELECT ECInstanceId, Name FROM meta.ECClassDef WHERE InVirtualSet(?, ECInstanceId)", params, optionBuilder.getOptions());
107
182
  await readerCallback(reader);
108
183
  }
109
- catch (e_1) {
110
- env_1.error = e_1;
111
- env_1.hasError = true;
184
+ catch (e_2) {
185
+ env_2.error = e_2;
186
+ env_2.hasError = true;
112
187
  }
113
188
  finally {
114
- __disposeResources(env_1);
189
+ __disposeResources(env_2);
115
190
  }
116
191
  });
117
192
  it("ecsql reader simple for IdSet", async () => {
118
- const env_2 = { stack: [], error: void 0, hasError: false };
193
+ const env_3 = { stack: [], error: void 0, hasError: false };
119
194
  try {
120
- const ecdb = __addDisposableResource(env_2, ECDbTestHelper.createECDb(outDir, "test.ecdb", `<ECSchema schemaName="Test" alias="ts" version="01.00.00" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.2">
195
+ const ecdb = __addDisposableResource(env_3, ECDbTestHelper.createECDb(outDir, "test.ecdb", `<ECSchema schemaName="Test" alias="ts" version="01.00.00" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.2">
121
196
  <ECEntityClass typeName="Foo" modifier="Sealed">
122
197
  <ECProperty propertyName="n" typeName="int"/>
123
198
  </ECEntityClass>
@@ -143,18 +218,18 @@ describe("QueryReaders - createQueryReader() and withQueryReader() api tests", (
143
218
  const reader = ecdb.createQueryReader("SELECT ECInstanceId, Name FROM meta.ECClassDef, IdSet(?) WHERE id = ECInstanceId ECSQLOPTIONS ENABLE_EXPERIMENTAL_FEATURES", params, optionBuilder.getOptions());
144
219
  await readerCallback(reader);
145
220
  }
146
- catch (e_2) {
147
- env_2.error = e_2;
148
- env_2.hasError = true;
221
+ catch (e_3) {
222
+ env_3.error = e_3;
223
+ env_3.hasError = true;
149
224
  }
150
225
  finally {
151
- __disposeResources(env_2);
226
+ __disposeResources(env_3);
152
227
  }
153
228
  });
154
229
  it("bindIdSet throws on invalid integer Ids", () => {
155
- const env_3 = { stack: [], error: void 0, hasError: false };
230
+ const env_4 = { stack: [], error: void 0, hasError: false };
156
231
  try {
157
- const ecdb = __addDisposableResource(env_3, ECDbTestHelper.createECDb(outDir, "test.ecdb", `<ECSchema schemaName="Test" alias="ts" version="01.00.00" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.2">
232
+ const ecdb = __addDisposableResource(env_4, ECDbTestHelper.createECDb(outDir, "test.ecdb", `<ECSchema schemaName="Test" alias="ts" version="01.00.00" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.2">
158
233
  <ECEntityClass typeName="Foo" modifier="Sealed">
159
234
  <ECProperty propertyName="n" typeName="int"/>
160
235
  </ECEntityClass>
@@ -164,18 +239,18 @@ describe("QueryReaders - createQueryReader() and withQueryReader() api tests", (
164
239
  const params = new QueryBinder();
165
240
  expect(() => params.bindIdSet(1, ["50"])).to.throw(/is not a valid Id64String/);
166
241
  }
167
- catch (e_3) {
168
- env_3.error = e_3;
169
- env_3.hasError = true;
242
+ catch (e_4) {
243
+ env_4.error = e_4;
244
+ env_4.hasError = true;
170
245
  }
171
246
  finally {
172
- __disposeResources(env_3);
247
+ __disposeResources(env_4);
173
248
  }
174
249
  });
175
250
  it("ecsql reader simple using query reader", async () => {
176
- const env_4 = { stack: [], error: void 0, hasError: false };
251
+ const env_5 = { stack: [], error: void 0, hasError: false };
177
252
  try {
178
- const ecdb = __addDisposableResource(env_4, ECDbTestHelper.createECDb(outDir, "test.ecdb", `<ECSchema schemaName="Test" alias="ts" version="01.00.00" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.2">
253
+ const ecdb = __addDisposableResource(env_5, ECDbTestHelper.createECDb(outDir, "test.ecdb", `<ECSchema schemaName="Test" alias="ts" version="01.00.00" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.2">
179
254
  <ECEntityClass typeName="Foo" modifier="Sealed">
180
255
  <ECProperty propertyName="n" typeName="int"/>
181
256
  </ECEntityClass>
@@ -215,12 +290,12 @@ describe("QueryReaders - createQueryReader() and withQueryReader() api tests", (
215
290
  const reader = ecdb.createQueryReader("SELECT ECInstanceId, n FROM ts.Foo WHERE ECInstanceId=:firstId", params, { limit: { count: 1 } });
216
291
  await readerCallback(reader);
217
292
  }
218
- catch (e_4) {
219
- env_4.error = e_4;
220
- env_4.hasError = true;
293
+ catch (e_5) {
294
+ env_5.error = e_5;
295
+ env_5.hasError = true;
221
296
  }
222
297
  finally {
223
- __disposeResources(env_4);
298
+ __disposeResources(env_5);
224
299
  }
225
300
  });
226
301
  it("ecsql reader simple using query row reader", async () => {
@@ -255,10 +330,10 @@ describe("QueryReaders - createQueryReader() and withQueryReader() api tests", (
255
330
  await readerCallback(reader);
256
331
  });
257
332
  it("should bind Range3d", async () => {
258
- const env_5 = { stack: [], error: void 0, hasError: false };
333
+ const env_6 = { stack: [], error: void 0, hasError: false };
259
334
  try {
260
335
  const testRange = new Range3d(1.2, 2.3, 3.4, 4.5, 5.6, 6.7);
261
- const ecdb = __addDisposableResource(env_5, ECDbTestHelper.createECDb(outDir, "bindrange3d.ecdb", `<ECSchema schemaName="Test" alias="test" version="01.00.00" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.1">
336
+ const ecdb = __addDisposableResource(env_6, ECDbTestHelper.createECDb(outDir, "bindrange3d.ecdb", `<ECSchema schemaName="Test" alias="test" version="01.00.00" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.1">
262
337
  <ECEntityClass typeName="Foo" modifier="Sealed">
263
338
  <ECProperty propertyName="Range3d" typeName="binary"/>
264
339
  </ECEntityClass>
@@ -280,12 +355,12 @@ describe("QueryReaders - createQueryReader() and withQueryReader() api tests", (
280
355
  const actualRange = new Range3d(...rangeFloatArray);
281
356
  assert.isTrue(actualRange.isAlmostEqual(testRange));
282
357
  }
283
- catch (e_5) {
284
- env_5.error = e_5;
285
- env_5.hasError = true;
358
+ catch (e_6) {
359
+ env_6.error = e_6;
360
+ env_6.hasError = true;
286
361
  }
287
362
  finally {
288
- __disposeResources(env_5);
363
+ __disposeResources(env_6);
289
364
  }
290
365
  });
291
366
  });