Mercurial > hg > orthanc-databases
comparison Framework/PostgreSQL/PostgreSQLDatabase.cpp @ 134:cc3dc759c989
Added an advisory lock to avoid race conditions during database setup
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 08 May 2019 20:21:13 +0200 |
parents | 5765cc5fd268 |
children | 4cd7e45b671e |
comparison
equal
deleted
inserted
replaced
133:b1d7d255fb73 | 134:cc3dc759c989 |
---|---|
29 | 29 |
30 #include <Core/Logging.h> | 30 #include <Core/Logging.h> |
31 #include <Core/OrthancException.h> | 31 #include <Core/OrthancException.h> |
32 | 32 |
33 #include <boost/lexical_cast.hpp> | 33 #include <boost/lexical_cast.hpp> |
34 #include <boost/thread.hpp> | |
34 | 35 |
35 | 36 |
36 namespace OrthancDatabases | 37 namespace OrthancDatabases |
37 { | 38 { |
38 void PostgreSQLDatabase::ThrowException(bool log) | 39 void PostgreSQLDatabase::ThrowException(bool log) |
107 throw Orthanc::OrthancException(Orthanc::ErrorCode_DatabaseUnavailable); | 108 throw Orthanc::OrthancException(Orthanc::ErrorCode_DatabaseUnavailable); |
108 } | 109 } |
109 } | 110 } |
110 | 111 |
111 | 112 |
113 bool PostgreSQLDatabase::RunAdvisoryLockStatement(const std::string& statement) | |
114 { | |
115 PostgreSQLTransaction transaction(*this); | |
116 | |
117 Query query(statement, false); | |
118 PostgreSQLStatement s(*this, query); | |
119 | |
120 PostgreSQLResult result(s); | |
121 | |
122 bool success = (!result.IsDone() && | |
123 result.GetBoolean(0)); | |
124 | |
125 transaction.Commit(); | |
126 | |
127 return success; | |
128 } | |
129 | |
130 | |
131 bool PostgreSQLDatabase::AcquireAdvisoryLock(int32_t lock) | |
132 { | |
133 return RunAdvisoryLockStatement( | |
134 "select pg_try_advisory_lock(" + | |
135 boost::lexical_cast<std::string>(lock) + ")"); | |
136 } | |
137 | |
138 | |
139 bool PostgreSQLDatabase::ReleaseAdvisoryLock(int32_t lock) | |
140 { | |
141 return RunAdvisoryLockStatement( | |
142 "select pg_advisory_unlock(" + | |
143 boost::lexical_cast<std::string>(lock) + ")"); | |
144 } | |
145 | |
146 | |
112 void PostgreSQLDatabase::AdvisoryLock(int32_t lock) | 147 void PostgreSQLDatabase::AdvisoryLock(int32_t lock) |
113 { | 148 { |
114 PostgreSQLTransaction transaction(*this); | 149 if (!AcquireAdvisoryLock(lock)) |
115 | |
116 Query query("select pg_try_advisory_lock(" + | |
117 boost::lexical_cast<std::string>(lock) + ");", false); | |
118 PostgreSQLStatement s(*this, query); | |
119 | |
120 PostgreSQLResult result(s); | |
121 if (result.IsDone() || | |
122 !result.GetBoolean(0)) | |
123 { | 150 { |
124 LOG(ERROR) << "The PostgreSQL database is locked by another instance of Orthanc"; | 151 LOG(ERROR) << "The PostgreSQL database is locked by another instance of Orthanc"; |
125 throw Orthanc::OrthancException(Orthanc::ErrorCode_Database); | 152 throw Orthanc::OrthancException(Orthanc::ErrorCode_Database); |
126 } | 153 } |
127 | |
128 transaction.Commit(); | |
129 } | 154 } |
130 | 155 |
131 | 156 |
132 void PostgreSQLDatabase::Execute(const std::string& sql) | 157 void PostgreSQLDatabase::Execute(const std::string& sql) |
133 { | 158 { |
241 else | 266 else |
242 { | 267 { |
243 return new PostgreSQLTransaction(*this); | 268 return new PostgreSQLTransaction(*this); |
244 } | 269 } |
245 } | 270 } |
271 | |
272 | |
273 PostgreSQLDatabase::TransientAdvisoryLock::TransientAdvisoryLock( | |
274 PostgreSQLDatabase& database, | |
275 int32_t lock) : | |
276 database_(database), | |
277 lock_(lock) | |
278 { | |
279 bool locked = true; | |
280 | |
281 for (unsigned int i = 0; i < 10; i++) | |
282 { | |
283 if (database_.AcquireAdvisoryLock(lock_)) | |
284 { | |
285 locked = false; | |
286 break; | |
287 } | |
288 else | |
289 { | |
290 boost::this_thread::sleep(boost::posix_time::milliseconds(500)); | |
291 } | |
292 } | |
293 | |
294 if (locked) | |
295 { | |
296 LOG(ERROR) << "Cannot acquire a transient advisory lock"; | |
297 throw Orthanc::OrthancException(Orthanc::ErrorCode_Plugin); | |
298 } | |
299 } | |
300 | |
301 | |
302 PostgreSQLDatabase::TransientAdvisoryLock::~TransientAdvisoryLock() | |
303 { | |
304 database_.ReleaseAdvisoryLock(lock_); | |
305 } | |
246 } | 306 } |