Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ConflictingLocksError class (backport #6852) [release/4.7.x] #6898

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions common/api/core-backend.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ import { LineStyleProps } from '@itwin/core-common';
import { LocalBriefcaseProps } from '@itwin/core-common';
import { LocalDirName } from '@itwin/core-common';
import { LocalFileName } from '@itwin/core-common';
import { LockState as LockState_2 } from '@itwin/core-common';
import { LogLevel } from '@itwin/core-bentley';
import { LowAndHighXYZ } from '@itwin/core-geometry';
import { MarkRequired } from '@itwin/core-bentley';
Expand Down Expand Up @@ -4024,15 +4025,15 @@ export interface LockControl {
}

// @internal (undocumented)
export type LockMap = Map<Id64String, LockState>;
export type LockMap = Map<Id64String, LockState_2>;

// @beta
export interface LockProps {
readonly id: Id64String;
readonly state: LockState;
readonly state: LockState_2;
}

// @public
// @public @deprecated
export enum LockState {
Exclusive = 2,
None = 0,
Expand All @@ -4046,7 +4047,7 @@ export interface LockStatusExclusive {
// (undocumented)
lastCsIndex?: ChangesetIndex;
// (undocumented)
state: LockState.Exclusive;
state: LockState_2.Exclusive;
}

// @internal
Expand All @@ -4056,7 +4057,7 @@ export interface LockStatusShared {
// (undocumented)
sharedBy: Set<BriefcaseId>;
// (undocumented)
state: LockState.Shared;
state: LockState_2.Shared;
}

// @internal
Expand Down
21 changes: 21 additions & 0 deletions common/api/core-common.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1639,6 +1639,20 @@ export namespace ConcreteEntityTypes {
export function toBisCoreRootClassFullName(type: ConcreteEntityTypes): string;
}

// @public
export interface ConflictingLock {
briefcaseIds: number[];
objectId: string;
state: LockState;
}

// @public
export class ConflictingLocksError extends IModelError {
constructor(message: string, getMetaData?: LoggingMetaData, conflictingLocks?: ConflictingLock[]);
// (undocumented)
conflictingLocks?: ConflictingLock[];
}

// @alpha
export enum ContentFlags {
// (undocumented)
Expand Down Expand Up @@ -5523,6 +5537,13 @@ export interface Localization {
unregisterNamespace(namespace: string): void;
}

// @public
export enum LockState {
Exclusive = 2,
None = 0,
Shared = 1
}

export { LogFunction }

export { LoggingMetaData }
Expand Down
1 change: 1 addition & 0 deletions common/api/summary/core-backend.exports.csv
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ beta;LockControl
internal;LockMap = Map
beta;LockProps
public;LockState
deprecated;LockState
internal;LockStatusExclusive
internal;LockStatusShared
internal;MetaDataRegistry
Expand Down
3 changes: 3 additions & 0 deletions common/api/summary/core-common.exports.csv
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ internal;computeTileChordTolerance(tile: TileMetadata, is3d: boolean, tileScreen
alpha;ConcreteEntityTypes
alpha;ConcreteEntityTypes
internal;toBisCoreRootClassFullName(type: ConcreteEntityTypes): string
public;ConflictingLock
public;ConflictingLocksError
alpha;ContentFlags
internal;class ContentIdProvider
public;ContextRealityModel
Expand Down Expand Up @@ -459,6 +461,7 @@ public;LocalBriefcaseProps
public;LocalDirName = string
public;LocalFileName = string
public;Localization
public;LockState
public;MapImageryProps
public;MapImagerySettings
public;MapLayerKey
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@itwin/core-backend",
"comment": "",
"type": "none"
}
],
"packageName": "@itwin/core-backend"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@itwin/core-common",
"comment": "add ConflictingLocksError",
"type": "none"
}
],
"packageName": "@itwin/core-common"
}
37 changes: 20 additions & 17 deletions core/backend/src/BackendHubAccess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,12 @@
import { AccessToken, GuidString, Id64String, IModelHubStatus } from "@itwin/core-bentley";
import {
BriefcaseId, ChangesetFileProps, ChangesetIdWithIndex, ChangesetIndex, ChangesetIndexAndId, ChangesetIndexOrId, ChangesetProps, ChangesetRange,
IModelError, IModelVersion, LocalDirName, LocalFileName,
LockState as CommonLockState, IModelError, IModelVersion,
LocalDirName, LocalFileName,
} from "@itwin/core-common";
import { CheckpointProps, DownloadRequest, ProgressFunction } from "./CheckpointManager";
import type { TokenArg } from "./IModelDb";

/** The state of a lock.
* @public
*/
export enum LockState {
/** The element is not locked */
None = 0,
/** Holding a shared lock on an element blocks other users from acquiring the Exclusive lock it. More than one user may acquire the shared lock. */
Shared = 1,
/** A Lock that permits modifications to an element and blocks other users from making modifications to it.
* Holding an exclusive lock on an "owner" (a model or a parent element), implicitly exclusively locks all its members.
*/
Exclusive = 2,
}

/** Exception thrown if lock cannot be acquired.
* @beta
*/
Expand All @@ -43,6 +30,21 @@ export class LockConflict extends IModelError {
}
}

/** The state of a lock. See [Acquiring locks on elements.]($docs/learning/backend/ConcurrencyControl.md#acquiring-locks-on-elements).
* @deprecated in 4.7 Use [LockState]($common)
* @public
*/
export enum LockState {
/** The element is not locked */
None = 0,
/** Holding a shared lock on an element blocks other users from acquiring the Exclusive lock it. More than one user may acquire the shared lock. */
Shared = 1,
/** A Lock that permits modifications to an element and blocks other users from making modifications to it.
* Holding an exclusive lock on an "owner" (a model or a parent element), implicitly exclusively locks all its members.
*/
Exclusive = 2,
}

/**
* The properties to access a V2 checkpoint through a daemon.
* @internal
Expand All @@ -61,7 +63,7 @@ export interface V2CheckpointAccessProps {
}

/** @internal */
export type LockMap = Map<Id64String, LockState>;
export type LockMap = Map<Id64String, CommonLockState>;

/**
* The properties of a lock that may be obtained from a lock server.
Expand All @@ -71,7 +73,7 @@ export interface LockProps {
/** The elementId for the lock */
readonly id: Id64String;
/** the lock state */
readonly state: LockState;
readonly state: CommonLockState;
}

/**
Expand Down Expand Up @@ -232,6 +234,7 @@ export interface BackendHubAccess {
/**
* acquire one or more locks. Throws if unsuccessful. If *any* lock cannot be obtained, no locks are acquired
* @internal
* @throws ConflictingLocksError if one or more requested locks are held by other briefcases.
*/
acquireLocks: (arg: BriefcaseDbArg, locks: LockMap) => Promise<void>;

Expand Down
1 change: 1 addition & 0 deletions core/backend/src/IModelDb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ export interface LockControl {
* If any required lock is not available, this method throws an exception and *none* of the requested locks are acquired.
* > Note: acquiring the exclusive lock on an element requires also obtaining a shared lock on all its owner elements. This method will
* attempt to acquire all necessary locks for both sets of input ids.
* @throws ConflictingLocksError if one or more requested locks are held by other briefcases.
*/
acquireLocks(arg: {
/** if present, one or more elements to obtain shared lock */
Expand Down
4 changes: 2 additions & 2 deletions core/backend/src/LocalHub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import { join } from "path";
import { DbResult, GuidString, Id64String, IModelHubStatus, IModelStatus, OpenMode } from "@itwin/core-bentley";
import {
BriefcaseId, BriefcaseIdValue, ChangesetFileProps, ChangesetId, ChangesetIdWithIndex, ChangesetIndex, ChangesetIndexOrId, ChangesetProps,
ChangesetRange, IModelError, LocalDirName, LocalFileName,
ChangesetRange, IModelError, LocalDirName, LocalFileName, LockState,
} from "@itwin/core-common";
import { LockConflict, LockMap, LockProps, LockState } from "./BackendHubAccess";
import { LockConflict, LockMap, LockProps } from "./BackendHubAccess";
import { BriefcaseManager } from "./BriefcaseManager";
import { BriefcaseLocalValue, IModelDb, SnapshotDb } from "./IModelDb";
import { IModelJsFs } from "./IModelJsFs";
Expand Down
4 changes: 2 additions & 2 deletions core/backend/src/ServerBasedLocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
*/

import { DbResult, Id64, Id64Arg, Id64String, IModelStatus, OpenMode } from "@itwin/core-bentley";
import { IModel, IModelError } from "@itwin/core-common";
import { LockMap, LockState } from "./BackendHubAccess";
import { IModel, IModelError, LockState } from "@itwin/core-common";
import { LockMap } from "./BackendHubAccess";
import { BriefcaseDb, LockControl } from "./IModelDb";
import { IModelHost } from "./IModelHost";
import { SQLiteDb } from "./SQLiteDb";
Expand Down
4 changes: 2 additions & 2 deletions core/backend/src/test/standalone/HubMock.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
import { assert, expect } from "chai";
import { join } from "path";
import { AccessToken, Guid, Mutable } from "@itwin/core-bentley";
import { ChangesetFileProps, ChangesetType } from "@itwin/core-common";
import { LockProps, LockState } from "../../BackendHubAccess";
import { ChangesetFileProps, ChangesetType, LockState } from "@itwin/core-common";
import { LockProps } from "../../BackendHubAccess";
import { BriefcaseManager } from "../../BriefcaseManager";
import { IModelHost } from "../../IModelHost";
import { IModelJsFs } from "../../IModelJsFs";
Expand Down
5 changes: 3 additions & 2 deletions core/backend/src/test/standalone/IModelWrite.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import { AccessToken, DbResult, GuidString, Id64, Id64String } from "@itwin/core-bentley";
import {
Code, ColorDef,
GeometricElement2dProps, GeometryStreamProps, IModel, QueryRowFormat, RequestNewBriefcaseProps, SchemaState, SubCategoryAppearance,
GeometricElement2dProps, GeometryStreamProps, IModel, LockState, QueryRowFormat, RequestNewBriefcaseProps, SchemaState, SubCategoryAppearance,
} from "@itwin/core-common";
import { Arc3d, IModelJson, Point2d, Point3d } from "@itwin/core-geometry";
import * as chai from "chai";
Expand All @@ -23,7 +23,8 @@ import {
BriefcaseDb,
BriefcaseManager,
ChannelControl,
DefinitionModel, DictionaryModel, DocumentListModel, Drawing, DrawingGraphic, LockState, OpenBriefcaseArgs, SpatialCategory, Subject,
CodeService,
DefinitionModel, DictionaryModel, DocumentListModel, Drawing, DrawingGraphic, OpenBriefcaseArgs, SpatialCategory, Subject,
} from "../../core-backend";
import { IModelTestUtils, TestUserType } from "../IModelTestUtils";
import { ServerBasedLocks } from "../../ServerBasedLocks";
Expand Down
3 changes: 1 addition & 2 deletions core/backend/src/test/standalone/ServerBasedLocks.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
import { assert, expect } from "chai";
import { restore as sinonRestore, spy as sinonSpy } from "sinon";
import { AccessToken, GuidString, Id64, Id64Arg } from "@itwin/core-bentley";
import { Code, IModel, IModelError, LocalBriefcaseProps, PhysicalElementProps, RequestNewBriefcaseProps } from "@itwin/core-common";
import { LockState } from "../../BackendHubAccess";
import { Code, IModel, IModelError, LocalBriefcaseProps, LockState, PhysicalElementProps, RequestNewBriefcaseProps } from "@itwin/core-common";
import { BriefcaseManager } from "../../BriefcaseManager";
import { PhysicalObject } from "../../domains/GenericElements";
import { PhysicalElement } from "../../Element";
Expand Down
46 changes: 45 additions & 1 deletion core/common/src/IModelError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

import {
BentleyError, BentleyStatus, BriefcaseStatus, ChangeSetStatus, DbResult, IModelStatus, LoggingMetaData, RepositoryStatus,
BentleyError, BentleyStatus, BriefcaseStatus, ChangeSetStatus, DbResult, IModelHubStatus, IModelStatus, LoggingMetaData, RepositoryStatus,
} from "@itwin/core-bentley";

export {
Expand All @@ -32,6 +32,50 @@ export class IModelError extends BentleyError {
}
}

/** The state of a lock. See [Acquiring locks on elements.]($docs/learning/backend/ConcurrencyControl.md#acquiring-locks-on-elements).
* @public
*/
export enum LockState {
/** The element is not locked */
None = 0,
/** Holding a shared lock on an element blocks other users from acquiring the Exclusive lock it. More than one user may acquire the shared lock. */
Shared = 1,
/** A Lock that permits modifications to an element and blocks other users from making modifications to it.
* Holding an exclusive lock on an "owner" (a model or a parent element), implicitly exclusively locks all its members.
*/
Exclusive = 2,
}

/** Detailed information about a particular object Lock that is causing the Lock update conflict.
* An example of a lock update conflict would be attempting to use [LockControl.acquireLocks]($backend) on an object that is already locked by another Briefcase.
* @public
*/
export interface ConflictingLock {
/** Id of the object that is causing conflict. */
objectId: string;
/**
* The level of conflicting lock. Possible values are {@link LockState.Shared}, {@link LockState.Exclusive}.
* See {@link LockState}.
*/
state: LockState;
/** An array of Briefcase ids that hold this lock. */
briefcaseIds: number[];
}

/**
* An error raised when there is a lock conflict detected.
* Typically this error would be thrown by [LockControl.acquireLocks]($backend) when you are requesting a lock on an element that is already held by another briefcase.
* @public
*/
export class ConflictingLocksError extends IModelError {
public conflictingLocks?: ConflictingLock[];
constructor(message: string, getMetaData?: LoggingMetaData, conflictingLocks?: ConflictingLock[]) {
super(IModelHubStatus.LockOwnedByAnotherBriefcase, message, getMetaData);
this.conflictingLocks = conflictingLocks;
}

}

/** @public */
export class ServerError extends IModelError {
public constructor(errorNumber: number, message: string) {
Expand Down
Loading