comparison Framework/MySQL/MySQLDatabase.cpp @ 137:52b3859ee0b7

MySQL: acquiring named locks instead of numbers
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 09 May 2019 11:29:17 +0200
parents e26690365c25
children 4cd7e45b671e
comparison
equal deleted inserted replaced
136:3266785d5627 137:52b3859ee0b7
288 return false; 288 return false;
289 } 289 }
290 } 290 }
291 291
292 292
293 bool MySQLDatabase::RunAdvisoryLockStatement(const std::string& s) 293 bool MySQLDatabase::RunAdvisoryLockStatement(Query& query,
294 { 294 const std::string& lock)
295 Query query(s, false); 295 {
296 const std::string& dbName = parameters_.GetDatabase();
297
298 // Prepend the name of the lock by the database name. This allows
299 // to create a namespace for advisory locks:
300 // https://groups.google.com/d/msg/orthanc-users/yV3LSTh_TjI/MQIcvnMlAQAJ
301 std::string prefix;
302 prefix.reserve(dbName.size());
303 for (size_t i = 0; i < dbName.size(); i++)
304 {
305 if (isalnum(dbName[i]) ||
306 dbName[i] == '$' ||
307 dbName[i] == '_')
308 {
309 prefix.push_back(dbName[i]);
310 }
311 }
312
313 query.SetType("lock", ValueType_Utf8String);
314
296 MySQLStatement statement(*this, query); 315 MySQLStatement statement(*this, query);
297 316
298 MySQLTransaction t(*this);
299 Dictionary args; 317 Dictionary args;
300 318 args.SetUtf8Value("lock", prefix + "." + lock);
301 std::auto_ptr<IResult> result(t.Execute(statement, args)); 319
302 320 bool success;
303 bool success = (!result->IsDone() && 321
304 result->GetField(0).GetType() == ValueType_Integer64 && 322 {
305 dynamic_cast<const Integer64Value&>(result->GetField(0)).GetValue() == 1); 323 MySQLTransaction t(*this);
306 324 std::auto_ptr<IResult> result(t.Execute(statement, args));
307 t.Commit(); 325
326 success = (!result->IsDone() &&
327 result->GetField(0).GetType() == ValueType_Integer64 &&
328 dynamic_cast<const Integer64Value&>(result->GetField(0)).GetValue() == 1);
329
330 t.Commit();
331 }
308 332
309 return success; 333 return success;
310 } 334 }
311 335
312 336
313 bool MySQLDatabase::AcquireAdvisoryLock(int32_t lock) 337 bool MySQLDatabase::AcquireAdvisoryLock(const std::string& lock)
314 { 338 {
315 return RunAdvisoryLockStatement("SELECT GET_LOCK('Lock" + 339 Query query("SELECT GET_LOCK(${lock}, 0)", false);
316 boost::lexical_cast<std::string>(lock) + "', 0);"); 340 return RunAdvisoryLockStatement(query, lock);
317 } 341 }
318 342
319 343
320 bool MySQLDatabase::ReleaseAdvisoryLock(int32_t lock) 344 bool MySQLDatabase::ReleaseAdvisoryLock(const std::string& lock)
321 { 345 {
322 return RunAdvisoryLockStatement("SELECT RELEASE_LOCK('Lock" + 346 Query query("SELECT RELEASE_LOCK(${lock})", false);
323 boost::lexical_cast<std::string>(lock) + "');"); 347 return RunAdvisoryLockStatement(query, lock);
324 } 348 }
325 349
326 350
327 void MySQLDatabase::AdvisoryLock(int32_t lock) 351 void MySQLDatabase::AdvisoryLock(const std::string& lock)
328 { 352 {
329 if (!AcquireAdvisoryLock(lock)) 353 if (!AcquireAdvisoryLock(lock))
330 { 354 {
331 LOG(ERROR) << "The MySQL database is locked by another instance of Orthanc"; 355 LOG(ERROR) << "The MySQL database is locked by another instance of Orthanc";
332 throw Orthanc::OrthancException(Orthanc::ErrorCode_Database); 356 throw Orthanc::OrthancException(Orthanc::ErrorCode_Database);
511 } 535 }
512 536
513 537
514 MySQLDatabase::TransientAdvisoryLock:: 538 MySQLDatabase::TransientAdvisoryLock::
515 TransientAdvisoryLock(MySQLDatabase& database, 539 TransientAdvisoryLock(MySQLDatabase& database,
516 int32_t lock) : 540 const std::string& lock) :
517 database_(database), 541 database_(database),
518 lock_(lock) 542 lock_(lock)
519 { 543 {
520 bool locked = true; 544 bool locked = true;
521 545