diff --git a/core/Archive.php b/core/Archive.php index ebe0516a294dbed5c4e1dbdb7e3893a833e02845..4f4717f0918a37edb18ba755c112e7a761c93dba 100644 --- a/core/Archive.php +++ b/core/Archive.php @@ -41,7 +41,6 @@ */ class Piwik_Archive { - const FLAG_ALL_WEBSITES_REQUESTED = 'all'; /** * When saving DataTables in the DB, we sometimes replace the columns name by these IDs so we save up lots of bytes * Eg. INDEX_NB_UNIQ_VISITORS is an integer: 4 bytes, but 'nb_uniq_visitors' is 16 bytes at least @@ -103,6 +102,8 @@ class Piwik_Archive const INDEX_GOAL_ECOMMERCE_REVENUE_DISCOUNT = 7; const INDEX_GOAL_ECOMMERCE_ITEMS = 8; + const REQUEST_ALL_WEBSITES_FLAG = 'all'; + public static function getVisitsMetricNames() { $names = array(); @@ -308,7 +309,7 @@ class Piwik_Archive $allPeriods = array($oPeriod); } $segment = new Piwik_Segment($segment, $websiteIds); - $idSiteIsAll = $idSites == self::FLAG_ALL_WEBSITES_REQUESTED; + $idSiteIsAll = $idSites == self::REQUEST_ALL_WEBSITES_FLAG; return Piwik_Archive::factory($segment, $allPeriods, $websiteIds, $idSiteIsAll); } @@ -516,7 +517,7 @@ class Piwik_Archive return $result; } - $archiveData = Piwik_DataAccess_Archiver::getArchiveData($archiveIds, $archiveNames, $archiveDataType, $idSubtable); + $archiveData = Piwik_DataAccess_ArchiveSelector::getArchiveData($archiveIds, $archiveNames, $archiveDataType, $idSubtable); foreach ($archiveData as $row) { // values are grouped by idsite (site ID), date1-date2 (date range), then name (field name) $idSite = $row['idsite']; @@ -669,7 +670,7 @@ class Piwik_Archive */ private function cacheArchiveIdsWithoutLaunching($plugins) { - $idarchivesByReport = Piwik_DataAccess_Archiver::getArchiveIds( + $idarchivesByReport = Piwik_DataAccess_ArchiveSelector::getArchiveIds( $this->params->getIdSites(), $this->params->getPeriods(), $this->params->getSegment(), $plugins); // initialize archive ID cache for each report diff --git a/core/ArchiveProcessor.php b/core/ArchiveProcessor.php index 9791735d0e0f077bd6b447855e94116f61268043..c475177ee13e96a140c785f2642d968e7f7eb7b4 100644 --- a/core/ArchiveProcessor.php +++ b/core/ArchiveProcessor.php @@ -10,21 +10,8 @@ */ /** - * The ArchiveProcessor module is a module that reads the Piwik logs from the DB and - * compute all the reports, which are then stored in the database. - * * The ArchiveProcessor class is used by the Archive object to make sure the given Archive is processed and available in the DB. * - * A record in the Database for a given report is defined by - * - idarchive = unique ID that is associated to all the data of this archive (idsite+period+date) - * - idsite = the ID of the website - * - date1 = starting day of the period - * - date2 = ending day of the period - * - period = integer that defines the period (day/week/etc.). @see period::getId() - * - ts_archived = timestamp when the archive was processed (UTC) - * - name = the name of the report (ex: uniq_visitors or search_keywords_by_search_engines) - * - value = the actual data - * * @package Piwik * @subpackage Piwik_ArchiveProcessor */ @@ -74,13 +61,6 @@ abstract class Piwik_ArchiveProcessor */ protected $tableArchiveBlob; - /** - * Minimum timestamp looked at for processed archives - * - * @var int - */ - protected $minDatetimeArchiveProcessedUTC = false; - /** * Is the current archive temporary. ie. * - today @@ -88,13 +68,35 @@ abstract class Piwik_ArchiveProcessor */ protected $temporaryArchive; + protected $logAggregator = null; + /** - * This methods reads the subperiods if necessary, - * and computes the archive of the current period. + * @var int Number of visits cached as early as possible */ - abstract protected function compute(); + protected $visitsMetricCached = false; - abstract protected function aggregateCoreVisitsMetrics(); + /** + * @var int Number of visits with conversions, cached when selecting + */ + protected $convertedVisitsMetricCached = false; + + /** + * Site of the current archive + * Can be accessed by plugins (that is why it's public) + * + * @var Piwik_Site + */ + private $site = null; + + /** + * @var Piwik_Period + */ + private $period = null; + + /** + * @var Piwik_Segment + */ + private $segment = null; public function __construct(Piwik_Period $period, Piwik_Site $site, Piwik_Segment $segment) { @@ -103,65 +105,146 @@ abstract class Piwik_ArchiveProcessor $this->segment = $segment; } - protected $logAggregator = null; - /** * @return Piwik_DataAccess_LogAggregator */ public function getLogAggregator() { - if(empty($this->logAggregator)) { - $this->logAggregator = new Piwik_DataAccess_LogAggregator( $this->getPeriod()->getDateStart(), $this->getPeriod()->getDateEnd(), - $this->getSite(), $this->getSegment() ); + if (empty($this->logAggregator)) { + $this->logAggregator = new Piwik_DataAccess_LogAggregator($this->getPeriod()->getDateStart(), $this->getPeriod()->getDateEnd(), + $this->getSite(), $this->getSegment()); } return $this->logAggregator; } + public function preProcessArchive($requestedPlugin, $enforceProcessCoreMetricsOnly = false) + { + $this->idArchive = false; + + $this->setRequestedPlugin($requestedPlugin); + + if (!$enforceProcessCoreMetricsOnly) { + $this->idArchive = $this->loadExistingArchiveIdFromDb($requestedPlugin); + if ($this->isArchivingForcedToTrigger()) { + $this->idArchive = false; + $this->setNumberOfVisits(false); + } + if (!empty($this->idArchive)) { + return $this->idArchive; + } + + $visitsNotKnownYet = $this->getNumberOfVisits() === false; + + $createAnotherArchiveForVisitsSummary = !$this->doesRequestedPluginIncludeVisitsSummary($requestedPlugin) && $visitsNotKnownYet; + + if ($createAnotherArchiveForVisitsSummary) { + // recursive archive creation in case we create another separate one, for VisitsSummary core metrics + // We query VisitsSummary here, as it is needed in the call below ($this->getNumberOfVisits() > 0) + $requestedPlugin = $this->getRequestedPlugin(); + $this->preProcessArchive('VisitsSummary', $pleaseProcessCoreMetricsOnly = true); + $this->setRequestedPlugin($requestedPlugin); + if ($this->getNumberOfVisits() === false) { + throw new Exception("preProcessArchive() is expected to set number of visits to a numeric value."); + } + } + } + + return $this->computeNewArchive($requestedPlugin, $enforceProcessCoreMetricsOnly); + } + + public function setRequestedPlugin($plugin) + { + $this->requestedPlugin = $plugin; + } + /** - * Returns the minimum archive processed datetime to look at - * - * @return string Datetime string, or false if must look at any archive available + * Returns the idArchive if the archive is available in the database for the requested plugin. + * Returns false if the archive needs to be processed. * - * @public for tests + * @return int|false */ - public function getMinTimeArchivedProcessed() + protected function loadExistingArchiveIdFromDb($requestedPlugin) { + $minDatetimeArchiveProcessedUTC = $this->getMinTimeArchivedProcessed(); $site = $this->getSite(); - $segment = $this->getSegment(); $period = $this->getPeriod(); - $dateStart = $this->getDateStart(); - $dateEnd = $this->getDateEnd(); + $segment = $this->getSegment(); + $numericTableName = $this->getTableArchiveNumericName(); + $idAndVisits = Piwik_DataAccess_ArchiveSelector::getArchiveIdAndVisits($numericTableName, $site, $period, $segment, $minDatetimeArchiveProcessedUTC, $requestedPlugin); + if (!$idAndVisits) { + return false; + } + list($idArchive, $visits, $visitsConverted) = $idAndVisits; + $this->setNumberOfVisits($visits, $visitsConverted); + return $idArchive; + } + + protected static function determineIfArchivePermanent(Piwik_Date $dateEnd) + { $now = time(); $endTimestampUTC = strtotime($dateEnd->getDateEndUTC()); if ($endTimestampUTC <= $now) { // - if the period we are looking for is finished, we look for a ts_archived that // is greater than the last day of the archive - $this->temporaryArchive = false; return $endTimestampUTC; } + return false; + } - $this->temporaryArchive = true; - - $minimumArchiveTime = $now - Piwik_ArchiveProcessor_Rules::getTodayArchiveTimeToLive(); + /** + * Returns the minimum archive processed datetime to look at + * + * @return string Datetime string, or false if must look at any archive available + * + * @public for tests + */ + public function getMinTimeArchivedProcessed() + { - $isArchivingDisabled = Piwik_ArchiveProcessor_Rules::isArchivingDisabledFor($segment, $period->getLabel()); + $endDateTimestamp = self::determineIfArchivePermanent($this->getDateEnd()); + $isArchiveTemporary = ($endDateTimestamp === false); + $this->temporaryArchive = $isArchiveTemporary; - if ($isArchivingDisabled) { - if ($endTimestampUTC > $now - && $period->getNumberOfSubperiods() == 0 - && $dateStart->getTimestamp() <= $now - ) { - $minimumArchiveTime = false; - } else { - // However, if archiving is disabled for this request, we shall - // accept any archive that was processed today after 00:00:01 this morning - $timezone = $site->getTimezone(); - $minimumArchiveTime = Piwik_Date::factory(Piwik_Date::factory('now', $timezone)->getDateStartUTC())->setTimezone($timezone)->getTimestamp(); - } + if($endDateTimestamp) { + // Permanent archive + return $endDateTimestamp; } + // Temporary archive + return Piwik_ArchiveProcessor_Rules::getMinTimeProcessedForTemporaryArchive($this->getDateStart(), $this->getPeriod(), $this->getSegment(), $this->getSite()); + } + + /** + * @return Piwik_Date + */ + public function getDateStart() + { + return $this->getPeriod()->getDateStart()->setTimezone($this->getSite()->getTimezone()); + } - return $minimumArchiveTime; + /** + * @return Piwik_Date + */ + public function getDateEnd() + { + return $this->getPeriod()->getDateEnd()->setTimezone($this->getSite()->getTimezone()); + } + + /** + * A flag mechanism to store whether + * @param $visitsMetricCached + * @param bool $convertedVisitsMetricCached + */ + protected function setNumberOfVisits($visitsMetricCached, $convertedVisitsMetricCached = false) + { + if (empty($visitsMetricCached)) { + $visitsMetricCached = 0; + } + if (empty($convertedVisitsMetricCached)) { + $convertedVisitsMetricCached = 0; + } + $this->visitsMetricCached = (int)$visitsMetricCached; + $this->convertedVisitsMetricCached = (int)$convertedVisitsMetricCached; } protected function isArchivingForcedToTrigger() @@ -176,39 +259,9 @@ abstract class Piwik_ArchiveProcessor return Piwik_Config::getInstance()->Debug[$debugSetting]; } - public function preProcessArchive($requestedPlugin, $enforceProcessCoreMetricsOnly = false) + public function getNumberOfVisits() { - $this->idArchive = false; - - $this->setRequestedPlugin($requestedPlugin); - - if( !$enforceProcessCoreMetricsOnly ) { - $this->idArchive = $this->loadExistingArchiveIdFromDb($requestedPlugin); - if ($this->isArchivingForcedToTrigger()) { - $this->idArchive = false; - $this->setNumberOfVisits(false); - } - if (!empty($this->idArchive)) { - return $this->idArchive; - } - - $visitsNotKnownYet = $this->getNumberOfVisits() === false; - - $createAnotherArchiveForVisitsSummary = !$this->doesRequestedPluginIncludeVisitsSummary($requestedPlugin) && $visitsNotKnownYet; - - if ($createAnotherArchiveForVisitsSummary) { - // recursive archive creation in case we create another separate one, for VisitsSummary core metrics - // We query VisitsSummary here, as it is needed in the call below ($this->getNumberOfVisits() > 0) - $requestedPlugin = $this->getRequestedPlugin(); - $this->preProcessArchive('VisitsSummary', $pleaseProcessCoreMetricsOnly = true); - $this->setRequestedPlugin($requestedPlugin); - if($this->getNumberOfVisits() === false) { - throw new Exception("preProcessArchive() is expected to set number of visits to a numeric value."); - } - } - } - - return $this->computeNewArchive($requestedPlugin, $enforceProcessCoreMetricsOnly); + return $this->visitsMetricCached; } protected function doesRequestedPluginIncludeVisitsSummary($requestedPlugin) @@ -226,11 +279,9 @@ abstract class Piwik_ArchiveProcessor */ protected function computeNewArchive($requestedPlugin, $enforceProcessCoreMetricsOnly) { - if (!Piwik_DataAccess_Archiver::getArchiveProcessorLock($this->getSite()->getId(), $this->getPeriod(), $this->getSegment())) { - Piwik::log('SELECT GET_LOCK(?, 1) FAILED to acquire lock. Proceeding anyway...'); - } + Piwik_DataAccess_ArchiveSelector::getArchiveProcessorLock($this->getSite()->getId(), $this->getPeriod(), $this->getSegment()); - $this->idArchive = Piwik_DataAccess_Archiver::allocateNewArchiveId($this->getTableArchiveNumericName(), $this->getSite()->getId()); + $this->idArchive = Piwik_DataAccess_ArchiveSelector::allocateNewArchiveId($this->getTableArchiveNumericName(), $this->getSite()->getId()); $doneFlag = Piwik_ArchiveProcessor_Rules::getDoneStringFlagFor($this->getSegment(), $this->getPeriod()->getLabel(), $requestedPlugin); $this->insertNumericRecord($doneFlag, Piwik_ArchiveProcessor::DONE_ERROR); @@ -250,19 +301,7 @@ abstract class Piwik_ArchiveProcessor } } - $temporary = 'definitive archive'; - if ($this->isArchiveTemporary()) { - $temporary = 'temporary archive'; - } - Piwik::log(sprintf("'%s, idSite = %d (%s), segment '%s', report = '%s', UTC datetime [%s -> %s]", - $this->getPeriod()->getLabel(), - $this->getSite()->getId(), - $temporary, - $this->getSegment()->getString(), - $requestedPlugin, - $this->getDateStart()->getDateStartUTC(), - $this->getDateEnd()->getDateEndUTC() - )); + $this->logStatus($requestedPlugin); if ($this->getNumberOfVisits() > 0 && !$enforceProcessCoreMetricsOnly @@ -270,7 +309,7 @@ abstract class Piwik_ArchiveProcessor $this->compute(); } - Piwik_DataAccess_Archiver::deletePreviousArchiveStatus($this->getTableArchiveNumericName(), $doneFlag, $this->getIdArchive()); + Piwik_DataAccess_ArchiveSelector::deletePreviousArchiveStatus($this->getTableArchiveNumericName(), $doneFlag, $this->getIdArchive()); $flag = Piwik_ArchiveProcessor::DONE_OK; if ($this->isArchiveTemporary()) { @@ -278,77 +317,54 @@ abstract class Piwik_ArchiveProcessor } $this->insertNumericRecord($doneFlag, $flag); - Piwik_DataAccess_Archiver::releaseArchiveProcessorLock($this->getSite()->getId(), $this->getPeriod(), $this->getSegment()); + Piwik_DataAccess_ArchiveSelector::releaseArchiveProcessorLock($this->getSite()->getId(), $this->getPeriod(), $this->getSegment()); return $this->idArchive; } - /** - * Returns the name of the numeric table where the archive numeric values are stored - * - * @return string - */ - public function getTableArchiveNumericName() - { - if (empty($this->tableArchiveNumeric)) { - $this->tableArchiveNumeric = new Piwik_TablePartitioning_Monthly('archive_numeric'); - $this->tableArchiveNumeric->setTimestamp($this->getPeriod()->getDateStart()->getTimestamp()); - } - return $this->tableArchiveNumeric->getTableName(); - } + abstract protected function aggregateCoreVisitsMetrics(); /** - * Returns the name of the blob table where the archive blob values are stored - * - * @return string + * @param $requestedPlugin */ - public function getTableArchiveBlobName() + protected function logStatus($requestedPlugin) { - if (empty($this->tableArchiveBlob)) { - $this->tableArchiveBlob = new Piwik_TablePartitioning_Monthly('archive_blob'); - $this->tableArchiveBlob->setTimestamp($this->getPeriod()->getDateStart()->getTimestamp()); + $temporary = 'definitive archive'; + if ($this->isArchiveTemporary()) { + $temporary = 'temporary archive'; } - return $this->tableArchiveBlob->getTableName(); - } - - public function setRequestedPlugin($plugin) - { - $this->requestedPlugin = $plugin; + Piwik::log(sprintf("'%s, idSite = %d (%s), segment '%s', report = '%s', UTC datetime [%s -> %s]", + $this->getPeriod()->getLabel(), + $this->getSite()->getId(), + $temporary, + $this->getSegment()->getString(), + $requestedPlugin, + $this->getDateStart()->getDateStartUTC(), + $this->getDateEnd()->getDateEndUTC() + )); } - protected function getRequestedPlugin() + public function isArchiveTemporary() { - return $this->requestedPlugin; + return $this->temporaryArchive; } - protected $visitsMetricCached = false; - protected $convertedVisitsMetricCached = false; - /** - * A flag mechanism to store whether - * @param $visitsMetricCached - * @param bool $convertedVisitsMetricCached + * This methods reads the subperiods if necessary, + * and computes the archive of the current period. */ - protected function setNumberOfVisits($visitsMetricCached, $convertedVisitsMetricCached = false) - { - if (empty($visitsMetricCached)) { - $visitsMetricCached = 0; - } - if (empty($convertedVisitsMetricCached)) { - $convertedVisitsMetricCached = 0; - } - $this->visitsMetricCached = (int)$visitsMetricCached; - $this->convertedVisitsMetricCached = (int)$convertedVisitsMetricCached; - } + abstract protected function compute(); - public function getNumberOfVisits() + public function getNumberOfVisitsConverted() { - return $this->visitsMetricCached; + return $this->convertedVisitsMetricCached; } - public function getNumberOfVisitsConverted() + public function insertNumericRecords($numericRecords) { - return $this->convertedVisitsMetricCached; + foreach ($numericRecords as $name => $value) { + $this->insertNumericRecord($name, $value); + } } /** @@ -361,13 +377,6 @@ abstract class Piwik_ArchiveProcessor return $this->insertRecord($name, $value); } - public function insertNumericRecords($numericRecords) - { - foreach ($numericRecords as $name => $value) { - $this->insertNumericRecord($name, $value); - } - } - /** * @param string $name * @param string|array $values @@ -441,21 +450,6 @@ abstract class Piwik_ArchiveProcessor return true; } - protected function getInsertRecordBind() - { - return array($this->getIdArchive(), - $this->getSite()->getId(), - $this->getPeriod()->getDateStart()->toString('Y-m-d'), - $this->getPeriod()->getDateEnd()->toString('Y-m-d'), - $this->getPeriod()->getId(), - date("Y-m-d H:i:s")); - } - - protected function getInsertFields() - { - return array('idarchive', 'idsite', 'date1', 'date2', 'period', 'ts_archived', 'name', 'value'); - } - /** * Inserts a record in the right table (either NUMERIC or BLOB) * @@ -466,7 +460,7 @@ abstract class Piwik_ArchiveProcessor */ protected function insertRecord($name, $value) { - if($this->isRecordZero($name, $value)) { + if ($this->isRecordZero($name, $value)) { return; } @@ -481,6 +475,7 @@ abstract class Piwik_ArchiveProcessor $bindSql[] = $name; $bindSql[] = $value; Piwik_Query($query, $bindSql); + return true; } /** @@ -504,73 +499,56 @@ abstract class Piwik_ArchiveProcessor } /** - * Returns the idArchive if the archive is available in the database for the requested plugin. - * Returns false if the archive needs to be processed. + * Returns the name of the numeric table where the archive numeric values are stored * - * @return int|false + * @return string */ - protected function loadExistingArchiveIdFromDb($requestedPlugin) + public function getTableArchiveNumericName() { - $minDatetimeArchiveProcessedUTC = $this->getMinTimeArchivedProcessed(); - $site = $this->getSite(); - $period = $this->getPeriod(); - $segment = $this->getSegment(); - $numericTableName = $this->getTableArchiveNumericName(); - - $idAndVisits = Piwik_DataAccess_Archiver::getArchiveIdAndVisits($numericTableName, $site, $period, $segment, $minDatetimeArchiveProcessedUTC, $requestedPlugin); - if (!$idAndVisits) { - return false; + if (empty($this->tableArchiveNumeric)) { + $this->tableArchiveNumeric = new Piwik_TablePartitioning_Monthly('archive_numeric'); + $this->tableArchiveNumeric->setTimestamp($this->getPeriod()->getDateStart()->getTimestamp()); } - list($idArchive, $visits, $visitsConverted) = $idAndVisits; - $this->setNumberOfVisits($visits, $visitsConverted); - return $idArchive; + return $this->tableArchiveNumeric->getTableName(); } - /** - * Whether the specified plugin's reports should be archived - * @param string $pluginName - * @return bool - */ - public function shouldProcessReportsForPlugin($pluginName) + public function getPeriod() { - if (Piwik_ArchiveProcessor_Rules::shouldProcessReportsAllPlugins($this->getSegment(), $this->getPeriod()->getLabel())) { - return true; - } - // If any other segment, only process if the requested report belong to this plugin - $pluginBeingProcessed = $this->getRequestedPlugin(); - if ($pluginBeingProcessed == $pluginName) { - return true; - } - if (!Piwik_PluginsManager::getInstance()->isPluginLoaded($pluginBeingProcessed)) { - return true; - } - return false; + return $this->period; } /** - * Site of the current archive - * Can be accessed by plugins (that is why it's public) + * Returns the name of the blob table where the archive blob values are stored * - * @var Piwik_Site + * @return string */ - private $site = null; + public function getTableArchiveBlobName() + { + if (empty($this->tableArchiveBlob)) { + $this->tableArchiveBlob = new Piwik_TablePartitioning_Monthly('archive_blob'); + $this->tableArchiveBlob->setTimestamp($this->getPeriod()->getDateStart()->getTimestamp()); + } + return $this->tableArchiveBlob->getTableName(); + } - /** - * @var Piwik_Period - */ - private $period = null; + protected function getInsertFields() + { + return array('idarchive', 'idsite', 'date1', 'date2', 'period', 'ts_archived', 'name', 'value'); + } - /** - * @var Piwik_Segment - */ - private $segment = null; + protected function getInsertRecordBind() + { + return array($this->getIdArchive(), + $this->getSite()->getId(), + $this->getPeriod()->getDateStart()->toString('Y-m-d'), + $this->getPeriod()->getDateEnd()->toString('Y-m-d'), + $this->getPeriod()->getId(), + date("Y-m-d H:i:s")); + } - /** - * @return Piwik_Segment - */ - public function getSegment() + public function getIdArchive() { - return $this->segment; + return $this->idArchive; } /** @@ -581,34 +559,37 @@ abstract class Piwik_ArchiveProcessor return $this->site; } - public function getPeriod() - { - return $this->period; - } - /** - * @return Piwik_Date + * Whether the specified plugin's reports should be archived + * @param string $pluginName + * @return bool */ - public function getDateEnd() + public function shouldProcessReportsForPlugin($pluginName) { - return $this->getPeriod()->getDateEnd()->setTimezone($this->getSite()->getTimezone()); + if (Piwik_ArchiveProcessor_Rules::shouldProcessReportsAllPlugins($this->getSegment(), $this->getPeriod()->getLabel())) { + return true; + } + // If any other segment, only process if the requested report belong to this plugin + $pluginBeingProcessed = $this->getRequestedPlugin(); + if ($pluginBeingProcessed == $pluginName) { + return true; + } + if (!Piwik_PluginsManager::getInstance()->isPluginLoaded($pluginBeingProcessed)) { + return true; + } + return false; } /** - * @return Piwik_Date + * @return Piwik_Segment */ - public function getDateStart() - { - return $this->getPeriod()->getDateStart()->setTimezone($this->getSite()->getTimezone()); - } - - public function isArchiveTemporary() + public function getSegment() { - return $this->temporaryArchive; + return $this->segment; } - public function getIdArchive() + protected function getRequestedPlugin() { - return $this->idArchive; + return $this->requestedPlugin; } } diff --git a/core/ArchiveProcessor/Rules.php b/core/ArchiveProcessor/Rules.php index 5817dc5519766a3f92704df15e075834d6f2e8ab..942f21420e9e3a57e8fa152877534a12aed6caf5 100644 --- a/core/ArchiveProcessor/Rules.php +++ b/core/ArchiveProcessor/Rules.php @@ -8,6 +8,7 @@ class Piwik_ArchiveProcessor_Rules const OPTION_TODAY_ARCHIVE_TTL = 'todayArchiveTimeToLive'; const OPTION_BROWSER_TRIGGER_ARCHIVING = 'enableBrowserTriggerArchiving'; + static public function isBrowserTriggerEnabled() { $browserArchivingEnabled = Piwik_GetOption(self::OPTION_BROWSER_TRIGGER_ARCHIVING); @@ -16,6 +17,7 @@ class Piwik_ArchiveProcessor_Rules } return (bool)Piwik_Config::getInstance()->General['enable_browser_archiving_triggering']; } + public static function getTodayArchiveTimeToLive() { $timeToLive = Piwik_GetOption(self::OPTION_TODAY_ARCHIVE_TTL); @@ -93,7 +95,6 @@ class Piwik_ArchiveProcessor_Rules return $isArchivingDisabled; } - /** * Returns the name of the archive field used to tell the status of an archive, (ie, * whether the archive was created successfully or not). @@ -176,15 +177,13 @@ class Piwik_ArchiveProcessor_Rules else { $purgeArchivesOlderThan = Piwik_Date::factory('today')->getDateTime(); } - Piwik_DataAccess_Archiver::purgeOutdatedArchives($numericTable, $blobTable, $purgeArchivesOlderThan); - + Piwik_DataAccess_ArchiveSelector::purgeOutdatedArchives($numericTable, $blobTable, $purgeArchivesOlderThan); // these tables will be OPTIMIZEd daily in a scheduled task, to claim lost space } else { Piwik::log("Purging temporary archives: skipped."); } } - public static function setTodayArchiveTimeToLive($timeToLiveSeconds) { $timeToLiveSeconds = (int)$timeToLiveSeconds; @@ -193,4 +192,27 @@ class Piwik_ArchiveProcessor_Rules } Piwik_SetOption(self::OPTION_TODAY_ARCHIVE_TTL, $timeToLiveSeconds, $autoload = true); } + + static public function getMinTimeProcessedForTemporaryArchive(Piwik_Date $dateStart, Piwik_Period $period, Piwik_Segment $segment, + Piwik_Site $site) + { + $now = time(); + $minimumArchiveTime = $now - Piwik_ArchiveProcessor_Rules::getTodayArchiveTimeToLive(); + + $isArchivingDisabled = Piwik_ArchiveProcessor_Rules::isArchivingDisabledFor($segment, $period->getLabel()); + if ($isArchivingDisabled) { + if ($period->getNumberOfSubperiods() == 0 + && $dateStart->getTimestamp() <= $now + ) { + $minimumArchiveTime = false; + } else { + // However, if archiving is disabled for this request, we shall + // accept any archive that was processed today after 00:00:01 this morning + $timezone = $site->getTimezone(); + $minimumArchiveTime = Piwik_Date::factory(Piwik_Date::factory('now', $timezone)->getDateStartUTC())->setTimezone($timezone)->getTimestamp(); + } + } + return $minimumArchiveTime; + } + } \ No newline at end of file diff --git a/core/DataAccess/Archiver.php b/core/DataAccess/ArchiveSelector.php similarity index 94% rename from core/DataAccess/Archiver.php rename to core/DataAccess/ArchiveSelector.php index 005bef11ab9b7bd0bff0208c36158614034ecb86..98937fe9f801a622290f8064e410e88591c9cc87 100644 --- a/core/DataAccess/Archiver.php +++ b/core/DataAccess/ArchiveSelector.php @@ -11,8 +11,19 @@ /** * Data Access object used to query archives, create new archives, and insert data for them. + * + * A record in the Database for a given report is defined by + * - idarchive = unique ID that is associated to all the data of this archive (idsite+period+date) + * - idsite = the ID of the website + * - date1 = starting day of the period + * - date2 = ending day of the period + * - period = integer that defines the period (day/week/etc.). @see period::getId() + * - ts_archived = timestamp when the archive was processed (UTC) + * - name = the name of the report (ex: uniq_visitors or search_keywords_by_search_engines) + * - value = the actual data (a numeric value, or a blob of compressed serialized data) + * */ -class Piwik_DataAccess_Archiver +class Piwik_DataAccess_ArchiveSelector { const NB_VISITS_RECORD_LOOKED_UP = "nb_visits"; const NB_VISITS_CONVERTED_RECORD_LOOKED_UP = "nb_visits_converted"; @@ -58,8 +69,12 @@ class Piwik_DataAccess_Archiver */ static public function getArchiveProcessorLock($idsite, $period, $segment) { + $lockName = self::getArchiveProcessorLockName($idsite, $period, $segment); - return Piwik_GetDbLock($lockName, $maxRetries = 30); + $result = Piwik_GetDbLock($lockName, $maxRetries = 30); + if(!$result) { + Piwik::log('SELECT GET_LOCK(?, 1) FAILED to acquire lock. Proceeding anyway...'); + } } /** @@ -169,7 +184,9 @@ class Piwik_DataAccess_Archiver protected static function getVisitsMetricsFromResults($idArchive, $idArchiveVisitsSummary, $results) { $visits = $visitsConverted = false; - if($idArchiveVisitsSummary !== false) { + + $archiveWithVisitsMetricsWasFound = ($idArchiveVisitsSummary !== false); + if($archiveWithVisitsMetricsWasFound) { $visits = $visitsConverted = 0; } foreach ($results as $result) { diff --git a/tests/PHPUnit/Integration/expected/test_apiGetReportMetadata__API.getSegmentsMetadata.xml b/tests/PHPUnit/Integration/expected/test_apiGetReportMetadata__API.getSegmentsMetadata.xml index 61062e2f5016e1543807bd6c9f51c29d747964ce..7488f019ffc7e7d5c91107145e26b17e8a976492 100644 --- a/tests/PHPUnit/Integration/expected/test_apiGetReportMetadata__API.getSegmentsMetadata.xml +++ b/tests/PHPUnit/Integration/expected/test_apiGetReportMetadata__API.getSegmentsMetadata.xml @@ -168,6 +168,7 @@ <name>Visitor ID</name> <segment>visitorId</segment> <acceptedValues>34c31e04394bdc63 - any 16 Hexadecimal chars ID, which can be fetched using the Tracking API function getVisitorId()</acceptedValues> + <permission>1</permission> </row> <row> <type>dimension</type>