Class LockManager

Class Documentation

class LockManager

Transport-agnostic lock manager for SOVD entity locking.

Manages exclusive locks on entities with optional scope restrictions. Supports parent-child lock propagation: a lock on a Component denies access to its Apps, and a lock on an Area denies access to its Components and their Apps.

Thread safety: uses shared_mutex (shared_lock for reads, unique_lock for writes). All public methods are thread-safe.

Design:

  • Primary storage: unordered_map<entity_id, LockInfo>

  • Secondary index: unordered_map<lock_id, entity_id>

  • One lock per entity (acquire on already-locked entity returns error unless break_lock=true)

  • Empty scopes = all collections locked

  • Parent propagation via EntityCache lookups (App->Component->Area)

Public Functions

LockManager(const ThreadSafeEntityCache &cache, LockConfig config)

Construct a LockManager.

Parameters:
  • cache – Reference to the entity cache for parent-chain lookups

  • config – Lock configuration

tl::expected<LockInfo, LockError> acquire(const std::string &entity_id, const std::string &client_id, const std::vector<std::string> &scopes, int expiration_seconds, bool break_lock = false)

Acquire a lock on an entity.

Parameters:
  • entity_id – Entity to lock

  • client_id – Client requesting the lock

  • scopes – Resource collections to lock (empty = all)

  • expiration_seconds – Lock duration in seconds

  • break_lock – If true, forcefully replace existing lock

Returns:

LockInfo on success, LockError on failure

tl::expected<void, LockError> release(const std::string &entity_id, const std::string &client_id)

Release a lock.

Parameters:
  • entity_id – Entity to unlock

  • client_id – Client requesting release (must match lock owner)

Returns:

Empty on success, LockError on failure

tl::expected<LockInfo, LockError> extend(const std::string &entity_id, const std::string &client_id, int additional_seconds)

Extend a lock’s expiration.

Parameters:
  • entity_id – Locked entity

  • client_id – Client requesting extension (must match lock owner)

  • additional_seconds – Seconds to add from now

Returns:

Updated LockInfo on success, LockError on failure

std::optional<LockInfo> get_lock(const std::string &entity_id) const

Get lock info for an entity.

Parameters:

entity_id – Entity to query

Returns:

LockInfo if locked, nullopt otherwise

std::optional<LockInfo> get_lock_by_id(const std::string &lock_id) const

Get lock info by lock ID.

Parameters:

lock_id – Lock identifier

Returns:

LockInfo if found, nullopt otherwise

LockAccessResult check_access(const std::string &entity_id, const std::string &client_id, const std::string &collection) const

Check if a client can access a resource collection on an entity.

Two-phase check:

  1. If lock_required is configured and no lock is held by client, deny

  2. Check lock conflict: walks up parent chain (App->Component->Area) checking for locks that cover the requested collection

Parameters:
  • entity_id – Entity being accessed

  • client_id – Client requesting access (empty = anonymous)

  • collection – Resource collection being accessed

Returns:

LockAccessResult indicating whether access is allowed

std::vector<ExpiredLockInfo> cleanup_expired()

Remove expired locks.

Returns:

List of expired locks that were removed

inline const LockConfig &config() const

Get the lock configuration.