comparison PostgreSQL/Plugins/PostgreSQLIndex.cpp @ 428:4d0bacbd0fba pg-transactions

rewrote CreateInstance to make it compatible with READ COMMITED transactions
author Alain Mazy <am@osimis.io>
date Thu, 30 Nov 2023 14:46:38 +0100
parents 3cdea26ece73
children 7c1fe5d6c12c
comparison
equal deleted inserted replaced
427:3cdea26ece73 428:4d0bacbd0fba
202 DatabaseManager::Transaction t(manager, TransactionType_ReadWrite); 202 DatabaseManager::Transaction t(manager, TransactionType_ReadWrite);
203 203
204 int property = 0; 204 int property = 0;
205 if (!LookupGlobalIntegerProperty(property, manager, MISSING_SERVER_IDENTIFIER, 205 if (!LookupGlobalIntegerProperty(property, manager, MISSING_SERVER_IDENTIFIER,
206 Orthanc::GlobalProperty_HasCreateInstance) || 206 Orthanc::GlobalProperty_HasCreateInstance) ||
207 property != 2) 207 property != 3)
208 { 208 {
209 LOG(INFO) << "Installing the CreateInstance extension"; 209 LOG(INFO) << "Installing the CreateInstance extension";
210 210
211 if (property == 1) 211 if (property == 1)
212 { 212 {
213 // Drop older, experimental versions of this extension 213 // Drop older, experimental versions of this extension
214 t.GetDatabaseTransaction().ExecuteMultiLines("DROP FUNCTION CreateInstance(" 214 t.GetDatabaseTransaction().ExecuteMultiLines("DROP FUNCTION CreateInstance("
215 "IN patient TEXT, IN study TEXT, IN series TEXT, in instance TEXT)"); 215 "IN patient TEXT, IN study TEXT, IN series TEXT, in instance TEXT)");
216 } 216 }
217 217
218 // property == 2 was a first version of the CreateInstance -> we need to replace it by the new one
219 // property == 3 is a new version (in v5.2) with same signature and CREATE OR UPDATE
220 // -> we can replace the previous one without deleting it
221 // and we can create it if it has never been created.
218 std::string query; 222 std::string query;
219 Orthanc::EmbeddedResources::GetFileResource 223 Orthanc::EmbeddedResources::GetFileResource
220 (query, Orthanc::EmbeddedResources::POSTGRESQL_CREATE_INSTANCE); 224 (query, Orthanc::EmbeddedResources::POSTGRESQL_CREATE_INSTANCE);
221 t.GetDatabaseTransaction().ExecuteMultiLines(query); 225 t.GetDatabaseTransaction().ExecuteMultiLines(query);
222 226
223 SetGlobalIntegerProperty(manager, MISSING_SERVER_IDENTIFIER, Orthanc::GlobalProperty_HasCreateInstance, 2); 227 SetGlobalIntegerProperty(manager, MISSING_SERVER_IDENTIFIER, Orthanc::GlobalProperty_HasCreateInstance, 3);
224 } 228 }
225 229
226 230
227 if (!LookupGlobalIntegerProperty(property, manager, MISSING_SERVER_IDENTIFIER, 231 if (!LookupGlobalIntegerProperty(property, manager, MISSING_SERVER_IDENTIFIER,
228 Orthanc::GlobalProperty_GetTotalSizeIsFast) || 232 Orthanc::GlobalProperty_GetTotalSizeIsFast) ||
365 statement.Execute(); 369 statement.Execute();
366 370
367 result = static_cast<uint64_t>(statement.ReadInteger64(0)); 371 result = static_cast<uint64_t>(statement.ReadInteger64(0));
368 } 372 }
369 373
370 assert(result == IndexBackend::GetTotalCompressedSize(manager)); 374 // disabled because this is not alway true while transactions are being executed in READ COMITTED TRANSACTION. This is however true when no files are being delete/added
375 //assert(result == IndexBackend::GetTotalCompressedSize(manager));
371 return result; 376 return result;
372 } 377 }
373 378
374 379
375 uint64_t PostgreSQLIndex::GetTotalUncompressedSize(DatabaseManager& manager) 380 uint64_t PostgreSQLIndex::GetTotalUncompressedSize(DatabaseManager& manager)
386 statement.Execute(); 391 statement.Execute();
387 392
388 result = static_cast<uint64_t>(statement.ReadInteger64(0)); 393 result = static_cast<uint64_t>(statement.ReadInteger64(0));
389 } 394 }
390 395
391 assert(result == IndexBackend::GetTotalUncompressedSize(manager)); 396 // disabled because this is not alway true while transactions are being executed in READ COMITTED TRANSACTION. This is however true when no files are being delete/added
397 // assert(result == IndexBackend::GetTotalUncompressedSize(manager));
392 return result; 398 return result;
393 } 399 }
394 400
395 401
396 #if ORTHANC_PLUGINS_HAS_DATABASE_CONSTRAINT == 1 402 #if ORTHANC_PLUGINS_HAS_DATABASE_CONSTRAINT == 1
414 args.SetUtf8Value("patient", hashPatient); 420 args.SetUtf8Value("patient", hashPatient);
415 args.SetUtf8Value("study", hashStudy); 421 args.SetUtf8Value("study", hashStudy);
416 args.SetUtf8Value("series", hashSeries); 422 args.SetUtf8Value("series", hashSeries);
417 args.SetUtf8Value("instance", hashInstance); 423 args.SetUtf8Value("instance", hashInstance);
418 424
419 { // The CreateInstance procedure is not 100% safe in highly concurrent environments when the 425 statement.Execute(args);
420 // transaction isolation is set to "READ COMMITED": (e.g, with 10 clients
421 // anonymizing studies in parallel with the "ResourceModification" config set to 8, we have observed
422 // the same series being created twice). Therefore, we protect the whole CreateInstance procedure
423 // with an advisory lock
424 PostgreSQLDatabase& db = dynamic_cast<PostgreSQLDatabase&>(manager.GetDatabase());
425 PostgreSQLDatabase::TransientAdvisoryLock lock(db, POSTGRESQL_LOCK_CREATE_INSTANCE, 100, 1);
426
427 statement.Execute(args);
428 }
429 426
430 if (statement.IsDone() || 427 if (statement.IsDone() ||
431 statement.GetResultFieldsCount() != 8) 428 statement.GetResultFieldsCount() != 8)
432 { 429 {
433 throw Orthanc::OrthancException(Orthanc::ErrorCode_Database); 430 throw Orthanc::OrthancException(Orthanc::ErrorCode_Database);
482 statement.Execute(args); 479 statement.Execute(args);
483 480
484 result = static_cast<uint64_t>(statement.ReadInteger64(0)); 481 result = static_cast<uint64_t>(statement.ReadInteger64(0));
485 } 482 }
486 483
484 // disabled because this is not alway true while transactions are being executed in READ COMITTED TRANSACTION. This is however true when no files are being delete/added
487 assert(result == IndexBackend::GetResourcesCount(manager, resourceType)); 485 assert(result == IndexBackend::GetResourcesCount(manager, resourceType));
486
488 return result; 487 return result;
489 } 488 }
490 489
491 490
492 int64_t PostgreSQLIndex::GetLastChangeIndex(DatabaseManager& manager) 491 int64_t PostgreSQLIndex::GetLastChangeIndex(DatabaseManager& manager)