@itwin/core-backend 3.4.0-dev.48 → 3.4.0-dev.50

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 (221) hide show
  1. package/lib/cjs/AliCloudStorageService.d.ts +17 -17
  2. package/lib/cjs/AliCloudStorageService.js +68 -68
  3. package/lib/cjs/AliCloudStorageService.js.map +1 -1
  4. package/lib/cjs/BackendHubAccess.d.ts +224 -224
  5. package/lib/cjs/BackendHubAccess.js +41 -41
  6. package/lib/cjs/BackendHubAccess.js.map +1 -1
  7. package/lib/cjs/BackendLoggerCategory.d.ts +87 -82
  8. package/lib/cjs/BackendLoggerCategory.d.ts.map +1 -1
  9. package/lib/cjs/BackendLoggerCategory.js +95 -90
  10. package/lib/cjs/BackendLoggerCategory.js.map +1 -1
  11. package/lib/cjs/BisCoreSchema.d.ts +21 -21
  12. package/lib/cjs/BisCoreSchema.js +60 -60
  13. package/lib/cjs/BisCoreSchema.js.map +1 -1
  14. package/lib/cjs/BriefcaseManager.d.ts +165 -165
  15. package/lib/cjs/BriefcaseManager.js +405 -405
  16. package/lib/cjs/BriefcaseManager.js.map +1 -1
  17. package/lib/cjs/Category.d.ts +153 -153
  18. package/lib/cjs/Category.js +243 -243
  19. package/lib/cjs/Category.js.map +1 -1
  20. package/lib/cjs/ChangeSummaryManager.d.ts +187 -187
  21. package/lib/cjs/ChangeSummaryManager.js +445 -445
  22. package/lib/cjs/ChangeSummaryManager.js.map +1 -1
  23. package/lib/cjs/ChangedElementsDb.d.ts +99 -99
  24. package/lib/cjs/ChangedElementsDb.js +165 -165
  25. package/lib/cjs/ChangedElementsDb.js.map +1 -1
  26. package/lib/cjs/ChangedElementsManager.d.ts +39 -39
  27. package/lib/cjs/ChangedElementsManager.js +88 -88
  28. package/lib/cjs/ChangedElementsManager.js.map +1 -1
  29. package/lib/cjs/CheckpointManager.d.ts +122 -122
  30. package/lib/cjs/CheckpointManager.js +354 -354
  31. package/lib/cjs/CheckpointManager.js.map +1 -1
  32. package/lib/cjs/ClassRegistry.d.ts +71 -71
  33. package/lib/cjs/ClassRegistry.js +213 -213
  34. package/lib/cjs/ClassRegistry.js.map +1 -1
  35. package/lib/cjs/CloudSqlite.d.ts +328 -328
  36. package/lib/cjs/CloudSqlite.js +135 -135
  37. package/lib/cjs/CloudSqlite.js.map +1 -1
  38. package/lib/cjs/CloudStorageBackend.d.ts +46 -46
  39. package/lib/cjs/CloudStorageBackend.js +164 -164
  40. package/lib/cjs/CloudStorageBackend.js.map +1 -1
  41. package/lib/cjs/CodeService.d.ts +391 -391
  42. package/lib/cjs/CodeService.js +61 -61
  43. package/lib/cjs/CodeService.js.map +1 -1
  44. package/lib/cjs/CodeSpecs.d.ts +50 -50
  45. package/lib/cjs/CodeSpecs.js +112 -112
  46. package/lib/cjs/CodeSpecs.js.map +1 -1
  47. package/lib/cjs/ConcurrentQuery.d.ts +11 -11
  48. package/lib/cjs/ConcurrentQuery.js +30 -30
  49. package/lib/cjs/ConcurrentQuery.js.map +1 -1
  50. package/lib/cjs/CustomViewState3dCreator.d.ts +32 -32
  51. package/lib/cjs/CustomViewState3dCreator.d.ts.map +1 -1
  52. package/lib/cjs/CustomViewState3dCreator.js +107 -99
  53. package/lib/cjs/CustomViewState3dCreator.js.map +1 -1
  54. package/lib/cjs/DevTools.d.ts +71 -71
  55. package/lib/cjs/DevTools.js +154 -154
  56. package/lib/cjs/DevTools.js.map +1 -1
  57. package/lib/cjs/DisplayStyle.d.ts +106 -106
  58. package/lib/cjs/DisplayStyle.js +256 -256
  59. package/lib/cjs/DisplayStyle.js.map +1 -1
  60. package/lib/cjs/ECDb.d.ts +191 -191
  61. package/lib/cjs/ECDb.js +350 -350
  62. package/lib/cjs/ECDb.js.map +1 -1
  63. package/lib/cjs/ECSchemaXmlContext.d.ts +18 -18
  64. package/lib/cjs/ECSchemaXmlContext.js +41 -41
  65. package/lib/cjs/ECSchemaXmlContext.js.map +1 -1
  66. package/lib/cjs/ECSqlStatement.d.ts +466 -466
  67. package/lib/cjs/ECSqlStatement.js +791 -791
  68. package/lib/cjs/ECSqlStatement.js.map +1 -1
  69. package/lib/cjs/Element.d.ts +1109 -1109
  70. package/lib/cjs/Element.js +1421 -1421
  71. package/lib/cjs/Element.js.map +1 -1
  72. package/lib/cjs/ElementAspect.d.ts +156 -156
  73. package/lib/cjs/ElementAspect.js +178 -178
  74. package/lib/cjs/ElementAspect.js.map +1 -1
  75. package/lib/cjs/ElementGraphics.d.ts +9 -9
  76. package/lib/cjs/ElementGraphics.js +41 -41
  77. package/lib/cjs/ElementGraphics.js.map +1 -1
  78. package/lib/cjs/ElementTreeWalker.d.ts +162 -162
  79. package/lib/cjs/ElementTreeWalker.js +409 -409
  80. package/lib/cjs/ElementTreeWalker.js.map +1 -1
  81. package/lib/cjs/Entity.d.ts +76 -76
  82. package/lib/cjs/Entity.js +82 -82
  83. package/lib/cjs/Entity.js.map +1 -1
  84. package/lib/cjs/ExportGraphics.d.ts +317 -317
  85. package/lib/cjs/ExportGraphics.js +208 -208
  86. package/lib/cjs/ExportGraphics.js.map +1 -1
  87. package/lib/cjs/ExternalSource.d.ts +94 -94
  88. package/lib/cjs/ExternalSource.js +125 -125
  89. package/lib/cjs/ExternalSource.js.map +1 -1
  90. package/lib/cjs/GeoCoordConfig.d.ts +19 -19
  91. package/lib/cjs/GeoCoordConfig.js +82 -82
  92. package/lib/cjs/GeoCoordConfig.js.map +1 -1
  93. package/lib/cjs/GeometrySummary.d.ts +4 -4
  94. package/lib/cjs/GeometrySummary.js +380 -380
  95. package/lib/cjs/GeometrySummary.js.map +1 -1
  96. package/lib/cjs/HubMock.d.ts +93 -93
  97. package/lib/cjs/HubMock.js +190 -190
  98. package/lib/cjs/HubMock.js.map +1 -1
  99. package/lib/cjs/IModelCloneContext.d.ts +85 -85
  100. package/lib/cjs/IModelCloneContext.js +150 -150
  101. package/lib/cjs/IModelCloneContext.js.map +1 -1
  102. package/lib/cjs/IModelDb.d.ts +1164 -1164
  103. package/lib/cjs/IModelDb.js +2321 -2321
  104. package/lib/cjs/IModelDb.js.map +1 -1
  105. package/lib/cjs/IModelHost.d.ts +347 -347
  106. package/lib/cjs/IModelHost.js +457 -457
  107. package/lib/cjs/IModelHost.js.map +1 -1
  108. package/lib/cjs/IModelJsFs.d.ts +62 -62
  109. package/lib/cjs/IModelJsFs.js +140 -140
  110. package/lib/cjs/IModelJsFs.js.map +1 -1
  111. package/lib/cjs/IpcHost.d.ts +98 -98
  112. package/lib/cjs/IpcHost.js +234 -234
  113. package/lib/cjs/IpcHost.js.map +1 -1
  114. package/lib/cjs/LineStyle.d.ts +311 -311
  115. package/lib/cjs/LineStyle.js +295 -295
  116. package/lib/cjs/LineStyle.js.map +1 -1
  117. package/lib/cjs/LocalHub.d.ts +162 -162
  118. package/lib/cjs/LocalHub.js +587 -587
  119. package/lib/cjs/LocalHub.js.map +1 -1
  120. package/lib/cjs/LocalhostIpcHost.d.ts +20 -20
  121. package/lib/cjs/LocalhostIpcHost.js +81 -81
  122. package/lib/cjs/LocalhostIpcHost.js.map +1 -1
  123. package/lib/cjs/Material.d.ts +103 -103
  124. package/lib/cjs/Material.js +147 -147
  125. package/lib/cjs/Material.js.map +1 -1
  126. package/lib/cjs/Model.d.ts +386 -386
  127. package/lib/cjs/Model.js +468 -468
  128. package/lib/cjs/Model.js.map +1 -1
  129. package/lib/cjs/NativeAppStorage.d.ts +51 -51
  130. package/lib/cjs/NativeAppStorage.js +202 -202
  131. package/lib/cjs/NativeAppStorage.js.map +1 -1
  132. package/lib/cjs/NativeHost.d.ts +52 -52
  133. package/lib/cjs/NativeHost.js +168 -168
  134. package/lib/cjs/NativeHost.js.map +1 -1
  135. package/lib/cjs/NavigationRelationship.d.ts +156 -156
  136. package/lib/cjs/NavigationRelationship.js +225 -225
  137. package/lib/cjs/NavigationRelationship.js.map +1 -1
  138. package/lib/cjs/PromiseMemoizer.d.ts +51 -51
  139. package/lib/cjs/PromiseMemoizer.js +95 -95
  140. package/lib/cjs/PromiseMemoizer.js.map +1 -1
  141. package/lib/cjs/PropertyStore.d.ts +132 -132
  142. package/lib/cjs/PropertyStore.js +11 -11
  143. package/lib/cjs/PropertyStore.js.map +1 -1
  144. package/lib/cjs/Relationship.d.ts +400 -400
  145. package/lib/cjs/Relationship.js +465 -465
  146. package/lib/cjs/Relationship.js.map +1 -1
  147. package/lib/cjs/RpcBackend.d.ts +28 -28
  148. package/lib/cjs/RpcBackend.js +126 -126
  149. package/lib/cjs/RpcBackend.js.map +1 -1
  150. package/lib/cjs/SQLiteDb.d.ts +219 -219
  151. package/lib/cjs/SQLiteDb.js +214 -214
  152. package/lib/cjs/SQLiteDb.js.map +1 -1
  153. package/lib/cjs/Schema.d.ts +55 -55
  154. package/lib/cjs/Schema.js +83 -83
  155. package/lib/cjs/Schema.js.map +1 -1
  156. package/lib/cjs/ServerBasedLocks.d.ts +57 -57
  157. package/lib/cjs/ServerBasedLocks.js +168 -168
  158. package/lib/cjs/ServerBasedLocks.js.map +1 -1
  159. package/lib/cjs/SqliteStatement.d.ts +283 -283
  160. package/lib/cjs/SqliteStatement.js +448 -448
  161. package/lib/cjs/SqliteStatement.js.map +1 -1
  162. package/lib/cjs/Texture.d.ts +58 -58
  163. package/lib/cjs/Texture.js +82 -82
  164. package/lib/cjs/Texture.js.map +1 -1
  165. package/lib/cjs/TxnManager.d.ts +202 -202
  166. package/lib/cjs/TxnManager.js +353 -353
  167. package/lib/cjs/TxnManager.js.map +1 -1
  168. package/lib/cjs/ViewDefinition.d.ts +435 -435
  169. package/lib/cjs/ViewDefinition.js +629 -629
  170. package/lib/cjs/ViewDefinition.js.map +1 -1
  171. package/lib/cjs/ViewStateHydrator.d.ts +13 -13
  172. package/lib/cjs/ViewStateHydrator.js +103 -103
  173. package/lib/cjs/ViewStateHydrator.js.map +1 -1
  174. package/lib/cjs/assets/IModelChange.02.00.00.ecschema.xml +90 -90
  175. package/lib/cjs/assets/Settings/Schemas/Cloud.Schema.json +67 -67
  176. package/lib/cjs/assets/Settings/Schemas/Gcs.schema.json +31 -31
  177. package/lib/cjs/assets/Settings/Schemas/Workspace.Schema.json +52 -52
  178. package/lib/cjs/assets/Settings/backend.setting.json5 +138 -138
  179. package/lib/cjs/core-backend.d.ts +178 -178
  180. package/lib/cjs/core-backend.js +198 -198
  181. package/lib/cjs/core-backend.js.map +1 -1
  182. package/lib/cjs/domains/FunctionalElements.d.ts +101 -101
  183. package/lib/cjs/domains/FunctionalElements.js +145 -145
  184. package/lib/cjs/domains/FunctionalElements.js.map +1 -1
  185. package/lib/cjs/domains/FunctionalSchema.d.ts +13 -13
  186. package/lib/cjs/domains/FunctionalSchema.js +40 -40
  187. package/lib/cjs/domains/FunctionalSchema.js.map +1 -1
  188. package/lib/cjs/domains/GenericElements.d.ts +177 -177
  189. package/lib/cjs/domains/GenericElements.js +263 -263
  190. package/lib/cjs/domains/GenericElements.js.map +1 -1
  191. package/lib/cjs/domains/GenericSchema.d.ts +10 -10
  192. package/lib/cjs/domains/GenericSchema.js +28 -28
  193. package/lib/cjs/domains/GenericSchema.js.map +1 -1
  194. package/lib/cjs/rpc-impl/DevToolsRpcImpl.d.ts +15 -15
  195. package/lib/cjs/rpc-impl/DevToolsRpcImpl.js +32 -32
  196. package/lib/cjs/rpc-impl/DevToolsRpcImpl.js.map +1 -1
  197. package/lib/cjs/rpc-impl/IModelReadRpcImpl.d.ts +45 -45
  198. package/lib/cjs/rpc-impl/IModelReadRpcImpl.js +262 -262
  199. package/lib/cjs/rpc-impl/IModelReadRpcImpl.js.map +1 -1
  200. package/lib/cjs/rpc-impl/IModelTileRpcImpl.d.ts +20 -20
  201. package/lib/cjs/rpc-impl/IModelTileRpcImpl.js +195 -195
  202. package/lib/cjs/rpc-impl/IModelTileRpcImpl.js.map +1 -1
  203. package/lib/cjs/rpc-impl/RpcBriefcaseUtility.d.ts +36 -36
  204. package/lib/cjs/rpc-impl/RpcBriefcaseUtility.js +165 -165
  205. package/lib/cjs/rpc-impl/RpcBriefcaseUtility.js.map +1 -1
  206. package/lib/cjs/rpc-impl/SnapshotIModelRpcImpl.d.ts +16 -16
  207. package/lib/cjs/rpc-impl/SnapshotIModelRpcImpl.js +43 -43
  208. package/lib/cjs/rpc-impl/SnapshotIModelRpcImpl.js.map +1 -1
  209. package/lib/cjs/rpc-impl/WipRpcImpl.d.ts +15 -15
  210. package/lib/cjs/rpc-impl/WipRpcImpl.js +37 -37
  211. package/lib/cjs/rpc-impl/WipRpcImpl.js.map +1 -1
  212. package/lib/cjs/workspace/Settings.d.ts +186 -186
  213. package/lib/cjs/workspace/Settings.js +152 -152
  214. package/lib/cjs/workspace/Settings.js.map +1 -1
  215. package/lib/cjs/workspace/SettingsSchemas.d.ts +75 -75
  216. package/lib/cjs/workspace/SettingsSchemas.js +191 -191
  217. package/lib/cjs/workspace/SettingsSchemas.js.map +1 -1
  218. package/lib/cjs/workspace/Workspace.d.ts +405 -405
  219. package/lib/cjs/workspace/Workspace.js +539 -539
  220. package/lib/cjs/workspace/Workspace.js.map +1 -1
  221. package/package.json +11 -11
@@ -1,169 +1,169 @@
1
- "use strict";
2
- /*---------------------------------------------------------------------------------------------
3
- * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
4
- * See LICENSE.md in the project root for license terms and full copyright notice.
5
- *--------------------------------------------------------------------------------------------*/
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.ServerBasedLocks = void 0;
8
- /** @packageDocumentation
9
- * @module iModels
10
- */
11
- const core_bentley_1 = require("@itwin/core-bentley");
12
- const core_common_1 = require("@itwin/core-common");
13
- const BackendHubAccess_1 = require("./BackendHubAccess");
14
- const IModelHost_1 = require("./IModelHost");
15
- const SQLiteDb_1 = require("./SQLiteDb");
16
- /** @internal */
17
- class ServerBasedLocks {
18
- constructor(iModel) {
19
- this.lockDb = new SQLiteDb_1.SQLiteDb();
20
- this.briefcase = iModel;
21
- const dbName = `${iModel.nativeDb.getTempFileBaseName()}-locks`;
22
- try {
23
- this.lockDb.openDb(dbName, core_bentley_1.OpenMode.ReadWrite);
24
- }
25
- catch (_e) {
26
- this.lockDb.createDb(dbName);
27
- this.lockDb.executeSQL("CREATE TABLE locks(id INTEGER PRIMARY KEY NOT NULL,state INTEGER NOT NULL,origin INTEGER)");
28
- this.lockDb.saveChanges();
29
- }
30
- }
31
- get isServerBased() { return true; }
32
- close() {
33
- if (this.lockDb.isOpen)
34
- this.lockDb.closeDb();
35
- }
36
- getOwners(id) {
37
- return this.briefcase.withPreparedSqliteStatement("SELECT ModelId,ParentId FROM bis_Element WHERE id=?", (stmt) => {
38
- stmt.bindId(1, id);
39
- const rc = stmt.step();
40
- if (core_bentley_1.DbResult.BE_SQLITE_ROW !== rc)
41
- throw new core_common_1.IModelError(rc, `element ${id} not found`);
42
- return { modelId: stmt.getValueId(0), parentId: stmt.getValueId(1) };
43
- });
44
- }
45
- getLockState(id) {
46
- return (id === undefined || !core_bentley_1.Id64.isValid(id)) ? undefined : this.lockDb.withPreparedSqliteStatement("SELECT state FROM locks WHERE id=?", (stmt) => {
47
- stmt.bindId(1, id);
48
- return (core_bentley_1.DbResult.BE_SQLITE_ROW === stmt.step()) ? stmt.getValueInteger(0) : undefined;
49
- });
50
- }
51
- /** Clear the cache of locally held locks.
52
- * Note: does *not* release locks from server.
53
- */
54
- clearAllLocks() {
55
- this.lockDb.executeSQL("DELETE FROM locks");
56
- this.lockDb.saveChanges();
57
- }
58
- /** only for tests */
59
- getLockCount(state) {
60
- return this.lockDb.withSqliteStatement("SELECT count(*) FROM locks WHERE state=?", (stmt) => {
61
- stmt.bindInteger(1, state);
62
- stmt.step();
63
- return stmt.getValueInteger(0);
64
- });
65
- }
66
- async releaseAllLocks() {
67
- await IModelHost_1.IModelHost.hubAccess.releaseAllLocks(this.briefcase); // throws if unsuccessful
68
- this.clearAllLocks();
69
- }
70
- insertLock(id, state, origin) {
71
- this.lockDb.withPreparedSqliteStatement("INSERT INTO locks(id,state,origin) VALUES (?,?,?) ON CONFLICT(id) DO UPDATE SET state=excluded.state,origin=excluded.origin", (stmt) => {
72
- stmt.bindId(1, id);
73
- stmt.bindInteger(2, state);
74
- stmt.bindInteger(3, origin);
75
- const rc = stmt.step();
76
- if (core_bentley_1.DbResult.BE_SQLITE_DONE !== rc)
77
- throw new core_common_1.IModelError(rc, "can't insert lock into database");
78
- });
79
- return true;
80
- }
81
- ownerHoldsExclusiveLock(id) {
82
- if (id === undefined || id === core_common_1.IModel.rootSubjectId)
83
- return false; // has no owners
84
- const { modelId, parentId } = this.getOwners(id);
85
- if (this.getLockState(modelId) === BackendHubAccess_1.LockState.Exclusive || this.getLockState(parentId) === BackendHubAccess_1.LockState.Exclusive)
86
- return true;
87
- // see if this model is exclusively locked by one of its owners. If so, save that fact on modelId so future tests won't have to descend.
88
- if (this.ownerHoldsExclusiveLock(modelId))
89
- return this.insertLock(modelId, BackendHubAccess_1.LockState.Exclusive, 2 /* Discovered */);
90
- // see if the parent is exclusively locked by one of its owners. If so, save that fact on parentId so future tests won't have to descend.
91
- return this.ownerHoldsExclusiveLock(parentId) ? this.insertLock(parentId, BackendHubAccess_1.LockState.Exclusive, 2 /* Discovered */) : false; // eslint-disable-line @typescript-eslint/no-non-null-assertion
92
- }
93
- /** Determine whether an the exclusive lock is already held by an element (or one of its owners) */
94
- holdsExclusiveLock(id) {
95
- // see if we hold the exclusive lock. or if one of the element's owners is exclusively locked (recursively)
96
- return this.getLockState(id) === BackendHubAccess_1.LockState.Exclusive || this.ownerHoldsExclusiveLock(id);
97
- }
98
- holdsSharedLock(id) {
99
- const state = this.getLockState(id);
100
- // see if we hold shared or exclusive lock, or if an owner has exclusive lock. If so we implicitly have shared lock, but owner holding shared lock doesn't help.
101
- return (state === BackendHubAccess_1.LockState.Shared || state === BackendHubAccess_1.LockState.Exclusive) || this.ownerHoldsExclusiveLock(id);
102
- }
103
- /** if the shared lock on the element supplied is not already held, add it to the set of shared locks required. Then, check owners. */
104
- addSharedLock(id, locks) {
105
- // if the id is not valid, or of the lock is already in the set, or if we already hold a shared lock, we're done
106
- // Note: if we hold a shared lock, it is guaranteed that we also hold all required shared locks on owners.
107
- if (id === undefined || !core_bentley_1.Id64.isValid(id) || locks.has(id) || this.holdsSharedLock(id))
108
- return;
109
- locks.add(id); // add to set of needed shared locks
110
- this.addOwnerSharedLocks(id, locks); // check parent models and groups
111
- }
112
- /** add owners (recursively) of an element to a list of required shared locks, if not already held. */
113
- addOwnerSharedLocks(id, locks) {
114
- const el = this.getOwners(id);
115
- this.addSharedLock(el.parentId, locks); // if this element is in a group
116
- this.addSharedLock(el.modelId, locks); // check its model
117
- }
118
- /** attempt to acquire all necessary locks for a set of elements */
119
- async acquireAllLocks(locks) {
120
- if (locks.size === 0) // no locks are required.
121
- return;
122
- const sharedLocks = new Set();
123
- for (const lock of locks)
124
- this.addOwnerSharedLocks(lock[0], sharedLocks);
125
- for (const shared of sharedLocks) {
126
- if (!locks.has(shared)) // we may already be asking for exclusive lock
127
- locks.set(shared, BackendHubAccess_1.LockState.Shared);
128
- }
129
- await IModelHost_1.IModelHost.hubAccess.acquireLocks(this.briefcase, locks); // throws if unsuccessful
130
- for (const lock of locks)
131
- this.insertLock(lock[0], lock[1], 0 /* Acquired */);
132
- this.lockDb.saveChanges();
133
- }
134
- async acquireLocks(arg) {
135
- const locks = new Map();
136
- if (arg.shared) {
137
- for (const id of core_bentley_1.Id64.iterable(arg.shared)) {
138
- if (!this.holdsSharedLock(id))
139
- locks.set(id, BackendHubAccess_1.LockState.Shared);
140
- }
141
- }
142
- if (arg.exclusive) {
143
- for (const id of core_bentley_1.Id64.iterable(arg.exclusive)) {
144
- if (!this.holdsExclusiveLock(id))
145
- locks.set(id, BackendHubAccess_1.LockState.Exclusive);
146
- }
147
- }
148
- return this.acquireAllLocks(locks);
149
- }
150
- /** When an element is newly created in a session, we hold the lock on it implicitly. Save that fact. */
151
- elementWasCreated(id) {
152
- this.insertLock(id, BackendHubAccess_1.LockState.Exclusive, 1 /* NewElement */);
153
- this.lockDb.saveChanges();
154
- }
155
- /** locks are not necessary during change propagation. */
156
- get _locksAreRequired() { return !this.briefcase.txns.isIndirectChanges; }
157
- /** throw if locks are currently required and the exclusive lock is not held on the supplied element */
158
- checkExclusiveLock(id, type, operation) {
159
- if (this._locksAreRequired && !this.holdsExclusiveLock(id))
160
- throw new core_common_1.IModelError(core_bentley_1.IModelStatus.LockNotHeld, `exclusive lock not held on ${type} for ${operation} (id=${id})`);
161
- }
162
- /** throw if locks are currently required and a shared lock is not held on the supplied element */
163
- checkSharedLock(id, type, operation) {
164
- if (this._locksAreRequired && !this.holdsSharedLock(id))
165
- throw new core_common_1.IModelError(core_bentley_1.IModelStatus.LockNotHeld, `shared lock not held on ${type} for ${operation} (id=${id})`);
166
- }
167
- }
168
- exports.ServerBasedLocks = ServerBasedLocks;
1
+ "use strict";
2
+ /*---------------------------------------------------------------------------------------------
3
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
4
+ * See LICENSE.md in the project root for license terms and full copyright notice.
5
+ *--------------------------------------------------------------------------------------------*/
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.ServerBasedLocks = void 0;
8
+ /** @packageDocumentation
9
+ * @module iModels
10
+ */
11
+ const core_bentley_1 = require("@itwin/core-bentley");
12
+ const core_common_1 = require("@itwin/core-common");
13
+ const BackendHubAccess_1 = require("./BackendHubAccess");
14
+ const IModelHost_1 = require("./IModelHost");
15
+ const SQLiteDb_1 = require("./SQLiteDb");
16
+ /** @internal */
17
+ class ServerBasedLocks {
18
+ constructor(iModel) {
19
+ this.lockDb = new SQLiteDb_1.SQLiteDb();
20
+ this.briefcase = iModel;
21
+ const dbName = `${iModel.nativeDb.getTempFileBaseName()}-locks`;
22
+ try {
23
+ this.lockDb.openDb(dbName, core_bentley_1.OpenMode.ReadWrite);
24
+ }
25
+ catch (_e) {
26
+ this.lockDb.createDb(dbName);
27
+ this.lockDb.executeSQL("CREATE TABLE locks(id INTEGER PRIMARY KEY NOT NULL,state INTEGER NOT NULL,origin INTEGER)");
28
+ this.lockDb.saveChanges();
29
+ }
30
+ }
31
+ get isServerBased() { return true; }
32
+ close() {
33
+ if (this.lockDb.isOpen)
34
+ this.lockDb.closeDb();
35
+ }
36
+ getOwners(id) {
37
+ return this.briefcase.withPreparedSqliteStatement("SELECT ModelId,ParentId FROM bis_Element WHERE id=?", (stmt) => {
38
+ stmt.bindId(1, id);
39
+ const rc = stmt.step();
40
+ if (core_bentley_1.DbResult.BE_SQLITE_ROW !== rc)
41
+ throw new core_common_1.IModelError(rc, `element ${id} not found`);
42
+ return { modelId: stmt.getValueId(0), parentId: stmt.getValueId(1) };
43
+ });
44
+ }
45
+ getLockState(id) {
46
+ return (id === undefined || !core_bentley_1.Id64.isValid(id)) ? undefined : this.lockDb.withPreparedSqliteStatement("SELECT state FROM locks WHERE id=?", (stmt) => {
47
+ stmt.bindId(1, id);
48
+ return (core_bentley_1.DbResult.BE_SQLITE_ROW === stmt.step()) ? stmt.getValueInteger(0) : undefined;
49
+ });
50
+ }
51
+ /** Clear the cache of locally held locks.
52
+ * Note: does *not* release locks from server.
53
+ */
54
+ clearAllLocks() {
55
+ this.lockDb.executeSQL("DELETE FROM locks");
56
+ this.lockDb.saveChanges();
57
+ }
58
+ /** only for tests */
59
+ getLockCount(state) {
60
+ return this.lockDb.withSqliteStatement("SELECT count(*) FROM locks WHERE state=?", (stmt) => {
61
+ stmt.bindInteger(1, state);
62
+ stmt.step();
63
+ return stmt.getValueInteger(0);
64
+ });
65
+ }
66
+ async releaseAllLocks() {
67
+ await IModelHost_1.IModelHost.hubAccess.releaseAllLocks(this.briefcase); // throws if unsuccessful
68
+ this.clearAllLocks();
69
+ }
70
+ insertLock(id, state, origin) {
71
+ this.lockDb.withPreparedSqliteStatement("INSERT INTO locks(id,state,origin) VALUES (?,?,?) ON CONFLICT(id) DO UPDATE SET state=excluded.state,origin=excluded.origin", (stmt) => {
72
+ stmt.bindId(1, id);
73
+ stmt.bindInteger(2, state);
74
+ stmt.bindInteger(3, origin);
75
+ const rc = stmt.step();
76
+ if (core_bentley_1.DbResult.BE_SQLITE_DONE !== rc)
77
+ throw new core_common_1.IModelError(rc, "can't insert lock into database");
78
+ });
79
+ return true;
80
+ }
81
+ ownerHoldsExclusiveLock(id) {
82
+ if (id === undefined || id === core_common_1.IModel.rootSubjectId)
83
+ return false; // has no owners
84
+ const { modelId, parentId } = this.getOwners(id);
85
+ if (this.getLockState(modelId) === BackendHubAccess_1.LockState.Exclusive || this.getLockState(parentId) === BackendHubAccess_1.LockState.Exclusive)
86
+ return true;
87
+ // see if this model is exclusively locked by one of its owners. If so, save that fact on modelId so future tests won't have to descend.
88
+ if (this.ownerHoldsExclusiveLock(modelId))
89
+ return this.insertLock(modelId, BackendHubAccess_1.LockState.Exclusive, 2 /* Discovered */);
90
+ // see if the parent is exclusively locked by one of its owners. If so, save that fact on parentId so future tests won't have to descend.
91
+ return this.ownerHoldsExclusiveLock(parentId) ? this.insertLock(parentId, BackendHubAccess_1.LockState.Exclusive, 2 /* Discovered */) : false; // eslint-disable-line @typescript-eslint/no-non-null-assertion
92
+ }
93
+ /** Determine whether an the exclusive lock is already held by an element (or one of its owners) */
94
+ holdsExclusiveLock(id) {
95
+ // see if we hold the exclusive lock. or if one of the element's owners is exclusively locked (recursively)
96
+ return this.getLockState(id) === BackendHubAccess_1.LockState.Exclusive || this.ownerHoldsExclusiveLock(id);
97
+ }
98
+ holdsSharedLock(id) {
99
+ const state = this.getLockState(id);
100
+ // see if we hold shared or exclusive lock, or if an owner has exclusive lock. If so we implicitly have shared lock, but owner holding shared lock doesn't help.
101
+ return (state === BackendHubAccess_1.LockState.Shared || state === BackendHubAccess_1.LockState.Exclusive) || this.ownerHoldsExclusiveLock(id);
102
+ }
103
+ /** if the shared lock on the element supplied is not already held, add it to the set of shared locks required. Then, check owners. */
104
+ addSharedLock(id, locks) {
105
+ // if the id is not valid, or of the lock is already in the set, or if we already hold a shared lock, we're done
106
+ // Note: if we hold a shared lock, it is guaranteed that we also hold all required shared locks on owners.
107
+ if (id === undefined || !core_bentley_1.Id64.isValid(id) || locks.has(id) || this.holdsSharedLock(id))
108
+ return;
109
+ locks.add(id); // add to set of needed shared locks
110
+ this.addOwnerSharedLocks(id, locks); // check parent models and groups
111
+ }
112
+ /** add owners (recursively) of an element to a list of required shared locks, if not already held. */
113
+ addOwnerSharedLocks(id, locks) {
114
+ const el = this.getOwners(id);
115
+ this.addSharedLock(el.parentId, locks); // if this element is in a group
116
+ this.addSharedLock(el.modelId, locks); // check its model
117
+ }
118
+ /** attempt to acquire all necessary locks for a set of elements */
119
+ async acquireAllLocks(locks) {
120
+ if (locks.size === 0) // no locks are required.
121
+ return;
122
+ const sharedLocks = new Set();
123
+ for (const lock of locks)
124
+ this.addOwnerSharedLocks(lock[0], sharedLocks);
125
+ for (const shared of sharedLocks) {
126
+ if (!locks.has(shared)) // we may already be asking for exclusive lock
127
+ locks.set(shared, BackendHubAccess_1.LockState.Shared);
128
+ }
129
+ await IModelHost_1.IModelHost.hubAccess.acquireLocks(this.briefcase, locks); // throws if unsuccessful
130
+ for (const lock of locks)
131
+ this.insertLock(lock[0], lock[1], 0 /* Acquired */);
132
+ this.lockDb.saveChanges();
133
+ }
134
+ async acquireLocks(arg) {
135
+ const locks = new Map();
136
+ if (arg.shared) {
137
+ for (const id of core_bentley_1.Id64.iterable(arg.shared)) {
138
+ if (!this.holdsSharedLock(id))
139
+ locks.set(id, BackendHubAccess_1.LockState.Shared);
140
+ }
141
+ }
142
+ if (arg.exclusive) {
143
+ for (const id of core_bentley_1.Id64.iterable(arg.exclusive)) {
144
+ if (!this.holdsExclusiveLock(id))
145
+ locks.set(id, BackendHubAccess_1.LockState.Exclusive);
146
+ }
147
+ }
148
+ return this.acquireAllLocks(locks);
149
+ }
150
+ /** When an element is newly created in a session, we hold the lock on it implicitly. Save that fact. */
151
+ elementWasCreated(id) {
152
+ this.insertLock(id, BackendHubAccess_1.LockState.Exclusive, 1 /* NewElement */);
153
+ this.lockDb.saveChanges();
154
+ }
155
+ /** locks are not necessary during change propagation. */
156
+ get _locksAreRequired() { return !this.briefcase.txns.isIndirectChanges; }
157
+ /** throw if locks are currently required and the exclusive lock is not held on the supplied element */
158
+ checkExclusiveLock(id, type, operation) {
159
+ if (this._locksAreRequired && !this.holdsExclusiveLock(id))
160
+ throw new core_common_1.IModelError(core_bentley_1.IModelStatus.LockNotHeld, `exclusive lock not held on ${type} for ${operation} (id=${id})`);
161
+ }
162
+ /** throw if locks are currently required and a shared lock is not held on the supplied element */
163
+ checkSharedLock(id, type, operation) {
164
+ if (this._locksAreRequired && !this.holdsSharedLock(id))
165
+ throw new core_common_1.IModelError(core_bentley_1.IModelStatus.LockNotHeld, `shared lock not held on ${type} for ${operation} (id=${id})`);
166
+ }
167
+ }
168
+ exports.ServerBasedLocks = ServerBasedLocks;
169
169
  //# sourceMappingURL=ServerBasedLocks.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ServerBasedLocks.js","sourceRoot":"","sources":["../../src/ServerBasedLocks.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n* See LICENSE.md in the project root for license terms and full copyright notice.\n*--------------------------------------------------------------------------------------------*/\n\n/** @packageDocumentation\n * @module iModels\n */\n\nimport { DbResult, Id64, Id64Arg, Id64String, IModelStatus, OpenMode } from \"@itwin/core-bentley\";\nimport { IModel, IModelError } from \"@itwin/core-common\";\nimport { LockMap, LockState } from \"./BackendHubAccess\";\nimport { BriefcaseDb, LockControl } from \"./IModelDb\";\nimport { IModelHost } from \"./IModelHost\";\nimport { SQLiteDb } from \"./SQLiteDb\";\n\n/**\n * Both the Model and Parent of an element are considered \"owners\" of their member elements. That means:\n * 1) they must hold at least a shared lock before an exclusive lock can be acquired for their members\n * 2) if they hold an exclusive lock, then all of their members are exclusively locked implicitly.\n * @internal\n */\nexport interface ElementOwners {\n readonly modelId: Id64String;\n readonly parentId: Id64String | undefined;\n}\n\n// eslint-disable-next-line no-restricted-syntax\nconst enum LockOrigin {\n Acquired = 0,\n NewElement = 1,\n Discovered = 2,\n}\n\n/** @internal */\nexport class ServerBasedLocks implements LockControl {\n public get isServerBased() { return true; }\n protected readonly lockDb = new SQLiteDb();\n protected readonly briefcase: BriefcaseDb;\n\n public constructor(iModel: BriefcaseDb) {\n this.briefcase = iModel;\n const dbName = `${iModel.nativeDb.getTempFileBaseName()}-locks`;\n try {\n this.lockDb.openDb(dbName, OpenMode.ReadWrite);\n } catch (_e) {\n this.lockDb.createDb(dbName);\n this.lockDb.executeSQL(\"CREATE TABLE locks(id INTEGER PRIMARY KEY NOT NULL,state INTEGER NOT NULL,origin INTEGER)\");\n this.lockDb.saveChanges();\n }\n }\n\n public close() {\n if (this.lockDb.isOpen)\n this.lockDb.closeDb();\n }\n\n private getOwners(id: Id64String): ElementOwners {\n return this.briefcase.withPreparedSqliteStatement(\"SELECT ModelId,ParentId FROM bis_Element WHERE id=?\", (stmt) => {\n stmt.bindId(1, id);\n const rc = stmt.step();\n if (DbResult.BE_SQLITE_ROW !== rc)\n throw new IModelError(rc, `element ${id} not found`);\n\n return { modelId: stmt.getValueId(0), parentId: stmt.getValueId(1) };\n });\n }\n\n private getLockState(id?: Id64String): LockState | undefined {\n return (id === undefined || !Id64.isValid(id)) ? undefined : this.lockDb.withPreparedSqliteStatement(\"SELECT state FROM locks WHERE id=?\", (stmt) => {\n stmt.bindId(1, id);\n return (DbResult.BE_SQLITE_ROW === stmt.step()) ? stmt.getValueInteger(0) : undefined;\n });\n }\n\n /** Clear the cache of locally held locks.\n * Note: does *not* release locks from server.\n */\n private clearAllLocks() {\n this.lockDb.executeSQL(\"DELETE FROM locks\");\n this.lockDb.saveChanges();\n }\n\n /** only for tests */\n public getLockCount(state: LockState): number {\n return this.lockDb.withSqliteStatement(\"SELECT count(*) FROM locks WHERE state=?\", (stmt) => {\n stmt.bindInteger(1, state);\n stmt.step();\n return stmt.getValueInteger(0);\n });\n }\n\n public async releaseAllLocks(): Promise<void> {\n await IModelHost.hubAccess.releaseAllLocks(this.briefcase); // throws if unsuccessful\n this.clearAllLocks();\n }\n\n private insertLock(id: Id64String, state: LockState, origin: LockOrigin): true {\n this.lockDb.withPreparedSqliteStatement(\"INSERT INTO locks(id,state,origin) VALUES (?,?,?) ON CONFLICT(id) DO UPDATE SET state=excluded.state,origin=excluded.origin\", (stmt) => {\n stmt.bindId(1, id);\n stmt.bindInteger(2, state);\n stmt.bindInteger(3, origin);\n const rc = stmt.step();\n if (DbResult.BE_SQLITE_DONE !== rc)\n throw new IModelError(rc, \"can't insert lock into database\");\n });\n return true;\n }\n\n private ownerHoldsExclusiveLock(id: Id64String | undefined): boolean {\n if (id === undefined || id === IModel.rootSubjectId)\n return false; // has no owners\n\n const { modelId, parentId } = this.getOwners(id);\n if (this.getLockState(modelId) === LockState.Exclusive || this.getLockState(parentId) === LockState.Exclusive)\n return true;\n\n // see if this model is exclusively locked by one of its owners. If so, save that fact on modelId so future tests won't have to descend.\n if (this.ownerHoldsExclusiveLock(modelId))\n return this.insertLock(modelId, LockState.Exclusive, LockOrigin.Discovered);\n\n // see if the parent is exclusively locked by one of its owners. If so, save that fact on parentId so future tests won't have to descend.\n return this.ownerHoldsExclusiveLock(parentId) ? this.insertLock(parentId!, LockState.Exclusive, LockOrigin.Discovered) : false; // eslint-disable-line @typescript-eslint/no-non-null-assertion\n }\n\n /** Determine whether an the exclusive lock is already held by an element (or one of its owners) */\n public holdsExclusiveLock(id: Id64String): boolean {\n // see if we hold the exclusive lock. or if one of the element's owners is exclusively locked (recursively)\n return this.getLockState(id) === LockState.Exclusive || this.ownerHoldsExclusiveLock(id);\n }\n\n public holdsSharedLock(id: Id64String): boolean {\n const state = this.getLockState(id);\n // see if we hold shared or exclusive lock, or if an owner has exclusive lock. If so we implicitly have shared lock, but owner holding shared lock doesn't help.\n return (state === LockState.Shared || state === LockState.Exclusive) || this.ownerHoldsExclusiveLock(id);\n }\n\n /** if the shared lock on the element supplied is not already held, add it to the set of shared locks required. Then, check owners. */\n private addSharedLock(id: Id64String | undefined, locks: Set<Id64String>) {\n // if the id is not valid, or of the lock is already in the set, or if we already hold a shared lock, we're done\n // Note: if we hold a shared lock, it is guaranteed that we also hold all required shared locks on owners.\n if (id === undefined || !Id64.isValid(id) || locks.has(id) || this.holdsSharedLock(id))\n return;\n\n locks.add(id); // add to set of needed shared locks\n this.addOwnerSharedLocks(id, locks); // check parent models and groups\n }\n\n /** add owners (recursively) of an element to a list of required shared locks, if not already held. */\n private addOwnerSharedLocks(id: Id64String, locks: Set<Id64String>) {\n const el = this.getOwners(id);\n this.addSharedLock(el.parentId, locks); // if this element is in a group\n this.addSharedLock(el.modelId, locks); // check its model\n }\n\n /** attempt to acquire all necessary locks for a set of elements */\n private async acquireAllLocks(locks: LockMap) {\n if (locks.size === 0) // no locks are required.\n return;\n\n const sharedLocks = new Set<Id64String>();\n for (const lock of locks)\n this.addOwnerSharedLocks(lock[0], sharedLocks);\n\n for (const shared of sharedLocks) {\n if (!locks.has(shared)) // we may already be asking for exclusive lock\n locks.set(shared, LockState.Shared);\n }\n\n await IModelHost.hubAccess.acquireLocks(this.briefcase, locks); // throws if unsuccessful\n for (const lock of locks)\n this.insertLock(lock[0], lock[1], LockOrigin.Acquired);\n this.lockDb.saveChanges();\n }\n\n public async acquireLocks(arg: { shared?: Id64Arg, exclusive?: Id64Arg }): Promise<void> {\n const locks = new Map<Id64String, LockState>();\n if (arg.shared) {\n for (const id of Id64.iterable(arg.shared)) {\n if (!this.holdsSharedLock(id))\n locks.set(id, LockState.Shared);\n }\n }\n if (arg.exclusive) {\n for (const id of Id64.iterable(arg.exclusive)) {\n if (!this.holdsExclusiveLock(id))\n locks.set(id, LockState.Exclusive);\n }\n }\n return this.acquireAllLocks(locks);\n }\n\n /** When an element is newly created in a session, we hold the lock on it implicitly. Save that fact. */\n public elementWasCreated(id: Id64String) {\n this.insertLock(id, LockState.Exclusive, LockOrigin.NewElement);\n this.lockDb.saveChanges();\n }\n\n /** locks are not necessary during change propagation. */\n private get _locksAreRequired() { return !this.briefcase.txns.isIndirectChanges; }\n\n /** throw if locks are currently required and the exclusive lock is not held on the supplied element */\n public checkExclusiveLock(id: Id64String, type: string, operation: string) {\n if (this._locksAreRequired && !this.holdsExclusiveLock(id))\n throw new IModelError(IModelStatus.LockNotHeld, `exclusive lock not held on ${type} for ${operation} (id=${id})`);\n }\n\n /** throw if locks are currently required and a shared lock is not held on the supplied element */\n public checkSharedLock(id: Id64String, type: string, operation: string) {\n if (this._locksAreRequired && !this.holdsSharedLock(id))\n throw new IModelError(IModelStatus.LockNotHeld, `shared lock not held on ${type} for ${operation} (id=${id})`);\n }\n\n}\n\n"]}
1
+ {"version":3,"file":"ServerBasedLocks.js","sourceRoot":"","sources":["../../src/ServerBasedLocks.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\n\r\n/** @packageDocumentation\r\n * @module iModels\r\n */\r\n\r\nimport { DbResult, Id64, Id64Arg, Id64String, IModelStatus, OpenMode } from \"@itwin/core-bentley\";\r\nimport { IModel, IModelError } from \"@itwin/core-common\";\r\nimport { LockMap, LockState } from \"./BackendHubAccess\";\r\nimport { BriefcaseDb, LockControl } from \"./IModelDb\";\r\nimport { IModelHost } from \"./IModelHost\";\r\nimport { SQLiteDb } from \"./SQLiteDb\";\r\n\r\n/**\r\n * Both the Model and Parent of an element are considered \"owners\" of their member elements. That means:\r\n * 1) they must hold at least a shared lock before an exclusive lock can be acquired for their members\r\n * 2) if they hold an exclusive lock, then all of their members are exclusively locked implicitly.\r\n * @internal\r\n */\r\nexport interface ElementOwners {\r\n readonly modelId: Id64String;\r\n readonly parentId: Id64String | undefined;\r\n}\r\n\r\n// eslint-disable-next-line no-restricted-syntax\r\nconst enum LockOrigin {\r\n Acquired = 0,\r\n NewElement = 1,\r\n Discovered = 2,\r\n}\r\n\r\n/** @internal */\r\nexport class ServerBasedLocks implements LockControl {\r\n public get isServerBased() { return true; }\r\n protected readonly lockDb = new SQLiteDb();\r\n protected readonly briefcase: BriefcaseDb;\r\n\r\n public constructor(iModel: BriefcaseDb) {\r\n this.briefcase = iModel;\r\n const dbName = `${iModel.nativeDb.getTempFileBaseName()}-locks`;\r\n try {\r\n this.lockDb.openDb(dbName, OpenMode.ReadWrite);\r\n } catch (_e) {\r\n this.lockDb.createDb(dbName);\r\n this.lockDb.executeSQL(\"CREATE TABLE locks(id INTEGER PRIMARY KEY NOT NULL,state INTEGER NOT NULL,origin INTEGER)\");\r\n this.lockDb.saveChanges();\r\n }\r\n }\r\n\r\n public close() {\r\n if (this.lockDb.isOpen)\r\n this.lockDb.closeDb();\r\n }\r\n\r\n private getOwners(id: Id64String): ElementOwners {\r\n return this.briefcase.withPreparedSqliteStatement(\"SELECT ModelId,ParentId FROM bis_Element WHERE id=?\", (stmt) => {\r\n stmt.bindId(1, id);\r\n const rc = stmt.step();\r\n if (DbResult.BE_SQLITE_ROW !== rc)\r\n throw new IModelError(rc, `element ${id} not found`);\r\n\r\n return { modelId: stmt.getValueId(0), parentId: stmt.getValueId(1) };\r\n });\r\n }\r\n\r\n private getLockState(id?: Id64String): LockState | undefined {\r\n return (id === undefined || !Id64.isValid(id)) ? undefined : this.lockDb.withPreparedSqliteStatement(\"SELECT state FROM locks WHERE id=?\", (stmt) => {\r\n stmt.bindId(1, id);\r\n return (DbResult.BE_SQLITE_ROW === stmt.step()) ? stmt.getValueInteger(0) : undefined;\r\n });\r\n }\r\n\r\n /** Clear the cache of locally held locks.\r\n * Note: does *not* release locks from server.\r\n */\r\n private clearAllLocks() {\r\n this.lockDb.executeSQL(\"DELETE FROM locks\");\r\n this.lockDb.saveChanges();\r\n }\r\n\r\n /** only for tests */\r\n public getLockCount(state: LockState): number {\r\n return this.lockDb.withSqliteStatement(\"SELECT count(*) FROM locks WHERE state=?\", (stmt) => {\r\n stmt.bindInteger(1, state);\r\n stmt.step();\r\n return stmt.getValueInteger(0);\r\n });\r\n }\r\n\r\n public async releaseAllLocks(): Promise<void> {\r\n await IModelHost.hubAccess.releaseAllLocks(this.briefcase); // throws if unsuccessful\r\n this.clearAllLocks();\r\n }\r\n\r\n private insertLock(id: Id64String, state: LockState, origin: LockOrigin): true {\r\n this.lockDb.withPreparedSqliteStatement(\"INSERT INTO locks(id,state,origin) VALUES (?,?,?) ON CONFLICT(id) DO UPDATE SET state=excluded.state,origin=excluded.origin\", (stmt) => {\r\n stmt.bindId(1, id);\r\n stmt.bindInteger(2, state);\r\n stmt.bindInteger(3, origin);\r\n const rc = stmt.step();\r\n if (DbResult.BE_SQLITE_DONE !== rc)\r\n throw new IModelError(rc, \"can't insert lock into database\");\r\n });\r\n return true;\r\n }\r\n\r\n private ownerHoldsExclusiveLock(id: Id64String | undefined): boolean {\r\n if (id === undefined || id === IModel.rootSubjectId)\r\n return false; // has no owners\r\n\r\n const { modelId, parentId } = this.getOwners(id);\r\n if (this.getLockState(modelId) === LockState.Exclusive || this.getLockState(parentId) === LockState.Exclusive)\r\n return true;\r\n\r\n // see if this model is exclusively locked by one of its owners. If so, save that fact on modelId so future tests won't have to descend.\r\n if (this.ownerHoldsExclusiveLock(modelId))\r\n return this.insertLock(modelId, LockState.Exclusive, LockOrigin.Discovered);\r\n\r\n // see if the parent is exclusively locked by one of its owners. If so, save that fact on parentId so future tests won't have to descend.\r\n return this.ownerHoldsExclusiveLock(parentId) ? this.insertLock(parentId!, LockState.Exclusive, LockOrigin.Discovered) : false; // eslint-disable-line @typescript-eslint/no-non-null-assertion\r\n }\r\n\r\n /** Determine whether an the exclusive lock is already held by an element (or one of its owners) */\r\n public holdsExclusiveLock(id: Id64String): boolean {\r\n // see if we hold the exclusive lock. or if one of the element's owners is exclusively locked (recursively)\r\n return this.getLockState(id) === LockState.Exclusive || this.ownerHoldsExclusiveLock(id);\r\n }\r\n\r\n public holdsSharedLock(id: Id64String): boolean {\r\n const state = this.getLockState(id);\r\n // see if we hold shared or exclusive lock, or if an owner has exclusive lock. If so we implicitly have shared lock, but owner holding shared lock doesn't help.\r\n return (state === LockState.Shared || state === LockState.Exclusive) || this.ownerHoldsExclusiveLock(id);\r\n }\r\n\r\n /** if the shared lock on the element supplied is not already held, add it to the set of shared locks required. Then, check owners. */\r\n private addSharedLock(id: Id64String | undefined, locks: Set<Id64String>) {\r\n // if the id is not valid, or of the lock is already in the set, or if we already hold a shared lock, we're done\r\n // Note: if we hold a shared lock, it is guaranteed that we also hold all required shared locks on owners.\r\n if (id === undefined || !Id64.isValid(id) || locks.has(id) || this.holdsSharedLock(id))\r\n return;\r\n\r\n locks.add(id); // add to set of needed shared locks\r\n this.addOwnerSharedLocks(id, locks); // check parent models and groups\r\n }\r\n\r\n /** add owners (recursively) of an element to a list of required shared locks, if not already held. */\r\n private addOwnerSharedLocks(id: Id64String, locks: Set<Id64String>) {\r\n const el = this.getOwners(id);\r\n this.addSharedLock(el.parentId, locks); // if this element is in a group\r\n this.addSharedLock(el.modelId, locks); // check its model\r\n }\r\n\r\n /** attempt to acquire all necessary locks for a set of elements */\r\n private async acquireAllLocks(locks: LockMap) {\r\n if (locks.size === 0) // no locks are required.\r\n return;\r\n\r\n const sharedLocks = new Set<Id64String>();\r\n for (const lock of locks)\r\n this.addOwnerSharedLocks(lock[0], sharedLocks);\r\n\r\n for (const shared of sharedLocks) {\r\n if (!locks.has(shared)) // we may already be asking for exclusive lock\r\n locks.set(shared, LockState.Shared);\r\n }\r\n\r\n await IModelHost.hubAccess.acquireLocks(this.briefcase, locks); // throws if unsuccessful\r\n for (const lock of locks)\r\n this.insertLock(lock[0], lock[1], LockOrigin.Acquired);\r\n this.lockDb.saveChanges();\r\n }\r\n\r\n public async acquireLocks(arg: { shared?: Id64Arg, exclusive?: Id64Arg }): Promise<void> {\r\n const locks = new Map<Id64String, LockState>();\r\n if (arg.shared) {\r\n for (const id of Id64.iterable(arg.shared)) {\r\n if (!this.holdsSharedLock(id))\r\n locks.set(id, LockState.Shared);\r\n }\r\n }\r\n if (arg.exclusive) {\r\n for (const id of Id64.iterable(arg.exclusive)) {\r\n if (!this.holdsExclusiveLock(id))\r\n locks.set(id, LockState.Exclusive);\r\n }\r\n }\r\n return this.acquireAllLocks(locks);\r\n }\r\n\r\n /** When an element is newly created in a session, we hold the lock on it implicitly. Save that fact. */\r\n public elementWasCreated(id: Id64String) {\r\n this.insertLock(id, LockState.Exclusive, LockOrigin.NewElement);\r\n this.lockDb.saveChanges();\r\n }\r\n\r\n /** locks are not necessary during change propagation. */\r\n private get _locksAreRequired() { return !this.briefcase.txns.isIndirectChanges; }\r\n\r\n /** throw if locks are currently required and the exclusive lock is not held on the supplied element */\r\n public checkExclusiveLock(id: Id64String, type: string, operation: string) {\r\n if (this._locksAreRequired && !this.holdsExclusiveLock(id))\r\n throw new IModelError(IModelStatus.LockNotHeld, `exclusive lock not held on ${type} for ${operation} (id=${id})`);\r\n }\r\n\r\n /** throw if locks are currently required and a shared lock is not held on the supplied element */\r\n public checkSharedLock(id: Id64String, type: string, operation: string) {\r\n if (this._locksAreRequired && !this.holdsSharedLock(id))\r\n throw new IModelError(IModelStatus.LockNotHeld, `shared lock not held on ${type} for ${operation} (id=${id})`);\r\n }\r\n\r\n}\r\n\r\n"]}