public function purgeOutdatedArchives() { $archiveTables = ArchiveTableCreator::getTablesArchivesInstalled(); foreach ($archiveTables as $table) { $date = ArchiveTableCreator::getDateFromTableName($table); list($year, $month) = explode('_', $date); // Somehow we may have archive tables created with older dates, prevent exception from being thrown if ($year > 1990) { ArchiveSelector::purgeOutdatedArchives(Date::factory("{$year}-{$month}-15")); } } }
/** * Gets the IDs of the archives we're querying for and stores them in $this->archives. * This function will not launch the archiving process (and is thus much, much faster * than cacheArchiveIdsAfterLaunching). * * @param array $plugins List of plugin names from which data is being requested. */ private function cacheArchiveIdsWithoutLaunching($plugins) { $idarchivesByReport = ArchiveSelector::getArchiveIds($this->params->getIdSites(), $this->params->getPeriods(), $this->params->getSegment(), $plugins, $this->params->isSkipAggregationOfSubTables()); // initialize archive ID cache for each report foreach ($plugins as $plugin) { $doneFlag = $this->getDoneStringForPlugin($plugin); $this->initializeArchiveIdCache($doneFlag); } foreach ($idarchivesByReport as $doneFlag => $idarchivesByDate) { foreach ($idarchivesByDate as $dateRange => $idarchives) { foreach ($idarchives as $idarchive) { $this->idarchives[$doneFlag][$dateRange][] = $idarchive; } } } }
/** * Returns the idArchive if the archive is available in the database for the requested plugin. * Returns false if the archive needs to be processed. * * @return array */ protected function loadExistingArchiveIdFromDb() { $noArchiveFound = array(false, false, false); // see isArchiveTemporary() $minDatetimeArchiveProcessedUTC = $this->getMinTimeArchiveProcessed(); if ($this->isArchivingForcedToTrigger()) { return $noArchiveFound; } $idAndVisits = ArchiveSelector::getArchiveIdAndVisits($this->params, $minDatetimeArchiveProcessedUTC); if (!$idAndVisits) { return $noArchiveFound; } return $idAndVisits; }
/** * Returns the idArchive if the archive is available in the database for the requested plugin. * Returns false if the archive needs to be processed. * * @return array */ protected function loadExistingArchiveIdFromDb() { $noArchiveFound = array(false, false, false); // see isArchiveTemporary() $minDatetimeArchiveProcessedUTC = $this->getMinTimeArchiveProcessed(); if ($this->isArchivingForcedToTrigger()) { return $noArchiveFound; } $site = $this->params->getSite(); $period = $this->params->getPeriod(); $segment = $this->params->getSegment(); $requestedPlugin = $this->params->getRequestedPlugin(); $idAndVisits = ArchiveSelector::getArchiveIdAndVisits($site, $period, $segment, $minDatetimeArchiveProcessedUTC, $requestedPlugin); if (!$idAndVisits) { return $noArchiveFound; } return $idAndVisits; }
/** * Queries and returns archive data using a set of archive IDs. * * @param array $archiveIds The IDs of the archives to get data from. * @param array $recordNames The names of the data to retrieve (ie, nb_visits, nb_actions, etc.) * @param string $archiveDataType The archive data type (either, 'blob' or 'numeric'). * @param int|null|string $idSubtable null if the root blob should be loaded, an integer if a subtable should be * loaded and 'all' if all subtables should be loaded. * @throws Exception * @return array */ public function getArchiveData($archiveIds, $recordNames, $archiveDataType, $idSubtable) { $chunk = new Chunk(); // create the SQL to select archive data $loadAllSubtables = $idSubtable == Archive::ID_SUBTABLE_LOAD_ALL_SUBTABLES; if ($loadAllSubtables) { $name = reset($recordNames); // select blobs w/ name like "$name_[0-9]+" w/o using RLIKE $nameEnd = strlen($name) + 1; $nameEndAppendix = $nameEnd + 1; $appendix = $chunk->getAppendix(); $lenAppendix = strlen($appendix); $checkForChunkBlob = "SUBSTRING(name FROM {$nameEnd} FOR {$lenAppendix}) = '{$appendix}'"; $checkForSubtableId = "(SUBSTRING(name FROM {$nameEndAppendix} FOR 1) >= '0'\n AND SUBSTRING(name FROM {$nameEndAppendix} FOR 1) <= '9')"; $whereNameIs = "(name = ? OR (name LIKE ? AND ( {$checkForChunkBlob} OR {$checkForSubtableId} ) ))"; $bind = array($name, $name . '%'); } else { if ($idSubtable === null) { // select root table or specific record names $bind = array_values($recordNames); } else { // select a subtable id $bind = array(); foreach ($recordNames as $recordName) { // to be backwards compatibe we need to look for the exact idSubtable blob and for the chunk // that stores the subtables (a chunk stores many blobs in one blob) $bind[] = $chunk->getRecordNameForTableId($recordName, $idSubtable); $bind[] = ArchiveSelector::appendIdSubtable($recordName, $idSubtable); } } $inNames = Common::getSqlStringFieldsArray($bind); $whereNameIs = "name IN ({$inNames})"; } $getValuesSql = "SELECT %s, name, idsite, date1, date2, ts_archived\n FROM %s\n WHERE idarchive IN (%s)\n AND " . $whereNameIs; // get data from every table we're querying $rows = array(); foreach ($archiveIds as $period => $ids) { if (empty($ids)) { throw new Exception("Unexpected: id archive not found for period '{$period}' '"); } // $period = "2009-01-04,2009-01-04", $date = Date::factory(substr($period, 0, 10)); $isNumeric = $archiveDataType == 'numeric'; if ($isNumeric) { $table = ArchiveTableCreator::getNumericTable($date); } else { $table = ArchiveTableCreator::getBlobTable($date); } $valueCol = $this->prepareForBinary($table); $sql = sprintf($getValuesSql, $valueCol, $table, implode(',', $ids)); $dataRows = $this->db->fetchAll($sql, $bind); $dataRows = $this->binaryOutput($dataRows, true); foreach ($dataRows as $row) { if ($isNumeric) { $rows[] = $row; } else { $row['value'] = $this->uncompress($row['value']); if ($chunk->isRecordNameAChunk($row['name'])) { $this->moveChunkRowToRows($rows, $row, $chunk, $loadAllSubtables, $idSubtable); } else { $rows[] = $row; } } } } return $rows; }
protected function moveChunkRowToRows(&$rows, $row, Chunk $chunk, $loadAllSubtables, $idSubtable) { // $blobs = array([subtableID] = [blob of subtableId]) $blobs = unserialize($row['value']); if (!is_array($blobs)) { return; } // $rawName = eg 'PluginName_ArchiveName' $rawName = $chunk->getRecordNameWithoutChunkAppendix($row['name']); if ($loadAllSubtables) { foreach ($blobs as $subtableId => $blob) { $row['value'] = $blob; $row['name'] = ArchiveSelector::appendIdSubtable($rawName, $subtableId); $rows[] = $row; } } elseif (array_key_exists($idSubtable, $blobs)) { $row['value'] = $blobs[$idSubtable]; $row['name'] = ArchiveSelector::appendIdSubtable($rawName, $idSubtable); $rows[] = $row; } }