@itwin/core-backend 5.15.0-dev.9 → 5.15.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.
Files changed (220) hide show
  1. package/CHANGELOG.md +39 -1
  2. package/lib/cjs/BlobContainerService.d.ts +2 -0
  3. package/lib/cjs/BlobContainerService.d.ts.map +1 -1
  4. package/lib/cjs/BlobContainerService.js.map +1 -1
  5. package/lib/cjs/BriefcaseManager.d.ts +2 -1
  6. package/lib/cjs/BriefcaseManager.d.ts.map +1 -1
  7. package/lib/cjs/BriefcaseManager.js +39 -9
  8. package/lib/cjs/BriefcaseManager.js.map +1 -1
  9. package/lib/cjs/ChangeUnifier.d.ts +82 -0
  10. package/lib/cjs/ChangeUnifier.d.ts.map +1 -0
  11. package/lib/cjs/ChangeUnifier.js +163 -0
  12. package/lib/cjs/ChangeUnifier.js.map +1 -0
  13. package/lib/cjs/ChangesetReader.d.ts +21 -2
  14. package/lib/cjs/ChangesetReader.d.ts.map +1 -1
  15. package/lib/cjs/ChangesetReader.js +37 -1
  16. package/lib/cjs/ChangesetReader.js.map +1 -1
  17. package/lib/cjs/CloudSqlite.d.ts +15 -0
  18. package/lib/cjs/CloudSqlite.d.ts.map +1 -1
  19. package/lib/cjs/CloudSqlite.js.map +1 -1
  20. package/lib/cjs/ECDb.d.ts +1 -0
  21. package/lib/cjs/ECDb.d.ts.map +1 -1
  22. package/lib/cjs/ECDb.js +4 -1
  23. package/lib/cjs/ECDb.js.map +1 -1
  24. package/lib/cjs/EditTxn.d.ts +61 -19
  25. package/lib/cjs/EditTxn.d.ts.map +1 -1
  26. package/lib/cjs/EditTxn.js +84 -29
  27. package/lib/cjs/EditTxn.js.map +1 -1
  28. package/lib/cjs/GeoCoordConfig.d.ts +1 -0
  29. package/lib/cjs/GeoCoordConfig.d.ts.map +1 -1
  30. package/lib/cjs/GeoCoordConfig.js +12 -8
  31. package/lib/cjs/GeoCoordConfig.js.map +1 -1
  32. package/lib/cjs/IModelDb.d.ts +22 -9
  33. package/lib/cjs/IModelDb.d.ts.map +1 -1
  34. package/lib/cjs/IModelDb.js +54 -12
  35. package/lib/cjs/IModelDb.js.map +1 -1
  36. package/lib/cjs/NativeHost.d.ts.map +1 -1
  37. package/lib/cjs/NativeHost.js +5 -1
  38. package/lib/cjs/NativeHost.js.map +1 -1
  39. package/lib/cjs/Relationship.d.ts +28 -0
  40. package/lib/cjs/Relationship.d.ts.map +1 -1
  41. package/lib/cjs/Relationship.js +78 -0
  42. package/lib/cjs/Relationship.js.map +1 -1
  43. package/lib/cjs/SchemaSync.d.ts.map +1 -1
  44. package/lib/cjs/SchemaSync.js +1 -0
  45. package/lib/cjs/SchemaSync.js.map +1 -1
  46. package/lib/cjs/TxnManager.d.ts +126 -89
  47. package/lib/cjs/TxnManager.d.ts.map +1 -1
  48. package/lib/cjs/TxnManager.js +114 -76
  49. package/lib/cjs/TxnManager.js.map +1 -1
  50. package/lib/cjs/ViewStateHydrator.d.ts.map +1 -1
  51. package/lib/cjs/ViewStateHydrator.js.map +1 -1
  52. package/lib/cjs/ViewStore.d.ts.map +1 -1
  53. package/lib/cjs/ViewStore.js +62 -19
  54. package/lib/cjs/ViewStore.js.map +1 -1
  55. package/lib/cjs/annotations/LeaderGeometry.d.ts.map +1 -1
  56. package/lib/cjs/annotations/LeaderGeometry.js +3 -0
  57. package/lib/cjs/annotations/LeaderGeometry.js.map +1 -1
  58. package/lib/cjs/core-backend.d.ts +1 -0
  59. package/lib/cjs/core-backend.d.ts.map +1 -1
  60. package/lib/cjs/core-backend.js +1 -0
  61. package/lib/cjs/core-backend.js.map +1 -1
  62. package/lib/cjs/internal/BriefcaseUtils.d.ts +19 -0
  63. package/lib/cjs/internal/BriefcaseUtils.d.ts.map +1 -0
  64. package/lib/cjs/internal/BriefcaseUtils.js +65 -0
  65. package/lib/cjs/internal/BriefcaseUtils.js.map +1 -0
  66. package/lib/cjs/internal/QueryMetadataCache.d.ts +44 -0
  67. package/lib/cjs/internal/QueryMetadataCache.d.ts.map +1 -0
  68. package/lib/cjs/internal/QueryMetadataCache.js +107 -0
  69. package/lib/cjs/internal/QueryMetadataCache.js.map +1 -0
  70. package/lib/cjs/internal/Symbols.d.ts +9 -0
  71. package/lib/cjs/internal/Symbols.d.ts.map +1 -1
  72. package/lib/cjs/internal/Symbols.js +10 -1
  73. package/lib/cjs/internal/Symbols.js.map +1 -1
  74. package/lib/cjs/internal/workspace/WorkspaceImpl.d.ts.map +1 -1
  75. package/lib/cjs/internal/workspace/WorkspaceImpl.js +20 -6
  76. package/lib/cjs/internal/workspace/WorkspaceImpl.js.map +1 -1
  77. package/lib/cjs/rpc-impl/IModelReadRpcImpl.d.ts +6 -6
  78. package/lib/cjs/rpc-impl/IModelReadRpcImpl.d.ts.map +1 -1
  79. package/lib/cjs/rpc-impl/IModelReadRpcImpl.js.map +1 -1
  80. package/lib/cjs/workspace/SettingsEditor.d.ts +4 -3
  81. package/lib/cjs/workspace/SettingsEditor.d.ts.map +1 -1
  82. package/lib/cjs/workspace/SettingsEditor.js +7 -5
  83. package/lib/cjs/workspace/SettingsEditor.js.map +1 -1
  84. package/lib/esm/BlobContainerService.d.ts +2 -0
  85. package/lib/esm/BlobContainerService.d.ts.map +1 -1
  86. package/lib/esm/BlobContainerService.js.map +1 -1
  87. package/lib/esm/BriefcaseManager.d.ts +2 -1
  88. package/lib/esm/BriefcaseManager.d.ts.map +1 -1
  89. package/lib/esm/BriefcaseManager.js +40 -10
  90. package/lib/esm/BriefcaseManager.js.map +1 -1
  91. package/lib/esm/ChangeUnifier.d.ts +82 -0
  92. package/lib/esm/ChangeUnifier.d.ts.map +1 -0
  93. package/lib/esm/ChangeUnifier.js +159 -0
  94. package/lib/esm/ChangeUnifier.js.map +1 -0
  95. package/lib/esm/ChangesetReader.d.ts +21 -2
  96. package/lib/esm/ChangesetReader.d.ts.map +1 -1
  97. package/lib/esm/ChangesetReader.js +38 -2
  98. package/lib/esm/ChangesetReader.js.map +1 -1
  99. package/lib/esm/CloudSqlite.d.ts +15 -0
  100. package/lib/esm/CloudSqlite.d.ts.map +1 -1
  101. package/lib/esm/CloudSqlite.js.map +1 -1
  102. package/lib/esm/ECDb.d.ts +1 -0
  103. package/lib/esm/ECDb.d.ts.map +1 -1
  104. package/lib/esm/ECDb.js +4 -1
  105. package/lib/esm/ECDb.js.map +1 -1
  106. package/lib/esm/EditTxn.d.ts +61 -19
  107. package/lib/esm/EditTxn.d.ts.map +1 -1
  108. package/lib/esm/EditTxn.js +85 -30
  109. package/lib/esm/EditTxn.js.map +1 -1
  110. package/lib/esm/GeoCoordConfig.d.ts +1 -0
  111. package/lib/esm/GeoCoordConfig.d.ts.map +1 -1
  112. package/lib/esm/GeoCoordConfig.js +12 -8
  113. package/lib/esm/GeoCoordConfig.js.map +1 -1
  114. package/lib/esm/IModelDb.d.ts +22 -9
  115. package/lib/esm/IModelDb.d.ts.map +1 -1
  116. package/lib/esm/IModelDb.js +56 -14
  117. package/lib/esm/IModelDb.js.map +1 -1
  118. package/lib/esm/NativeHost.d.ts.map +1 -1
  119. package/lib/esm/NativeHost.js +5 -1
  120. package/lib/esm/NativeHost.js.map +1 -1
  121. package/lib/esm/Relationship.d.ts +28 -0
  122. package/lib/esm/Relationship.d.ts.map +1 -1
  123. package/lib/esm/Relationship.js +78 -0
  124. package/lib/esm/Relationship.js.map +1 -1
  125. package/lib/esm/SchemaSync.d.ts.map +1 -1
  126. package/lib/esm/SchemaSync.js +1 -0
  127. package/lib/esm/SchemaSync.js.map +1 -1
  128. package/lib/esm/TxnManager.d.ts +126 -89
  129. package/lib/esm/TxnManager.d.ts.map +1 -1
  130. package/lib/esm/TxnManager.js +116 -78
  131. package/lib/esm/TxnManager.js.map +1 -1
  132. package/lib/esm/ViewStateHydrator.d.ts.map +1 -1
  133. package/lib/esm/ViewStateHydrator.js.map +1 -1
  134. package/lib/esm/ViewStore.d.ts.map +1 -1
  135. package/lib/esm/ViewStore.js +62 -19
  136. package/lib/esm/ViewStore.js.map +1 -1
  137. package/lib/esm/annotations/LeaderGeometry.d.ts.map +1 -1
  138. package/lib/esm/annotations/LeaderGeometry.js +3 -0
  139. package/lib/esm/annotations/LeaderGeometry.js.map +1 -1
  140. package/lib/esm/core-backend.d.ts +1 -0
  141. package/lib/esm/core-backend.d.ts.map +1 -1
  142. package/lib/esm/core-backend.js +1 -0
  143. package/lib/esm/core-backend.js.map +1 -1
  144. package/lib/esm/internal/BriefcaseUtils.d.ts +19 -0
  145. package/lib/esm/internal/BriefcaseUtils.d.ts.map +1 -0
  146. package/lib/esm/internal/BriefcaseUtils.js +61 -0
  147. package/lib/esm/internal/BriefcaseUtils.js.map +1 -0
  148. package/lib/esm/internal/QueryMetadataCache.d.ts +44 -0
  149. package/lib/esm/internal/QueryMetadataCache.d.ts.map +1 -0
  150. package/lib/esm/internal/QueryMetadataCache.js +103 -0
  151. package/lib/esm/internal/QueryMetadataCache.js.map +1 -0
  152. package/lib/esm/internal/Symbols.d.ts +9 -0
  153. package/lib/esm/internal/Symbols.d.ts.map +1 -1
  154. package/lib/esm/internal/Symbols.js +9 -0
  155. package/lib/esm/internal/Symbols.js.map +1 -1
  156. package/lib/esm/internal/workspace/WorkspaceImpl.d.ts.map +1 -1
  157. package/lib/esm/internal/workspace/WorkspaceImpl.js +20 -6
  158. package/lib/esm/internal/workspace/WorkspaceImpl.js.map +1 -1
  159. package/lib/esm/rpc-impl/IModelReadRpcImpl.d.ts +6 -6
  160. package/lib/esm/rpc-impl/IModelReadRpcImpl.d.ts.map +1 -1
  161. package/lib/esm/rpc-impl/IModelReadRpcImpl.js.map +1 -1
  162. package/lib/esm/test/annotations/LeaderGeometry.test.js +15 -1
  163. package/lib/esm/test/annotations/LeaderGeometry.test.js.map +1 -1
  164. package/lib/esm/test/ecdb/ConcurrentQuery.test.js +144 -30
  165. package/lib/esm/test/ecdb/ConcurrentQuery.test.js.map +1 -1
  166. package/lib/esm/test/ecdb/QueryMetadataCache.test.d.ts +2 -0
  167. package/lib/esm/test/ecdb/QueryMetadataCache.test.d.ts.map +1 -0
  168. package/lib/esm/test/ecdb/QueryMetadataCache.test.js +630 -0
  169. package/lib/esm/test/ecdb/QueryMetadataCache.test.js.map +1 -0
  170. package/lib/esm/test/element/DeleteDefinitionElements.test.js +403 -249
  171. package/lib/esm/test/element/DeleteDefinitionElements.test.js.map +1 -1
  172. package/lib/esm/test/element/RelationshipBatchLookup.test.d.ts +2 -0
  173. package/lib/esm/test/element/RelationshipBatchLookup.test.d.ts.map +1 -0
  174. package/lib/esm/test/element/RelationshipBatchLookup.test.js +202 -0
  175. package/lib/esm/test/element/RelationshipBatchLookup.test.js.map +1 -0
  176. package/lib/esm/test/hubaccess/BriefcaseManager.test.js +187 -1
  177. package/lib/esm/test/hubaccess/BriefcaseManager.test.js.map +1 -1
  178. package/lib/esm/test/hubaccess/SchemaImportOrphanColumns.test.d.ts +2 -0
  179. package/lib/esm/test/hubaccess/SchemaImportOrphanColumns.test.d.ts.map +1 -0
  180. package/lib/esm/test/hubaccess/SchemaImportOrphanColumns.test.js +142 -0
  181. package/lib/esm/test/hubaccess/SchemaImportOrphanColumns.test.js.map +1 -0
  182. package/lib/esm/test/imodel/IModelGeolocation.test.js +8 -6
  183. package/lib/esm/test/imodel/IModelGeolocation.test.js.map +1 -1
  184. package/lib/esm/test/imodel/IModelProps.test.d.ts +2 -0
  185. package/lib/esm/test/imodel/IModelProps.test.d.ts.map +1 -0
  186. package/lib/esm/test/imodel/IModelProps.test.js +411 -0
  187. package/lib/esm/test/imodel/IModelProps.test.js.map +1 -0
  188. package/lib/esm/test/schema/SchemaViewPropertyOverrides.test.d.ts +2 -0
  189. package/lib/esm/test/schema/SchemaViewPropertyOverrides.test.d.ts.map +1 -0
  190. package/lib/esm/test/schema/SchemaViewPropertyOverrides.test.js +240 -0
  191. package/lib/esm/test/schema/SchemaViewPropertyOverrides.test.js.map +1 -0
  192. package/lib/esm/test/schema/SchemaViewValidation.test.js +2 -8
  193. package/lib/esm/test/schema/SchemaViewValidation.test.js.map +1 -1
  194. package/lib/esm/test/standalone/BriefcaseManagerDelete.test.d.ts +2 -0
  195. package/lib/esm/test/standalone/BriefcaseManagerDelete.test.d.ts.map +1 -0
  196. package/lib/esm/test/standalone/BriefcaseManagerDelete.test.js +159 -0
  197. package/lib/esm/test/standalone/BriefcaseManagerDelete.test.js.map +1 -0
  198. package/lib/esm/test/standalone/ChangeUnifier.test.d.ts +2 -0
  199. package/lib/esm/test/standalone/ChangeUnifier.test.d.ts.map +1 -0
  200. package/lib/esm/test/standalone/ChangeUnifier.test.js +732 -0
  201. package/lib/esm/test/standalone/ChangeUnifier.test.js.map +1 -0
  202. package/lib/esm/test/standalone/DeleteElements.test.js +962 -83
  203. package/lib/esm/test/standalone/DeleteElements.test.js.map +1 -1
  204. package/lib/esm/test/standalone/EditTxn.test.js +72 -1
  205. package/lib/esm/test/standalone/EditTxn.test.js.map +1 -1
  206. package/lib/esm/test/standalone/GeoCoordConfig.test.d.ts +2 -0
  207. package/lib/esm/test/standalone/GeoCoordConfig.test.d.ts.map +1 -0
  208. package/lib/esm/test/standalone/GeoCoordConfig.test.js +158 -0
  209. package/lib/esm/test/standalone/GeoCoordConfig.test.js.map +1 -0
  210. package/lib/esm/test/standalone/ViewStoreDb.test.js +53 -0
  211. package/lib/esm/test/standalone/ViewStoreDb.test.js.map +1 -1
  212. package/lib/esm/test/workspace/SettingsContainers.test.d.ts +2 -0
  213. package/lib/esm/test/workspace/SettingsContainers.test.d.ts.map +1 -0
  214. package/lib/esm/test/workspace/SettingsContainers.test.js +95 -0
  215. package/lib/esm/test/workspace/SettingsContainers.test.js.map +1 -0
  216. package/lib/esm/workspace/SettingsEditor.d.ts +4 -3
  217. package/lib/esm/workspace/SettingsEditor.d.ts.map +1 -1
  218. package/lib/esm/workspace/SettingsEditor.js +7 -5
  219. package/lib/esm/workspace/SettingsEditor.js.map +1 -1
  220. package/package.json +18 -18
@@ -1,4 +1,4 @@
1
- import { DbResponseStatus } from "@itwin/core-common";
1
+ import { DbResponseStatus, DbValueFormat, QueryBinder } from "@itwin/core-common";
2
2
  import { expect } from "chai";
3
3
  import * as os from "os";
4
4
  import { ConcurrentQuery } from "../../ConcurrentQuery";
@@ -33,6 +33,9 @@ describe("ConcurrentQuery", () => {
33
33
  progressOpCount: 5000,
34
34
  requestQueueSize: 2000,
35
35
  statementCacheSizePerWorker: 40,
36
+ enableCursors: true,
37
+ maxCursorsPerWorker: -1,
38
+ cursorIdleTimeout: 30,
36
39
  workerThreads: defaultWorkerThreads(),
37
40
  };
38
41
  const config = ConcurrentQuery.resetConfig(db[_nativeDb], {});
@@ -53,6 +56,9 @@ describe("ConcurrentQuery", () => {
53
56
  progressOpCount: 6000,
54
57
  requestQueueSize: 1000,
55
58
  statementCacheSizePerWorker: 20,
59
+ enableCursors: false,
60
+ maxCursorsPerWorker: 3,
61
+ cursorIdleTimeout: 10,
56
62
  workerThreads: 1,
57
63
  };
58
64
  const config = ConcurrentQuery.resetConfig(db[_nativeDb], modifiedConfig);
@@ -67,6 +73,94 @@ describe("ConcurrentQuery", () => {
67
73
  expect(config.workerThreads).eq(defaultWorkerThreads());
68
74
  db.close();
69
75
  });
76
+ it("round-trips the page-cache target in KiB and rejects invalid sizes", () => {
77
+ const db = SnapshotDb.openFile(IModelTestUtils.resolveAssetFile("test.bim"));
78
+ try {
79
+ expect(ConcurrentQuery.resetConfig(db[_nativeDb], {}).cacheSizeInKB).eq(undefined);
80
+ for (const cacheSizeInKB of [0, 8192, 2147483647])
81
+ expect(ConcurrentQuery.resetConfig(db[_nativeDb], { cacheSizeInKB }).cacheSizeInKB).eq(cacheSizeInKB);
82
+ for (const cacheSizeInKB of [-1, 1.5, 2147483648, NaN, Infinity, -Infinity])
83
+ expect(ConcurrentQuery.resetConfig(db[_nativeDb], { cacheSizeInKB }).cacheSizeInKB).eq(undefined);
84
+ }
85
+ finally {
86
+ db.close();
87
+ }
88
+ });
89
+ it("resumes finite pages without losing rows, with OFFSET fallback when disabled", async () => {
90
+ const db = SnapshotDb.openFile(IModelTestUtils.resolveAssetFile("test.bim"));
91
+ try {
92
+ for (const enableCursors of [false, true]) {
93
+ ConcurrentQuery.shutdown(db[_nativeDb]);
94
+ ConcurrentQuery.resetConfig(db[_nativeDb], { workerThreads: 1, enableCursors, globalQuota: { time: 60, memory: 1 } });
95
+ const rows = [];
96
+ let resumed = 0;
97
+ while (rows.length < 20) {
98
+ const resp = await ConcurrentQuery.executeQueryRequest(db[_nativeDb], {
99
+ query: "WITH sequence(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM sequence WHERE n<50) SELECT n FROM sequence ORDER BY n DESC",
100
+ cursorId: "finite-reader",
101
+ limit: { offset: 5 + rows.length, count: 20 - rows.length },
102
+ });
103
+ expect(resp.status).eq(DbResponseStatus.Partial);
104
+ expect(resp.data).deep.eq([[45 - rows.length]]);
105
+ rows.push(resp.data[0][0]);
106
+ if (resp.stats.resumed)
107
+ ++resumed;
108
+ }
109
+ expect(rows).deep.eq(Array.from({ length: 20 }, (_, i) => 45 - i));
110
+ expect(resumed).eq(enableCursors ? 19 : 0);
111
+ }
112
+ }
113
+ finally {
114
+ db.close();
115
+ }
116
+ });
117
+ it("isolates readers and bindings and falls back after cursor eviction", async () => {
118
+ const db = SnapshotDb.openFile(IModelTestUtils.resolveAssetFile("test.bim"));
119
+ try {
120
+ ConcurrentQuery.resetConfig(db[_nativeDb], { workerThreads: 1, maxCursorsPerWorker: 1, globalQuota: { time: 60, memory: 1 } });
121
+ const query = "WITH sequence(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM sequence WHERE n<10) SELECT n+? FROM sequence ORDER BY n";
122
+ const page = async (cursorId, offset, value) => ConcurrentQuery.executeQueryRequest(db[_nativeDb], {
123
+ query, cursorId, args: new QueryBinder().bindInt(1, value).serialize(), limit: { offset, count: -1 },
124
+ });
125
+ expect((await page("a", 0, 0)).data).deep.eq([[1]]);
126
+ expect((await page("a", 1, 0)).stats.resumed).eq(true);
127
+ expect((await page("b", 0, 100)).data).deep.eq([[101]]);
128
+ const evicted = await page("a", 2, 0);
129
+ expect(evicted.stats.resumed).eq(false);
130
+ expect(evicted.data).deep.eq([[3]]);
131
+ const rebound = await page("a", 3, 100);
132
+ expect(rebound.stats.resumed).eq(false);
133
+ expect(rebound.data).deep.eq([[104]]);
134
+ }
135
+ finally {
136
+ db.close();
137
+ }
138
+ });
139
+ it("preserves class and navigation rendering across worker connections", async () => {
140
+ const db = SnapshotDb.openFile(IModelTestUtils.resolveAssetFile("test.bim"));
141
+ try {
142
+ ConcurrentQuery.resetConfig(db[_nativeDb], { workerThreads: defaultWorkerThreads(), globalQuota: { time: 60, memory: 8388608 } });
143
+ const query = "SELECT ECClassId, Schema FROM meta.ECClassDef ORDER BY ECInstanceId LIMIT 20";
144
+ for (const valueFormat of [DbValueFormat.ECSqlNames, DbValueFormat.JsNames]) {
145
+ const request = {
146
+ query, valueFormat,
147
+ convertClassIdsToClassNames: true,
148
+ };
149
+ const primary = await ConcurrentQuery.executeQueryRequest(db[_nativeDb], { ...request, usePrimaryConn: true });
150
+ expect(primary.status).eq(DbResponseStatus.Done);
151
+ expect(primary.data.length).eq(20);
152
+ const workers = await Promise.all(Array.from({ length: defaultWorkerThreads() * 2 }, async () => ConcurrentQuery.executeQueryRequest(db[_nativeDb], request)));
153
+ for (const worker of workers) {
154
+ expect(worker.status).eq(DbResponseStatus.Done);
155
+ expect(worker.data).deep.eq(primary.data);
156
+ expect(worker.meta).deep.eq(primary.meta);
157
+ }
158
+ }
159
+ }
160
+ finally {
161
+ db.close();
162
+ }
163
+ });
70
164
  it("time limit check", async () => {
71
165
  const testFile = IModelTestUtils.resolveAssetFile("test.bim");
72
166
  const db = SnapshotDb.openFile(testFile);
@@ -147,38 +241,46 @@ describe("ConcurrentQuery", () => {
147
241
  it("queue limit check", async () => {
148
242
  const testFile = IModelTestUtils.resolveAssetFile("test.bim");
149
243
  const db = SnapshotDb.openFile(testFile);
150
- ConcurrentQuery.resetConfig(db[_nativeDb], { requestQueueSize: 40, globalQuota: { time: 5, memory: 100000 } });
151
- const req = {
152
- query: `WITH sequence(n) AS (
153
- SELECT 1 UNION ALL SELECT n + 1 FROM sequence WHERE n < 10000000
154
- ) SELECT n FROM sequence s`,
155
- };
156
- const responsePromises = [];
157
- for (let i = 0; i < 60; ++i) {
158
- responsePromises.push(ConcurrentQuery.executeQueryRequest(db[_nativeDb], req));
244
+ try {
245
+ const requestQueueSize = 40;
246
+ const requestCount = 60;
247
+ ConcurrentQuery.resetConfig(db[_nativeDb], { requestQueueSize, ignoreDelay: false, globalQuota: { time: 5, memory: 100000 } });
248
+ // A delay keeps accepted requests in the queue (workers only dequeue requests whose delay has elapsed),
249
+ // so the queue fills up deterministically regardless of how fast the worker threads are.
250
+ const req = { query: "SELECT 1", delay: 2000 };
251
+ const responsePromises = [];
252
+ for (let i = 0; i < requestCount; ++i) {
253
+ responsePromises.push(ConcurrentQuery.executeQueryRequest(db[_nativeDb], req));
254
+ }
255
+ const responses = await Promise.all(responsePromises);
256
+ const queueFullResponses = responses.filter((x) => x.status === DbResponseStatus.QueueFull);
257
+ expect(queueFullResponses.length).to.equal(requestCount - requestQueueSize);
258
+ const otherStatuses = responses.filter((x) => x.status !== DbResponseStatus.QueueFull).map((x) => x.status);
259
+ expect(otherStatuses).to.have.lengthOf(requestQueueSize);
260
+ expect(otherStatuses.every((x) => x === DbResponseStatus.Done)).to.be.true;
261
+ }
262
+ finally {
263
+ db.close();
159
264
  }
160
- const responses = await Promise.all(responsePromises);
161
- const queueResponses = Array.from(responses.filter((x) => x.status === DbResponseStatus.QueueFull));
162
- expect(queueResponses.length).to.be.greaterThanOrEqual(10);
163
- db.close();
164
265
  });
165
266
  it("timeout check", async () => {
166
267
  const testFile = IModelTestUtils.resolveAssetFile("test.bim");
167
268
  const db = SnapshotDb.openFile(testFile);
168
- ConcurrentQuery.resetConfig(db[_nativeDb], { monitorPollInterval: 1, globalQuota: { time: 5, memory: 10000000 } });
169
- const req = {
170
- query: `WITH sequence(n) AS (
171
- SELECT 1 UNION ALL SELECT n + 1 FROM sequence WHERE n < 10000000
172
- ) SELECT n FROM sequence s`,
173
- };
174
- const responsePromises = [];
175
- for (let i = 0; i < 100; ++i) {
176
- responsePromises.push(ConcurrentQuery.executeQueryRequest(db[_nativeDb], req));
269
+ try {
270
+ ConcurrentQuery.resetConfig(db[_nativeDb], { ignoreDelay: false, monitorPollInterval: 1000, globalQuota: { time: 1, memory: 1000 } });
271
+ // Keep requests queued past their deadline without generating large result sets.
272
+ const req = { query: "SELECT 1", delay: 2000 };
273
+ const responsePromises = [];
274
+ for (let i = 0; i < 100; ++i) {
275
+ responsePromises.push(ConcurrentQuery.executeQueryRequest(db[_nativeDb], req));
276
+ }
277
+ const responses = await Promise.all(responsePromises);
278
+ for (const response of responses)
279
+ expect(response.status).equals(DbResponseStatus.Timeout);
280
+ }
281
+ finally {
282
+ db.close();
177
283
  }
178
- const responses = await Promise.all(responsePromises);
179
- const queueResponses = Array.from(responses.filter((x) => x.status === DbResponseStatus.Timeout));
180
- expect(queueResponses.length).to.be.greaterThanOrEqual(10);
181
- db.close();
182
284
  });
183
285
  it("should handle concurrent queries during shutdown without deadlock", async () => {
184
286
  const testFile = IModelTestUtils.resolveAssetFile("test.bim");
@@ -187,9 +289,18 @@ describe("ConcurrentQuery", () => {
187
289
  const config = {
188
290
  requestQueueSize: 1000,
189
291
  statementCacheSizePerWorker: 1, // Force frequent prepare calls
292
+ ignoreDelay: false, // Honor request delays so some requests are guaranteed to still be queued at shutdown
190
293
  };
191
294
  // Reset configuration
192
295
  ConcurrentQuery.resetConfig(iModelDb[_nativeDb], config);
296
+ // Requests that are still queued when shutdown happens are rejected with ShuttingDown. A delay keeps these
297
+ // requests from being dequeued by a worker, so they are deterministically queued at shutdown regardless of
298
+ // how fast or slow the worker threads are. They are enqueued first so they cannot be rejected with QueueFull.
299
+ const queuedRequestCount = 10;
300
+ const queuedPromises = [];
301
+ for (let i = 0; i < queuedRequestCount; ++i) {
302
+ queuedPromises.push(ConcurrentQuery.executeQueryRequest(iModelDb[_nativeDb], { query: "SELECT 1", delay: 5000 }));
303
+ }
193
304
  const responsePromises = [];
194
305
  const spamPromises = [];
195
306
  let shouldStop = false;
@@ -213,11 +324,14 @@ describe("ConcurrentQuery", () => {
213
324
  await new Promise(resolve => setTimeout(resolve, 10));
214
325
  ConcurrentQuery.shutdown(iModelDb[_nativeDb]);
215
326
  shouldStop = true;
216
- // Wait for all promises to complete
327
+ // Wait for all promises to complete. If shutdown deadlocked, these would never settle and the test would time out.
328
+ const queuedResults = await Promise.allSettled(queuedPromises);
217
329
  const results = await Promise.allSettled(responsePromises);
218
330
  await Promise.allSettled(spamPromises);
219
- const satisfiesShutDownResponse = results.some((result) => result.status === "fulfilled" && result.value.status === DbResponseStatus.ShuttingDown);
220
- expect(satisfiesShutDownResponse).to.be.true; // some queries should face shutdown
331
+ expect(results.every((result) => result.status === "fulfilled")).to.be.true;
332
+ // Every request that was still queued at shutdown must be rejected with ShuttingDown.
333
+ const queuedStatuses = queuedResults.map((result) => result.status === "fulfilled" ? result.value.status : undefined);
334
+ expect(queuedStatuses).to.deep.equal(new Array(queuedRequestCount).fill(DbResponseStatus.ShuttingDown));
221
335
  // Restore original config by resetting to default
222
336
  ConcurrentQuery.resetConfig(iModelDb[_nativeDb], {});
223
337
  iModelDb.close();
@@ -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 * 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"]}
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, DbValueFormat, QueryBinder } 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 enableCursors: true,\r\n maxCursorsPerWorker: -1,\r\n cursorIdleTimeout: 30,\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 enableCursors: false,\r\n maxCursorsPerWorker: 3,\r\n cursorIdleTimeout: 10,\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(\"round-trips the page-cache target in KiB and rejects invalid sizes\", () => {\r\n const db = SnapshotDb.openFile(IModelTestUtils.resolveAssetFile(\"test.bim\"));\r\n try {\r\n expect(ConcurrentQuery.resetConfig(db[_nativeDb], {}).cacheSizeInKB).eq(undefined);\r\n for (const cacheSizeInKB of [0, 8192, 2147483647])\r\n expect(ConcurrentQuery.resetConfig(db[_nativeDb], { cacheSizeInKB }).cacheSizeInKB).eq(cacheSizeInKB);\r\n for (const cacheSizeInKB of [-1, 1.5, 2147483648, NaN, Infinity, -Infinity])\r\n expect(ConcurrentQuery.resetConfig(db[_nativeDb], { cacheSizeInKB }).cacheSizeInKB).eq(undefined);\r\n } finally {\r\n db.close();\r\n }\r\n });\r\n\r\n it(\"resumes finite pages without losing rows, with OFFSET fallback when disabled\", async () => {\r\n const db = SnapshotDb.openFile(IModelTestUtils.resolveAssetFile(\"test.bim\"));\r\n try {\r\n for (const enableCursors of [false, true]) {\r\n ConcurrentQuery.shutdown(db[_nativeDb]);\r\n ConcurrentQuery.resetConfig(db[_nativeDb], { workerThreads: 1, enableCursors, globalQuota: { time: 60, memory: 1 } });\r\n const rows: number[] = [];\r\n let resumed = 0;\r\n while (rows.length < 20) {\r\n const resp = await ConcurrentQuery.executeQueryRequest(db[_nativeDb], {\r\n query: \"WITH sequence(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM sequence WHERE n<50) SELECT n FROM sequence ORDER BY n DESC\",\r\n cursorId: \"finite-reader\",\r\n limit: { offset: 5 + rows.length, count: 20 - rows.length },\r\n });\r\n expect(resp.status).eq(DbResponseStatus.Partial);\r\n expect(resp.data).deep.eq([[45 - rows.length]]);\r\n rows.push(resp.data[0][0]);\r\n if (resp.stats.resumed)\r\n ++resumed;\r\n }\r\n expect(rows).deep.eq(Array.from({ length: 20 }, (_, i) => 45 - i));\r\n expect(resumed).eq(enableCursors ? 19 : 0);\r\n }\r\n } finally {\r\n db.close();\r\n }\r\n });\r\n\r\n it(\"isolates readers and bindings and falls back after cursor eviction\", async () => {\r\n const db = SnapshotDb.openFile(IModelTestUtils.resolveAssetFile(\"test.bim\"));\r\n try {\r\n ConcurrentQuery.resetConfig(db[_nativeDb], { workerThreads: 1, maxCursorsPerWorker: 1, globalQuota: { time: 60, memory: 1 } });\r\n const query = \"WITH sequence(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM sequence WHERE n<10) SELECT n+? FROM sequence ORDER BY n\";\r\n const page = async (cursorId: string, offset: number, value: number) => ConcurrentQuery.executeQueryRequest(db[_nativeDb], {\r\n query, cursorId, args: new QueryBinder().bindInt(1, value).serialize(), limit: { offset, count: -1 },\r\n });\r\n expect((await page(\"a\", 0, 0)).data).deep.eq([[1]]);\r\n expect((await page(\"a\", 1, 0)).stats.resumed).eq(true);\r\n expect((await page(\"b\", 0, 100)).data).deep.eq([[101]]);\r\n const evicted = await page(\"a\", 2, 0);\r\n expect(evicted.stats.resumed).eq(false);\r\n expect(evicted.data).deep.eq([[3]]);\r\n const rebound = await page(\"a\", 3, 100);\r\n expect(rebound.stats.resumed).eq(false);\r\n expect(rebound.data).deep.eq([[104]]);\r\n } finally {\r\n db.close();\r\n }\r\n });\r\n\r\n it(\"preserves class and navigation rendering across worker connections\", async () => {\r\n const db = SnapshotDb.openFile(IModelTestUtils.resolveAssetFile(\"test.bim\"));\r\n try {\r\n ConcurrentQuery.resetConfig(db[_nativeDb], { workerThreads: defaultWorkerThreads(), globalQuota: { time: 60, memory: 8388608 } });\r\n const query = \"SELECT ECClassId, Schema FROM meta.ECClassDef ORDER BY ECInstanceId LIMIT 20\";\r\n for (const valueFormat of [DbValueFormat.ECSqlNames, DbValueFormat.JsNames]) {\r\n const request: DbQueryRequest = {\r\n query, valueFormat,\r\n convertClassIdsToClassNames: true,\r\n };\r\n const primary = await ConcurrentQuery.executeQueryRequest(db[_nativeDb], { ...request, usePrimaryConn: true });\r\n expect(primary.status).eq(DbResponseStatus.Done);\r\n expect(primary.data.length).eq(20);\r\n const workers = await Promise.all(Array.from({ length: defaultWorkerThreads() * 2 },\r\n async () => ConcurrentQuery.executeQueryRequest(db[_nativeDb], request)));\r\n for (const worker of workers) {\r\n expect(worker.status).eq(DbResponseStatus.Done);\r\n expect(worker.data).deep.eq(primary.data);\r\n expect(worker.meta).deep.eq(primary.meta);\r\n }\r\n }\r\n } finally {\r\n db.close();\r\n }\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 try {\r\n const requestQueueSize = 40;\r\n const requestCount = 60;\r\n ConcurrentQuery.resetConfig(db[_nativeDb], { requestQueueSize, ignoreDelay: false, globalQuota: { time: 5, memory: 100000 } });\r\n // A delay keeps accepted requests in the queue (workers only dequeue requests whose delay has elapsed),\r\n // so the queue fills up deterministically regardless of how fast the worker threads are.\r\n const req: DbQueryRequest = { query: \"SELECT 1\", delay: 2000 };\r\n\r\n const responsePromises: Promise<DbQueryResponse>[] = [];\r\n for (let i = 0; i < requestCount; ++i) {\r\n responsePromises.push(ConcurrentQuery.executeQueryRequest(db[_nativeDb], req));\r\n }\r\n const responses = await Promise.all(responsePromises);\r\n const queueFullResponses = responses.filter((x) => x.status === DbResponseStatus.QueueFull);\r\n expect(queueFullResponses.length).to.equal(requestCount - requestQueueSize);\r\n const otherStatuses = responses.filter((x) => x.status !== DbResponseStatus.QueueFull).map((x) => x.status);\r\n expect(otherStatuses).to.have.lengthOf(requestQueueSize);\r\n expect(otherStatuses.every((x) => x === DbResponseStatus.Done)).to.be.true;\r\n } finally {\r\n db.close();\r\n }\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 try {\r\n ConcurrentQuery.resetConfig(db[_nativeDb], { ignoreDelay: false, monitorPollInterval: 1000, globalQuota: { time: 1, memory: 1000 } });\r\n // Keep requests queued past their deadline without generating large result sets.\r\n const req: DbQueryRequest = { query: \"SELECT 1\", delay: 2000 };\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 for (const response of responses)\r\n expect(response.status).equals(DbResponseStatus.Timeout);\r\n } finally {\r\n db.close();\r\n }\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 ignoreDelay: false, // Honor request delays so some requests are guaranteed to still be queued at shutdown\r\n };\r\n\r\n // Reset configuration\r\n ConcurrentQuery.resetConfig(iModelDb[_nativeDb], config);\r\n\r\n // Requests that are still queued when shutdown happens are rejected with ShuttingDown. A delay keeps these\r\n // requests from being dequeued by a worker, so they are deterministically queued at shutdown regardless of\r\n // how fast or slow the worker threads are. They are enqueued first so they cannot be rejected with QueueFull.\r\n const queuedRequestCount = 10;\r\n const queuedPromises: Promise<DbQueryResponse>[] = [];\r\n for (let i = 0; i < queuedRequestCount; ++i) {\r\n queuedPromises.push(ConcurrentQuery.executeQueryRequest(iModelDb[_nativeDb], { query: \"SELECT 1\", delay: 5000 }));\r\n }\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. If shutdown deadlocked, these would never settle and the test would time out.\r\n const queuedResults = await Promise.allSettled(queuedPromises);\r\n const results = await Promise.allSettled(responsePromises);\r\n await Promise.allSettled(spamPromises);\r\n\r\n expect(results.every((result) => result.status === \"fulfilled\")).to.be.true;\r\n // Every request that was still queued at shutdown must be rejected with ShuttingDown.\r\n const queuedStatuses = queuedResults.map((result) => result.status === \"fulfilled\" ? result.value.status : undefined);\r\n expect(queuedStatuses).to.deep.equal(new Array(queuedRequestCount).fill(DbResponseStatus.ShuttingDown));\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"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=QueryMetadataCache.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QueryMetadataCache.test.d.ts","sourceRoot":"","sources":["../../../../src/test/ecdb/QueryMetadataCache.test.ts"],"names":[],"mappings":""}