diff --git a/core/dbobject.class.php b/core/dbobject.class.php index 069b2503b..c2ca10ab3 100644 --- a/core/dbobject.class.php +++ b/core/dbobject.class.php @@ -26,6 +26,7 @@ require_once('metamodel.class.php'); require_once('deletionplan.class.inc.php'); +require_once('mutex.class.inc.php'); /** diff --git a/datamodels/2.x/itop-tickets/datamodel.itop-tickets.xml b/datamodels/2.x/itop-tickets/datamodel.itop-tickets.xml index 299030c2e..c397bd309 100755 --- a/datamodels/2.x/itop-tickets/datamodel.itop-tickets.xml +++ b/datamodels/2.x/itop-tickets/datamodel.itop-tickets.xml @@ -148,7 +148,22 @@ 0 - + + + false + public + Overload-DBObject + Lock(); + $iKey = parent::DBInsertNoReload(); + $oMutex->Unlock(); + return $iKey; + } + ]]> + +
diff --git a/readme.txt b/readme.txt index fcada3385..3cb6f82f7 100644 --- a/readme.txt +++ b/readme.txt @@ -96,7 +96,7 @@ Flash version 8 or higher is required. - data - env-production - log -3) Point your web browser to the URL corresponding to the directory where the files +4) Point your web browser to the URL corresponding to the directory where the files have been unzipped and follow the indications on the screen. If you wish to re-launch the installation process (for example in order to install diff --git a/webservices/cron.php b/webservices/cron.php index 43b5b01f5..a20b66767 100644 --- a/webservices/cron.php +++ b/webservices/cron.php @@ -40,13 +40,27 @@ if (!file_exists($sConfigFile)) require_once(APPROOT.'/application/startup.inc.php'); +function LogError($oP, $sErrorMessage, $sSeverity = 'ERROR') +{ + $bModeCLI = utils::IsModeCLI(); + + if ($bModeCLI) + { + error_log(ITOP_APPLICATION." cron.php $sSeverity: ".$sErrorMessage); + } + else + { + $oP->p("$sSeverity: $sMessage"); + } + +} function ReadMandatoryParam($oP, $sParam, $sSanitizationFilter = 'parameter') { $sValue = utils::ReadParam($sParam, null, true /* Allow CLI */, $sSanitizationFilter); if (is_null($sValue)) { - $oP->p("ERROR: Missing argument '$sParam'\n"); + LogError($oP, "Missing argument '$sParam'"); UsageAndExit($oP); } return trim($sValue); @@ -59,7 +73,7 @@ function UsageAndExit($oP) if ($bModeCLI) { $oP->p("USAGE:\n"); - $oP->p("php cron.php --auth_user= --auth_pwd= [--param_file=] [--verbose=1] [--debug=1] [--status_only=1]\n"); + $oP->p("php cron.php --auth_user= --auth_pwd= [--param_file=] [--verbose=1] [--status_only=1]\n"); } else { @@ -69,7 +83,7 @@ function UsageAndExit($oP) exit -2; } -function RunTask($oProcess, BackgroundTask $oTask, $oStartDate, $iTimeLimit) +function RunTask($oP, $oProcess, BackgroundTask $oTask, $oStartDate, $iTimeLimit) { try { @@ -111,7 +125,7 @@ function RunTask($oProcess, BackgroundTask $oTask, $oStartDate, $iTimeLimit) } catch(Exception $e) { - $sMessage = 'Processing failed, the following exception occured: '.$e->getMessage(); + LogError($oP, 'Processing failed, the following exception occured: '.$e->getMessage()); } return $sMessage; } @@ -199,7 +213,7 @@ function CronExec($oP, $aProcesses, $bVerbose) { $oP->p(">> === ".$oNow->format('Y-m-d H:i:s').sprintf(" Starting:%-'=40s", ' '.$sTaskClass.' ')); } - $sMessage = RunTask($oProcess, $aTasks[$sTaskClass], $oNow, $iTimeLimit); + $sMessage = RunTask($oP, $oProcess, $aTasks[$sTaskClass], $oNow, $iTimeLimit); if ($bVerbose) { if(!empty($sMessage)) @@ -291,7 +305,7 @@ if (utils::IsModeCLI()) } else { - $oP->p("Access wrong credentials ('$sAuthUser')"); + LogError($oP, "Access wrong credentials ('$sAuthUser')"); $oP->output(); exit -1; } @@ -305,11 +319,19 @@ else if (!UserRights::IsAdministrator()) { - $oP->p("Access restricted to administrators"); - $oP->Output(); + LogError($oP, 'Access restricted to administrators'); + $oP->output(); exit -1; } +if (!MetaModel::DBHasAccess(ACCESS_ADMIN_WRITE)) +{ + LogError($oP, 'A database maintenance is ongoing (read-only mode even for admins)', 'WARNING'); + $oP->output(); + exit -1; +} + + // Enumerate classes implementing BackgroundProcess // $aProcesses = array(); @@ -329,7 +351,6 @@ foreach(get_declared_classes() as $sPHPClass) $bVerbose = utils::ReadParam('verbose', false, true /* Allow CLI */); -$bDebug = utils::ReadParam('debug', false, true /* Allow CLI */); if ($bVerbose) { @@ -348,44 +369,39 @@ if (utils::ReadParam('status_only', false, true /* Allow CLI */)) exit(0); } -require_once(APPROOT.'core/mutex.class.inc.php'); +// Compute the name of a lock for mysql +// The name is server-wide +$oConfig = utils::GetConfig(); +$sLockName = 'itop.cron.'.$oConfig->GetDBName().'_'.$oConfig->GetDBSubname(); + $oP->p("Starting: ".time().' ('.date('Y-m-d H:i:s').')'); -try +// CAUTION: using GET_LOCK anytime on the same connexion will RELEASE the lock +// Todo: invoke GET_LOCK from a dedicated session (encapsulate that into a mutex class) +$res = CMDBSource::QueryToScalar("SELECT GET_LOCK('$sLockName', 1)");// timeout = 1 second (see also IS_FREE_LOCK) +if (is_null($res)) { - $oConfig = utils::GetConfig(); - $oMutex = new iTopMutex('cron.'.$oConfig->GetDBName().'_'.$oConfig->GetDBSubname()); - if ($oMutex->TryLock()) + LogError($oP, "Failed to acquire the lock '$sLockName'"); +} +elseif ($res === '1') +{ + // The current session holds the lock + try { - // Note: testing this now in case some of the background processes forces the read-only mode for a while - // in that case it is better to exit with the check on reentrance (mutex) - if (!MetaModel::DBHasAccess(ACCESS_ADMIN_WRITE)) - { - $oP->p("A database maintenance is ongoing (read-only mode even for admins)."); - $oP->Output(); - exit -1; - } - CronExec($oP, $aProcesses, $bVerbose); - - $oMutex->Unlock(); } - else + catch(Exception $e) { - // Exit silently - $oP->p("Already running..."); + LogError($oP, $e->getMessage()."\n".$e->getTraceAsString()); } + $res = CMDBSource::QueryToScalar("SELECT RELEASE_LOCK('$sLockName')"); } -catch (Exception $e) +else { - $oP->p("ERROR: '".$e->getMessage()."'"); - if ($bDebug) - { - // Might contain verb parameters such a password... - $oP->p($e->getTraceAsString()); - } + // Lock already held by another session + // Exit silently + $oP->p("Already running..."); } - $oP->p("Exiting: ".time().' ('.date('Y-m-d H:i:s').')'); $oP->Output();