Mercurial > hg > orthanc-databases
comparison Framework/MySQL/MySQLDatabase.cpp @ 135:e26690365c25
MySQL: Added an advisory lock to avoid race conditions during database setup
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 08 May 2019 21:09:18 +0200 |
parents | 714c5d2bee76 |
children | 52b3859ee0b7 |
comparison
equal
deleted
inserted
replaced
134:cc3dc759c989 | 135:e26690365c25 |
---|---|
33 | 33 |
34 #include <errmsg.h> | 34 #include <errmsg.h> |
35 #include <mysqld_error.h> | 35 #include <mysqld_error.h> |
36 | 36 |
37 #include <memory> | 37 #include <memory> |
38 #include <boost/thread.hpp> | |
38 | 39 |
39 namespace OrthancDatabases | 40 namespace OrthancDatabases |
40 { | 41 { |
41 void MySQLDatabase::Close() | 42 void MySQLDatabase::Close() |
42 { | 43 { |
287 return false; | 288 return false; |
288 } | 289 } |
289 } | 290 } |
290 | 291 |
291 | 292 |
293 bool MySQLDatabase::RunAdvisoryLockStatement(const std::string& s) | |
294 { | |
295 Query query(s, false); | |
296 MySQLStatement statement(*this, query); | |
297 | |
298 MySQLTransaction t(*this); | |
299 Dictionary args; | |
300 | |
301 std::auto_ptr<IResult> result(t.Execute(statement, args)); | |
302 | |
303 bool success = (!result->IsDone() && | |
304 result->GetField(0).GetType() == ValueType_Integer64 && | |
305 dynamic_cast<const Integer64Value&>(result->GetField(0)).GetValue() == 1); | |
306 | |
307 t.Commit(); | |
308 | |
309 return success; | |
310 } | |
311 | |
312 | |
313 bool MySQLDatabase::AcquireAdvisoryLock(int32_t lock) | |
314 { | |
315 return RunAdvisoryLockStatement("SELECT GET_LOCK('Lock" + | |
316 boost::lexical_cast<std::string>(lock) + "', 0);"); | |
317 } | |
318 | |
319 | |
320 bool MySQLDatabase::ReleaseAdvisoryLock(int32_t lock) | |
321 { | |
322 return RunAdvisoryLockStatement("SELECT RELEASE_LOCK('Lock" + | |
323 boost::lexical_cast<std::string>(lock) + "');"); | |
324 } | |
325 | |
326 | |
292 void MySQLDatabase::AdvisoryLock(int32_t lock) | 327 void MySQLDatabase::AdvisoryLock(int32_t lock) |
293 { | 328 { |
294 try | 329 if (!AcquireAdvisoryLock(lock)) |
295 { | |
296 Query query("SELECT GET_LOCK('Lock" + | |
297 boost::lexical_cast<std::string>(lock) + "', 0);", false); | |
298 MySQLStatement statement(*this, query); | |
299 | |
300 MySQLTransaction t(*this); | |
301 Dictionary args; | |
302 | |
303 std::auto_ptr<IResult> result(t.Execute(statement, args)); | |
304 | |
305 if (result->IsDone() || | |
306 result->GetField(0).GetType() != ValueType_Integer64 || | |
307 dynamic_cast<const Integer64Value&>(result->GetField(0)).GetValue() != 1) | |
308 { | |
309 throw Orthanc::OrthancException(Orthanc::ErrorCode_Database); | |
310 } | |
311 | |
312 t.Commit(); | |
313 } | |
314 catch (Orthanc::OrthancException&) | |
315 { | 330 { |
316 LOG(ERROR) << "The MySQL database is locked by another instance of Orthanc"; | 331 LOG(ERROR) << "The MySQL database is locked by another instance of Orthanc"; |
317 Close(); | |
318 throw Orthanc::OrthancException(Orthanc::ErrorCode_Database); | 332 throw Orthanc::OrthancException(Orthanc::ErrorCode_Database); |
319 } | 333 } |
320 } | 334 } |
321 | 335 |
322 | 336 |
493 } | 507 } |
494 } | 508 } |
495 | 509 |
496 return true; | 510 return true; |
497 } | 511 } |
512 | |
513 | |
514 MySQLDatabase::TransientAdvisoryLock:: | |
515 TransientAdvisoryLock(MySQLDatabase& database, | |
516 int32_t lock) : | |
517 database_(database), | |
518 lock_(lock) | |
519 { | |
520 bool locked = true; | |
521 | |
522 for (unsigned int i = 0; i < 10; i++) | |
523 { | |
524 if (database_.AcquireAdvisoryLock(lock_)) | |
525 { | |
526 locked = false; | |
527 break; | |
528 } | |
529 else | |
530 { | |
531 boost::this_thread::sleep(boost::posix_time::milliseconds(500)); | |
532 } | |
533 } | |
534 | |
535 if (locked) | |
536 { | |
537 LOG(ERROR) << "Cannot acquire a transient advisory lock"; | |
538 throw Orthanc::OrthancException(Orthanc::ErrorCode_Plugin); | |
539 } | |
540 } | |
541 | |
542 | |
543 MySQLDatabase::TransientAdvisoryLock::~TransientAdvisoryLock() | |
544 { | |
545 database_.ReleaseAdvisoryLock(lock_); | |
546 } | |
498 } | 547 } |