Files
DP44/enriched-qwen3-coder-next/Common/DTS.Common/Classes/Locking.md
2026-04-17 14:55:32 -04:00

136 lines
8.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
source_files:
- Common/DTS.Common/Classes/Locking/LockRecord.cs
- Common/DTS.Common/Classes/Locking/LockError.cs
- Common/DTS.Common/Classes/Locking/SensorsLocking.cs
generated_at: "2026-04-16T03:16:01.173429+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "4c9a49fc0d53b85f"
---
# Locking
## Documentation: `DTS.Common.Classes.Locking` Module
---
### 1. Purpose
This module provides infrastructure for managing application-level locks on sensor-related data items within a distributed system. It defines core data structures (`LockRecord`, `LockError`) to represent lock state and error conditions, and a high-level locking coordinator (`SensorsLocking`) responsible for maintaining and validating locks on behalf of UI components (e.g., sensor editing controls). The module supports lock renewal, theft detection, and loss handling, integrating with logging (`APILogger`), event aggregation (`Prism.Events`), and a lower-level `LockManager` (referenced but not included here) for persistence operations.
---
### 2. Public Interface
#### `LockRecord` Class
Represents a single active lock on a data item.
- **Constructor**
```csharp
public LockRecord(string user, string machine, DateTime createTime, DateTime lastUpdate, string itemKey, int itemCategory, int itemId)
```
Initializes a new lock record with the specified metadata. All properties are read-only after construction.
- **Properties**
- `string LockingUserName` Name of the user who acquired the lock.
- `string LockingMachineName` Hostname of the machine holding the lock.
- `DateTime CreationTime` Timestamp when the lock was first acquired.
- `DateTime LastUpdated` Timestamp of the last lock renewal/maintenance.
- `string ItemKey` Human-readable key identifying the locked item (e.g., sensor name).
- `int ItemCategory` Numeric category of the item (e.g., `LockCategories` enum value in DB).
- `int ItemId` Numeric ID of the locked item (e.g., sensor ID).
#### `LockError` Class
Encapsulates error information from lock operations.
- **Constructor**
```csharp
public LockError(int error, string message, string user = null, string machine = null)
```
Creates an error instance with code, message, and optional lock holder details.
- **Properties**
- `int ErrorCode` Numeric error code (see constants below).
- `string Message` Human-readable description.
- `string LockingUser` User associated with the lock at time of error (empty if unknown).
- `string LockingMachine` Machine associated with the lock at time of error (empty if unknown).
- `bool LockStolen => ErrorCode == LOCKSTOLEN_ERROR` Indicates the lock was forcibly released by another user.
- `bool LockLost => ErrorCode == LOCKDOESNTEXIST_ERROR` Indicates the lock no longer exists in the backing store.
- **Constants**
- `BAD_NETPATH_ERROR = 994` Network path error (e.g., lost remote DB connection).
- `SEM_TIMEOUT_ERROR = 995` Semaphore timeout (e.g., connection failure).
- `ITEM_NOT_FOUND = 996` Referenced item not found.
- `LOCKDOESNTEXIST_ERROR = 997` Lock record missing (lock lost).
- `LOCKSTOLEN_ERROR = 998` Lock stolen by another user.
- `UNKNOWN_ERROR = 999` Generic/unspecified error.
#### `SensorsLocking` Class
Manages lock lifecycle for sensor UI controls.
- **`Unlock(bool bCheckLock, string userName, int userId)`**
Stops background lock renewal and attempts to release all tracked locks via `FreeLocks()`. Logs exceptions but does not propagate them.
*Note: Parameter `bCheckLock` is unused in the current implementation.*
- **`IsCurrentlyLocked(LockRecord lockRecord)`**
```csharp
public bool IsCurrentlyLocked(LockRecord lockRecord)
```
Returns `true` if the provided `lockRecord` matches an item currently tracked by this instance (i.e., `ItemId` and `ItemCategory` match any entry in `_existingLocks`). Thread-safe via `MyLock`.
- **Private Methods (Referenced)**
- `StopUpdating()` Cancels background renewal task and waits up to `MAX_WAIT_TIME_MS` (10s) for completion. Returns `true` only if stopped cleanly.
- `FreeLocks()` Iterates over `_existingLocks` and calls `LockManager.FreeLoc` for each (implementation truncated in source).
- `CheckLocks(bool publishErrors, string userName, int userId)` Validates all tracked locks; on failure, clears `_existingLocks`, calls `WipeOutChanges()`, and publishes `PageErrorEvent` if `publishErrors` is `true`.
- `CheckLock(...)` *Not implemented* (`NotImplementedException`).
- `WipeOutChanges()` *Not implemented* (`NotImplementedException`).
- `GetErrorMessage(LockError[] errors, LockRecord[] lockRecords)` Builds a localized error message string for display, handling `LockStolen` and `LockLost` cases.
---
### 3. Invariants
- `_existingLocks` is always `null` or a non-null array (never partially initialized).
- Lock records in `_existingLocks` are only modified or cleared under the `MyLock` synchronization object.
- `LockRecord` instances are immutable after construction (all properties are `readonly` or get-only).
- `LockError.ErrorCode` is set once at construction and never modified.
- Lock renewal/maintenance is performed periodically via `_updateTask`; failure to renew triggers `CheckLocks()` failure.
- On *any* lock failure during `CheckLocks()`, `_existingLocks` is atomically reset to an empty array, and `WipeOutChanges()` is called (though implementation is missing).
- `LockManager.FreeLoc` is assumed to be the canonical method for releasing locks (external dependency).
---
### 4. Dependencies
#### **Internal Dependencies (from imports)**
- `DTS.Common.Events` For `PageErrorEvent` and `PageErrorArg`.
- `DTS.Common.SharedResource.Strings` For localized strings (`StringResources.FailedToUpdateLock`, `LockStolen_Sensors`, `LockLost_Sensors`).
- `DTS.Common.Utilities.Logging` For `APILogger`.
- `Prism.Events` For `IEventAggregator` and `ContainerLocator.Container`.
- `System.Threading.Tasks` For `Task`, `CancellationTokenSource`.
#### **External Dependencies (inferred)**
- `LockManager` Referenced in `FreeLocks()` but not defined in the provided source. Critical dependency for lock acquisition/release.
- `PageErrorEvent` A Prism event used to publish UI-level errors.
- `ContainerLocator.Container` Prism/IoC container for resolving services (e.g., `IEventAggregator`).
#### **Depended Upon By**
- UI controls (e.g., sensor editing forms) that need to track and release locks on sensor items.
- Likely used in conjunction with `LockManager` for end-to-end locking workflows.
---
### 5. Gotchas
- **`CheckLock` and `WipeOutChanges` are unimplemented** (`NotImplementedException`). This module is incomplete and non-functional as-is.
- **`bCheckLock` parameter in `Unlock()` is ignored** The method always proceeds to `FreeLocks()` regardless of its value.
- **`FreeLocks()` calls `LockManager.FreeLoc` without arguments** The source is truncated (`FreeLoc` call is cut off), so the exact signature and required parameters (e.g., `LockRecord`) are unknown.
- **`GetErrorMessage` uses `Array.Exists` with `ItemId`/`ItemCategory` but `IsCurrentlyLocked` does the same** Redundant logic suggests potential for refactoring or inconsistency if `LockRecord` equality semantics change.
- **No validation of `LockRecord` constructor parameters** No null checks on `user`, `machine`, or `itemKey`; invalid values (e.g., empty `ItemKey`) may propagate silently.
- **`LockingUser`/`LockingMachine` in `LockError` default to `string.Empty`** Not `null`, which simplifies UI display but may mask missing data.
- **`MAX_WAIT_TIME_MS = 10000` is hardcoded** No configuration or override mechanism for timeout duration.
- **Thread-safety relies on `MyLock` but is inconsistent** `IsCurrentlyLocked` uses `lock(MyLock)`, but `CheckLocks` and `FreeLocks` use `lock(MyLock)` only for reading `_existingLocks`; background task (`_updateTask`) state is managed separately.
- **No explicit lock acquisition methods** The module only handles *renewal* and *release* of *already-acquired* locks (via `LockManager`), implying lock acquisition happens elsewhere.
*None identified beyond the above.*