| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| |
|
| | #include <Base/Interpreter.h> |
| |
|
| | #include "AutoTransaction.h" |
| | #include "Application.h" |
| | #include "Document.h" |
| | #include "Transactions.h" |
| |
|
| |
|
| | FC_LOG_LEVEL_INIT("App", true, true) |
| |
|
| | using namespace App; |
| |
|
| | static int _TransactionLock; |
| | static int _TransactionClosed; |
| |
|
| | AutoTransaction::AutoTransaction(const char* name, bool tmpName) |
| | { |
| | auto& app = GetApplication(); |
| | if (name && app._activeTransactionGuard >= 0) { |
| | if (!app.getActiveTransaction() || (!tmpName && app._activeTransactionTmpName)) { |
| | FC_LOG("auto transaction '" << name << "', " << tmpName); |
| | tid = app.setActiveTransaction(name); |
| | app._activeTransactionTmpName = tmpName; |
| | } |
| | } |
| | |
| | |
| | |
| | |
| | if (app._activeTransactionGuard < 0) { |
| | --app._activeTransactionGuard; |
| | } |
| | else if (tid || app._activeTransactionGuard > 0) { |
| | ++app._activeTransactionGuard; |
| | } |
| | else if (app.getActiveTransaction()) { |
| | FC_LOG("auto transaction disabled because of '" << app._activeTransactionName << "'"); |
| | --app._activeTransactionGuard; |
| | } |
| | else { |
| | ++app._activeTransactionGuard; |
| | } |
| | FC_TRACE("construct auto Transaction " << app._activeTransactionGuard); |
| | } |
| |
|
| | AutoTransaction::~AutoTransaction() |
| | { |
| | auto& app = GetApplication(); |
| | FC_TRACE("before destruct auto Transaction " << app._activeTransactionGuard); |
| | if (app._activeTransactionGuard < 0) { |
| | ++app._activeTransactionGuard; |
| | } |
| | else if (!app._activeTransactionGuard) { |
| | #ifdef FC_DEBUG |
| | FC_ERR("Transaction guard error"); |
| | #endif |
| | } |
| | else if (--app._activeTransactionGuard == 0) { |
| | try { |
| | |
| | |
| | |
| | |
| | app.closeActiveTransaction(); |
| | } |
| | catch (Base::Exception& e) { |
| | e.reportException(); |
| | } |
| | catch (...) { |
| | } |
| | } |
| | FC_TRACE("destruct auto Transaction " << app._activeTransactionGuard); |
| | } |
| |
|
| | void AutoTransaction::close(bool abort) |
| | { |
| | if (tid || abort) { |
| | GetApplication().closeActiveTransaction(abort, abort ? 0 : tid); |
| | tid = 0; |
| | } |
| | } |
| |
|
| | void AutoTransaction::setEnable(bool enable) |
| | { |
| | auto& app = GetApplication(); |
| | if (!app._activeTransactionGuard) { |
| | return; |
| | } |
| | if ((enable && app._activeTransactionGuard > 0) |
| | || (!enable && app._activeTransactionGuard < 0)) { |
| | return; |
| | } |
| | app._activeTransactionGuard = -app._activeTransactionGuard; |
| | FC_TRACE("toggle auto Transaction " << app._activeTransactionGuard); |
| | if (!enable && app._activeTransactionTmpName) { |
| | bool close = true; |
| | for (auto& v : app.DocMap) { |
| | if (v.second->hasPendingTransaction()) { |
| | close = false; |
| | break; |
| | } |
| | } |
| | if (close) { |
| | app.closeActiveTransaction(); |
| | } |
| | } |
| | } |
| |
|
| | int Application::setActiveTransaction(const char* name, bool persist) |
| | { |
| |
|
| | if (!name || !name[0]) { |
| | name = "Command"; |
| | } |
| | |
| | this->signalBeforeOpenTransaction(name); |
| | if (_activeTransactionGuard > 0 && getActiveTransaction()) { |
| | if (_activeTransactionTmpName) { |
| | FC_LOG("transaction rename to '" << name << "'"); |
| | for (auto& v : DocMap) { |
| | v.second->renameTransaction(name, _activeTransactionID); |
| | } |
| | } |
| | else { |
| | if (persist) { |
| | AutoTransaction::setEnable(false); |
| | } |
| | return 0; |
| | } |
| | } |
| | else if (_TransactionLock) { |
| | if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) { |
| | FC_WARN("Transaction locked, ignore new transaction '" << name << "'"); |
| | } |
| | return 0; |
| | } |
| | else { |
| | FC_LOG("set active transaction '" << name << "'"); |
| | _activeTransactionID = 0; |
| | for (auto& v : DocMap) { |
| | v.second->_commitTransaction(); |
| | } |
| | _activeTransactionID = Transaction::getNewID(); |
| | } |
| | _activeTransactionTmpName = false; |
| | _activeTransactionName = name; |
| | if (persist) { |
| | AutoTransaction::setEnable(false); |
| | } |
| | return _activeTransactionID; |
| | } |
| |
|
| | const char* Application::getActiveTransaction(int* id) const |
| | { |
| | int tid = 0; |
| | if (Transaction::getLastID() == _activeTransactionID) { |
| | tid = _activeTransactionID; |
| | } |
| | if (id) { |
| | *id = tid; |
| | } |
| | return tid ? _activeTransactionName.c_str() : nullptr; |
| | } |
| |
|
| | void Application::closeActiveTransaction(bool abort, int id) |
| | { |
| | if (!id) { |
| | id = _activeTransactionID; |
| | } |
| | if (!id) { |
| | return; |
| | } |
| |
|
| | if (_activeTransactionGuard > 0 && !abort) { |
| | FC_LOG("ignore close transaction"); |
| | return; |
| | } |
| |
|
| | if (_TransactionLock) { |
| | if (_TransactionClosed >= 0) { |
| | _TransactionLock = abort ? -1 : 1; |
| | } |
| | FC_LOG("pending " << (abort ? "abort" : "close") << " transaction"); |
| | return; |
| | } |
| |
|
| | FC_LOG("close transaction '" << _activeTransactionName << "' " << abort); |
| | _activeTransactionID = 0; |
| |
|
| | TransactionSignaller signaller(abort, false); |
| | for (auto& v : DocMap) { |
| | if (v.second->getTransactionID(true) != id) { |
| | continue; |
| | } |
| | if (abort) { |
| | v.second->_abortTransaction(); |
| | } |
| | else { |
| | v.second->_commitTransaction(); |
| | } |
| | } |
| | } |
| |
|
| | |
| |
|
| | TransactionLocker::TransactionLocker(bool lock) |
| | : active(lock) |
| | { |
| | if (lock) { |
| | ++_TransactionLock; |
| | } |
| | } |
| |
|
| | TransactionLocker::~TransactionLocker() |
| | { |
| | if (active) { |
| | try { |
| | activate(false); |
| | return; |
| | } |
| | catch (Base::Exception& e) { |
| | e.reportException(); |
| | } |
| | catch (Py::Exception&) { |
| | Base::PyException e; |
| | e.reportException(); |
| | } |
| | catch (std::exception& e) { |
| | FC_ERR(e.what()); |
| | } |
| | catch (...) { |
| | } |
| | FC_ERR("Exception when unlocking transaction"); |
| | } |
| | } |
| |
|
| | void TransactionLocker::activate(bool enable) |
| | { |
| | if (active == enable) { |
| | return; |
| | } |
| |
|
| | active = enable; |
| | if (active) { |
| | ++_TransactionLock; |
| | return; |
| | } |
| |
|
| | if (--_TransactionLock != 0) { |
| | return; |
| | } |
| |
|
| | if (_TransactionClosed) { |
| | bool abort = (_TransactionClosed < 0); |
| | _TransactionClosed = 0; |
| | GetApplication().closeActiveTransaction(abort); |
| | } |
| | } |
| |
|
| | bool TransactionLocker::isLocked() |
| | { |
| | return _TransactionLock > 0; |
| | } |
| |
|