Mercurial > hg > orthanc-databases
comparison Framework/Common/DatabaseManager.cpp @ 23:b2ff1cd2907a
handling of implicit transactions in DatabaseManager
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 12 Jul 2018 10:44:17 +0200 |
parents | c7c54993a92e |
children | 2fb9cd42af14 |
comparison
equal
deleted
inserted
replaced
22:1e9bad493475 | 23:b2ff1cd2907a |
---|---|
154 | 154 |
155 ITransaction& DatabaseManager::GetTransaction() | 155 ITransaction& DatabaseManager::GetTransaction() |
156 { | 156 { |
157 if (transaction_.get() == NULL) | 157 if (transaction_.get() == NULL) |
158 { | 158 { |
159 LOG(TRACE) << "Automatically creating a database transaction"; | 159 LOG(TRACE) << "Automatically creating an implicit database transaction"; |
160 | 160 |
161 try | 161 try |
162 { | 162 { |
163 transaction_.reset(GetDatabase().CreateTransaction()); | 163 transaction_.reset(GetDatabase().CreateTransaction(true)); |
164 } | 164 } |
165 catch (Orthanc::OrthancException& e) | 165 catch (Orthanc::OrthancException& e) |
166 { | 166 { |
167 CloseIfUnavailable(e.GetErrorCode()); | 167 CloseIfUnavailable(e.GetErrorCode()); |
168 throw; | 168 throw; |
169 } | 169 } |
170 } | 170 } |
171 | 171 |
172 assert(transaction_.get() != NULL); | 172 assert(transaction_.get() != NULL); |
173 return *transaction_; | 173 return *transaction_; |
174 } | |
175 | |
176 | |
177 void DatabaseManager::ReleaseImplicitTransaction() | |
178 { | |
179 if (transaction_.get() != NULL && | |
180 transaction_->IsImplicit()) | |
181 { | |
182 LOG(TRACE) << "Committing an implicit database transaction"; | |
183 | |
184 try | |
185 { | |
186 transaction_->Commit(); | |
187 transaction_.reset(NULL); | |
188 } | |
189 catch (Orthanc::OrthancException& e) | |
190 { | |
191 // Don't throw the exception, as we are in CachedStatement destructor | |
192 LOG(ERROR) << "Error while committing an implicit database transaction: " << e.What(); | |
193 } | |
194 } | |
174 } | 195 } |
175 | 196 |
176 | 197 |
177 DatabaseManager::DatabaseManager(IDatabaseFactory* factory) : // Takes ownership | 198 DatabaseManager::DatabaseManager(IDatabaseFactory* factory) : // Takes ownership |
178 factory_(factory) | 199 factory_(factory) |
192 | 213 |
193 try | 214 try |
194 { | 215 { |
195 if (transaction_.get() != NULL) | 216 if (transaction_.get() != NULL) |
196 { | 217 { |
197 #if 0 | 218 LOG(ERROR) << "Cannot start another transaction while there is an uncommitted transaction"; |
198 // TODO: This should be the right implementation | 219 throw Orthanc::OrthancException(Orthanc::ErrorCode_Database); |
199 if (transaction_->IsReadOnly()) | 220 } |
200 { | 221 |
201 LOG(TRACE) << "Rollback of an uncommitted read-only transaction to start another transaction"; | 222 transaction_.reset(GetDatabase().CreateTransaction(false)); |
202 transaction_->Rollback(); | 223 } |
203 transaction_.reset(NULL); | 224 catch (Orthanc::OrthancException& e) |
204 } | 225 { |
205 else | 226 CloseIfUnavailable(e.GetErrorCode()); |
206 { | 227 throw; |
207 LOG(ERROR) << "Cannot rollback an uncommitted write transaction to start another transaction"; | 228 } |
208 throw Orthanc::OrthancException(Orthanc::ErrorCode_Database); | 229 } |
209 } | 230 |
210 #else | 231 |
211 LOG(INFO) << "Committing an uncommitted transaction to start another transaction"; | 232 void DatabaseManager::CommitTransaction() |
233 { | |
234 boost::recursive_mutex::scoped_lock lock(mutex_); | |
235 | |
236 if (transaction_.get() == NULL) | |
237 { | |
238 LOG(ERROR) << "Cannot commit a non-existing transaction"; | |
239 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
240 } | |
241 else | |
242 { | |
243 try | |
244 { | |
212 transaction_->Commit(); | 245 transaction_->Commit(); |
213 transaction_.reset(NULL); | 246 transaction_.reset(NULL); |
214 #endif | |
215 } | |
216 | |
217 transaction_.reset(GetDatabase().CreateTransaction()); | |
218 } | |
219 catch (Orthanc::OrthancException& e) | |
220 { | |
221 CloseIfUnavailable(e.GetErrorCode()); | |
222 throw; | |
223 } | |
224 } | |
225 | |
226 | |
227 void DatabaseManager::CommitTransaction() | |
228 { | |
229 boost::recursive_mutex::scoped_lock lock(mutex_); | |
230 | |
231 if (transaction_.get() == NULL) | |
232 { | |
233 LOG(ERROR) << "Cannot commit a non-existing transaction"; | |
234 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
235 } | |
236 else | |
237 { | |
238 try | |
239 { | |
240 transaction_->Commit(); | |
241 transaction_.reset(NULL); | |
242 } | 247 } |
243 catch (Orthanc::OrthancException& e) | 248 catch (Orthanc::OrthancException& e) |
244 { | 249 { |
245 CloseIfUnavailable(e.GetErrorCode()); | 250 CloseIfUnavailable(e.GetErrorCode()); |
246 throw; | 251 throw; |
300 << location_.GetFile() << ":" << location_.GetLine(); | 305 << location_.GetFile() << ":" << location_.GetLine(); |
301 } | 306 } |
302 } | 307 } |
303 | 308 |
304 | 309 |
310 DatabaseManager::Transaction::Transaction(DatabaseManager& manager) : | |
311 lock_(manager.mutex_), | |
312 manager_(manager), | |
313 database_(manager.GetDatabase()), | |
314 committed_(false) | |
315 { | |
316 manager_.StartTransaction(); | |
317 } | |
318 | |
319 | |
320 DatabaseManager::Transaction::~Transaction() | |
321 { | |
322 if (!committed_) | |
323 { | |
324 try | |
325 { | |
326 manager_.RollbackTransaction(); | |
327 } | |
328 catch (Orthanc::OrthancException& e) | |
329 { | |
330 // Don't rethrow the exception as we are in a destructor | |
331 LOG(ERROR) << "Uncatched error during some transaction rollback: " << e.What(); | |
332 } | |
333 } | |
334 } | |
335 | |
336 | |
337 void DatabaseManager::Transaction::Commit() | |
338 { | |
339 if (committed_) | |
340 { | |
341 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
342 } | |
343 else | |
344 { | |
345 manager_.CommitTransaction(); | |
346 committed_ = true; | |
347 } | |
348 } | |
349 | |
350 | |
305 DatabaseManager::CachedStatement::CachedStatement(const StatementLocation& location, | 351 DatabaseManager::CachedStatement::CachedStatement(const StatementLocation& location, |
306 DatabaseManager& manager, | 352 DatabaseManager& manager, |
307 const char* sql) : | 353 const char* sql) : |
308 lock_(manager.mutex_), | 354 lock_(manager.mutex_), |
309 manager_(manager), | 355 manager_(manager), |
325 transaction_(manager_.GetTransaction()) | 371 transaction_(manager_.GetTransaction()) |
326 { | 372 { |
327 Setup(sql); | 373 Setup(sql); |
328 } | 374 } |
329 | 375 |
376 | |
377 DatabaseManager::CachedStatement::~CachedStatement() | |
378 { | |
379 manager_.ReleaseImplicitTransaction(); | |
380 } | |
381 | |
330 | 382 |
331 void DatabaseManager::CachedStatement::SetReadOnly(bool readOnly) | 383 void DatabaseManager::CachedStatement::SetReadOnly(bool readOnly) |
332 { | 384 { |
333 if (query_.get() != NULL) | 385 if (query_.get() != NULL) |
334 { | 386 { |