Lightweight 0.20251202.0
Loading...
Searching...
No Matches
SqlMigrationLock.hpp
1// SPDX-License-Identifier: Apache-2.0
2
3#pragma once
4
5#include "Api.hpp"
6#include "SqlConnection.hpp"
7
8#include <chrono>
9#include <string>
10#include <string_view>
11
12namespace Lightweight::SqlMigration
13{
14
15/// RAII-style migration lock to prevent concurrent migrations.
16///
17/// This class provides a distributed locking mechanism to ensure that only one process
18/// can run migrations at a time. The implementation uses database-specific advisory locks:
19/// - SQL Server: sp_getapplock / sp_releaseapplock
20/// - PostgreSQL: pg_advisory_lock / pg_advisory_unlock
21/// - SQLite: BEGIN IMMEDIATE transaction with PRAGMA busy_timeout
22///
23/// @code
24/// auto& connection = migrationManager.GetDataMapper().Connection();
25/// MigrationLock lock(connection);
26/// if (lock.IsLocked())
27/// {
28/// migrationManager.ApplyPendingMigrations();
29/// }
30/// @endcode
31///
32/// @ingroup SqlMigration
34{
35 public:
36 /// Acquire a migration lock.
37 ///
38 /// @param connection Database connection to use for locking
39 /// @param lockName Name of the lock (default: "lightweight_migration")
40 /// @param timeout Maximum time to wait for lock acquisition
41 /// @throws SqlException if lock cannot be acquired within timeout
42 LIGHTWEIGHT_API explicit MigrationLock(SqlConnection& connection,
43 std::string_view lockName = "lightweight_migration",
44 std::chrono::milliseconds timeout = std::chrono::seconds(30));
45
46 /// Releases the lock on destruction.
47 LIGHTWEIGHT_API ~MigrationLock();
48
49 MigrationLock(MigrationLock const&) = delete;
50 MigrationLock& operator=(MigrationLock const&) = delete;
51
52 /// Move constructor.
53 LIGHTWEIGHT_API MigrationLock(MigrationLock&& other) noexcept;
54
55 /// Move assignment operator.
56 LIGHTWEIGHT_API MigrationLock& operator=(MigrationLock&& other) noexcept;
57
58 /// Check if lock is held.
59 ///
60 /// @return true if the lock is currently held by this instance
61 [[nodiscard]] bool IsLocked() const noexcept
62 {
63 return _locked;
64 }
65
66 /// Release the lock early.
67 ///
68 /// This is automatically called in the destructor, but can be called
69 /// manually if early release is desired.
70 LIGHTWEIGHT_API void Release();
71
72 private:
73 SqlConnection* _connection;
74 std::string _lockName;
75 bool _locked { false };
76
77 void AcquireLock(std::chrono::milliseconds timeout);
78 void ReleaseLock();
79
80 void AcquireLockSqlServer(std::chrono::milliseconds timeout);
81 void ReleaseLockSqlServer();
82
83 void AcquireLockPostgreSQL(std::chrono::milliseconds timeout);
84 void ReleaseLockPostgreSQL();
85
86 void AcquireLockSQLite(std::chrono::milliseconds timeout);
87 void ReleaseLockSQLite();
88};
89
90} // namespace Lightweight::SqlMigration
Represents a connection to a SQL database.
LIGHTWEIGHT_API ~MigrationLock()
Releases the lock on destruction.
LIGHTWEIGHT_API MigrationLock(MigrationLock &&other) noexcept
Move constructor.
LIGHTWEIGHT_API MigrationLock & operator=(MigrationLock &&other) noexcept
Move assignment operator.
LIGHTWEIGHT_API MigrationLock(SqlConnection &connection, std::string_view lockName="lightweight_migration", std::chrono::milliseconds timeout=std::chrono::seconds(30))