Skip to content

Commit

Permalink
Merge branch 'pu/pm/TbTrnsMgrRefactorHooks' into 'main'
Browse files Browse the repository at this point in the history
tweak(TB TransactionMgr) refactor hooks a bit

See merge request tine20/tine20!6357
  • Loading branch information
paulmhh committed Dec 12, 2024
2 parents 8f41515 + bc72440 commit f90445f
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 103 deletions.
2 changes: 1 addition & 1 deletion tine20/HumanResources/Controller/DailyWTReport.php
Original file line number Diff line number Diff line change
Expand Up @@ -935,7 +935,7 @@ protected function _handleEvent(Tinebase_Event_Abstract $_eventObject)
static $earliestDeletionDate = [];
if (!isset($earliestDeletionDate[$accountId])) {
$earliestDeletionDate[$accountId] = $_eventObject->observable->start_date;
Tinebase_TransactionManager::getInstance()->registerAfterAfterCommitCallback(function() use(&$earliestDeletionDate) {
Tinebase_TransactionManager::getInstance()->registerAfterCommitCallback(function() use(&$earliestDeletionDate) {
// context async / sync
$context = (array)HumanResources_Controller_DailyWTReport::getInstance()->getRequestContext();
if (isset($context['tsSyncron'])) {
Expand Down
184 changes: 82 additions & 102 deletions tine20/Tinebase/TransactionManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,6 @@ class Tinebase_TransactionManager
*/
protected $_afterCommitCallbacks = array();

/**
* @var array list of callbacks to call after "afterCommitCallbacks" have been processed
*/
protected $_afterAfterCommitCallbacks = array();

/**
* @var array list of callbacks to call just before rollback
*/
Expand Down Expand Up @@ -157,91 +152,87 @@ public function commitTransaction($_transactionId)
{
if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(
__METHOD__ . '::' . __LINE__ . " commitTransaction request for $_transactionId");
$transactionIdx = array_search($_transactionId, $this->_openTransactions);
if ($transactionIdx !== false) {
unset($this->_openTransactions[$transactionIdx]);
}

// inside a pre commit callback we don't want to really commit, as this will happen after and outside
// the callback
if (static::$_insideCallBack) {
return;
}

$numOpenTransactions = count($this->_openTransactions);
if ($numOpenTransactions === 0) {
if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(
__METHOD__ . '::' . __LINE__ . " no more open transactions in queue commiting all transactionables");

// avoid loop backs. The callback may trigger a new transaction + commit/rollback...
$callbacks = $this->_onCommitCallbacks;
$afterCallbacks = $this->_afterCommitCallbacks;
$this->_onCommitCallbacks = array();
$this->_afterCommitCallbacks = array();
$this->_afterAfterCommitCallbacks = [];
$transactionIdx = array_search($_transactionId, $this->_openTransactions);
if ($transactionIdx !== false) {
unset($this->_openTransactions[$transactionIdx]);
}

static::$_rollBackOccurred = false;
try {
static::$_insideCallBack = true;
foreach ($callbacks as $callable) {
call_user_func_array($callable[0], $callable[1]);
// if a rollback happened we don't want to continue (the rollback method cleanup already)
// it would be better if the code issuing a rollback throws an exception anyway
if (static::$_rollBackOccurred) {
return;
}
}
} finally {
static::$_insideCallBack = false;
}
// inside a pre commit callback we don't want to really commit, as this will happen after and outside
// the callback
if (static::$_insideCallBack) {
return;
}

foreach ($this->_openTransactionables as $transactionable) {
if ($transactionable instanceof Zend_Db_Adapter_Abstract) {
$transactionable->commit();
}
}
// prevent call back issues. The callback may start and commit/rollback more transactions
$this->_openTransactionables = array();
$this->_onRollbackCallbacks = array();
$numOpenTransactions = count($this->_openTransactions);
if ($numOpenTransactions === 0) {
if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(
__METHOD__ . '::' . __LINE__ . " no more open transactions in queue commiting all transactionables");

foreach ($afterCallbacks as $callable) {
try {
call_user_func_array($callable[0], $callable[1]);
} catch (Tinebase_Exception_AccessDenied $tead) {
if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) Tinebase_Core::getLogger()->notice(
__METHOD__ . '::' . __LINE__ . ' ' . $tead->getMessage());
} catch (Tinebase_Exception_NotFound $tenf) {
if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) Tinebase_Core::getLogger()->notice(
__METHOD__ . '::' . __LINE__ . ' ' . $tenf->getMessage());
} catch (Exception $e) {
// we don't want to fail after we committed. Otherwise, a rollback maybe triggered outside which
// actually can't roll back anything anymore as we already committed.
// So afterCommitCallbacks will fail "silently", they only log and go to sentry
Tinebase_Exception::log($e, false);
}
}
// avoid loop backs. The callback may trigger a new transaction + commit/rollback...
$callbacks = $this->_onCommitCallbacks;
$afterCallbacks = $this->_afterCommitCallbacks;
$this->_onCommitCallbacks = [];
$this->_afterCommitCallbacks = [];

static::$_rollBackOccurred = false;
try {
static::$_insideCallBack = true;
do {
if (null === $callbacks) {
$callbacks = $this->_onCommitCallbacks;
$this->_onCommitCallbacks = [];
}
foreach ($callbacks as $callable) {
call_user_func_array($callable[0], $callable[1]);
// if a rollback happened we don't want to continue (the rollback method cleanup already)
// it would be better if the code issuing a rollback throws an exception anyway
if (static::$_rollBackOccurred) {
return;
}
}
$callbacks = null;
} while ($this->_onCommitCallbacks);
} finally {
static::$_insideCallBack = false;
}

foreach ($this->_afterAfterCommitCallbacks as $callable) {
try {
call_user_func_array($callable[0], $callable[1]);
} catch (Tinebase_Exception_AccessDenied $tead) {
if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) Tinebase_Core::getLogger()->notice(
__METHOD__ . '::' . __LINE__ . ' ' . $tead->getMessage());
} catch (Tinebase_Exception_NotFound $tenf) {
if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) Tinebase_Core::getLogger()->notice(
__METHOD__ . '::' . __LINE__ . ' ' . $tenf->getMessage());
} catch (Exception $e) {
// we don't want to fail after we committed. Otherwise, a rollback maybe triggered outside which
// actually can't roll back anything anymore as we already committed.
// So afterCommitCallbacks will fail "silently", they only log and go to sentry
Tinebase_Exception::log($e, false);
}
}
foreach ($this->_openTransactionables as $transactionable) {
if ($transactionable instanceof Zend_Db_Adapter_Abstract) {
$transactionable->commit();
}
}
// prevent call back issues. The callback may start and commit/rollback more transactions
$this->_openTransactionables = array();
$this->_onRollbackCallbacks = array();

do {
if (null === $afterCallbacks) {
$afterCallbacks = $this->_afterCommitCallbacks;
$this->_afterCommitCallbacks = [];
}
foreach ($afterCallbacks as $callable) {
try {
call_user_func_array($callable[0], $callable[1]);
} catch (Tinebase_Exception_AccessDenied $tead) {
if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) Tinebase_Core::getLogger()->notice(
__METHOD__ . '::' . __LINE__ . ' ' . $tead->getMessage());
} catch (Tinebase_Exception_NotFound $tenf) {
if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) Tinebase_Core::getLogger()->notice(
__METHOD__ . '::' . __LINE__ . ' ' . $tenf->getMessage());
} catch (Exception $e) {
// we don't want to fail after we committed. Otherwise, a rollback maybe triggered outside which
// actually can't roll back anything anymore as we already committed.
// So afterCommitCallbacks will fail "silently", they only log and go to sentry
Tinebase_Exception::log($e, false);
}
}
$afterCallbacks = null;
} while (0 === count($this->_openTransactionables) && $this->_afterCommitCallbacks);

} else if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) {
Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__
. " Committing deferred, as there are still $numOpenTransactions in the queue");
}
} else if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) {
Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__
. " Committing deferred, as there are still $numOpenTransactions in the queue");
}
}

/**
Expand All @@ -262,16 +253,17 @@ public function rollBack()
static::$_insideCallBack = false;

try {
foreach ($this->_openTransactionables as $transactionable) {
// avoid loop backs. The callback may trigger a new transaction + commit/rollback...
$callbacks = $this->_onRollbackCallbacks;
$transactionables = $this->_openTransactionables;
$this->resetTransactions();

foreach ($transactionables as $transactionable) {
if ($transactionable instanceof Zend_Db_Adapter_Abstract) {
$transactionable->rollBack();
}
}

// avoid loop backs. The callback may trigger a new transaction + commit/rollback...
$callbacks = $this->_onRollbackCallbacks;
$this->resetTransactions();

foreach ($callbacks as $callable) {
call_user_func_array($callable[0], $callable[1]);
}
Expand Down Expand Up @@ -306,17 +298,6 @@ public function registerAfterCommitCallback($callable, array $param = array())
$this->_afterCommitCallbacks[] = array($callable, $param);
}

/**
* register a callable to call after "afterCommitCallbacks" have been processed
*
* @param array|callable $callable
* @param array $param
*/
public function registerAfterAfterCommitCallback($callable, array $param = array())
{
$this->_afterAfterCommitCallbacks[] = array($callable, $param);
}

/**
* register a callable to call just before the rollback happens
*
Expand All @@ -342,7 +323,6 @@ public function resetTransactions()
{
$this->_onCommitCallbacks = [];
$this->_afterCommitCallbacks = [];
$this->_afterAfterCommitCallbacks = [];
$this->_onRollbackCallbacks = [];
$this->_openTransactionables = [];
$this->_openTransactions = [];
Expand Down

0 comments on commit f90445f

Please sign in to comment.