From d0d43a7b1c08a8d9a3252bc6cefaed171f2fcfce Mon Sep 17 00:00:00 2001
From: mattab <matthieu.aubry@gmail.com>
Date: Mon, 17 Jun 2013 22:42:59 +1200
Subject: [PATCH] Committing two new files

---
 core/DataAccess/ArchiveTableCreator.php |  29 +++
 core/DataAccess/ArchiveWriter.php       | 261 ++++++++++++++++++++++++
 2 files changed, 290 insertions(+)
 create mode 100644 core/DataAccess/ArchiveTableCreator.php
 create mode 100644 core/DataAccess/ArchiveWriter.php

diff --git a/core/DataAccess/ArchiveTableCreator.php b/core/DataAccess/ArchiveTableCreator.php
new file mode 100644
index 0000000000..9046f631a7
--- /dev/null
+++ b/core/DataAccess/ArchiveTableCreator.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ * @category Piwik
+ * @package Piwik
+ */
+
+class Piwik_DataAccess_ArchiveTableCreator
+{
+    static public function getNumericTable(Piwik_Date $date)
+    {
+        return self::getTable($date, "numeric");
+    }
+    static public function getBlobTable(Piwik_Date $date)
+    {
+        return self::getTable($date, "blob");
+    }
+
+    static protected function getTable(Piwik_Date $date, $type)
+    {
+        Piwik_TablePartitioning_Monthly::createArchiveTablesIfAbsent($date);
+
+        return Piwik_Common::prefixTable("archive_" . $type . "_" . $date->toString('Y_m'));
+    }
+}
\ No newline at end of file
diff --git a/core/DataAccess/ArchiveWriter.php b/core/DataAccess/ArchiveWriter.php
new file mode 100644
index 0000000000..7c42fb5ee5
--- /dev/null
+++ b/core/DataAccess/ArchiveWriter.php
@@ -0,0 +1,261 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ * @category Piwik
+ * @package Piwik
+ */
+
+class Piwik_DataAccess_ArchiveWriter
+{
+    /**
+     * A row is created to lock an idarchive for the current archive being processed
+     * @var string
+     */
+    const PREFIX_SQL_LOCK = "locked_";
+
+    protected $fields = array('idarchive',
+                              'idsite',
+                              'date1',
+                              'date2',
+                              'period',
+                              'ts_archived',
+                              'name',
+                              'value');
+
+    public function __construct($idSite, Piwik_Segment $segment, Piwik_Period $period, $requestedPlugin, $isArchiveTemporary)
+    {
+        $this->idArchive = false;
+        $this->idSite = $idSite;
+        $this->segment = $segment;
+        $this->period = $period;
+        $this->doneFlag = Piwik_ArchiveProcessor_Rules::getDoneStringFlagFor($segment, $period->getLabel(), $requestedPlugin);
+        $this->isArchiveTemporary = $isArchiveTemporary;
+
+        $this->dateStart = $this->period->getDateStart();
+        $this->numericTable = Piwik_DataAccess_ArchiveTableCreator::getNumericTable($this->dateStart);
+        $this->blobTable = Piwik_DataAccess_ArchiveTableCreator::getBlobTable($this->dateStart);
+    }
+
+    public function getIdArchive()
+    {
+        if($this->idArchive === false) {
+            throw new Exception("Must call allocateNewArchiveId() first");
+        }
+        return $this->idArchive;
+    }
+
+    public function initNewArchive()
+    {
+        $this->acquireLock();
+        $this->allocateNewArchiveId();
+        $this->logArchiveStatusAsIncomplete();
+    }
+
+    protected function acquireLock()
+    {
+        $lockName = $this->getArchiveProcessorLockName();
+        $result = Piwik_GetDbLock($lockName, $maxRetries = 30);
+        if (!$result) {
+            Piwik::log("SELECT GET_LOCK failed to acquire lock. Proceeding anyway.");
+        }
+    }
+
+    protected function allocateNewArchiveId()
+    {
+        $this->idArchive = $this->insertNewArchiveId();
+        return $this->idArchive;
+    }
+
+    protected function insertNewArchiveId()
+    {
+        $table = $this->numericTable;
+        $idSite = $this->idSite;
+
+        $db = Zend_Registry::get('db');
+        $locked = self::PREFIX_SQL_LOCK . Piwik_Common::generateUniqId();
+        $date = date("Y-m-d H:i:s");
+        $dbLockName = "allocateNewArchiveId.$table";
+
+        if (Piwik_GetDbLock($dbLockName, $maxRetries = 30) === false) {
+            throw new Exception("allocateNewArchiveId: Cannot get named lock for table $table.");
+        }
+        $insertSql = "INSERT INTO $table "
+            . " SELECT ifnull(max(idarchive),0)+1,
+								'" . $locked . "',
+								" . (int)$idSite . ",
+								'" . $date . "',
+								'" . $date . "',
+								0,
+								'" . $date . "',
+								0 "
+            . " FROM $table as tb1";
+        $db->exec($insertSql);
+        Piwik_ReleaseDbLock($dbLockName);
+        $selectIdSql = "SELECT idarchive FROM $table WHERE name = ? LIMIT 1";
+        $id = $db->fetchOne($selectIdSql, $locked);
+        return $id;
+    }
+
+    protected function logArchiveStatusAsIncomplete()
+    {
+        $statusWhileProcessing = Piwik_ArchiveProcessor::DONE_ERROR;
+        $this->insertRecord($this->doneFlag, $statusWhileProcessing);
+    }
+
+    protected function getArchiveProcessorLockName()
+    {
+        return self::makeLockName($this->idSite, $this->period, $this->segment);
+    }
+
+    /**
+     * @param $idsite
+     * @param $period
+     * @param Piwik_Segment $segment
+     * @return string
+     */
+    protected static function makeLockName($idsite, Piwik_Period $period, Piwik_Segment $segment)
+    {
+        $config = Piwik_Config::getInstance();
+
+        $lockName = 'piwik.'
+            . $config->database['dbname'] . '.'
+            . $config->database['tables_prefix'] . '/'
+            . $idsite . '/'
+            . (!$segment->isEmpty() ? $segment->getHash() . '/' : '')
+            . $period->getId() . '/'
+            . $period->getDateStart()->toString('Y-m-d') . ','
+            . $period->getDateEnd()->toString('Y-m-d');
+        return $lockName . '/' . md5($lockName . Piwik_Common::getSalt());
+    }
+
+    public function finalizeArchive()
+    {
+        $this->deletePreviousArchiveStatus();
+        $this->logArchiveStatusAsFinal();
+        $this->releaseArchiveProcessorLock();
+
+        if($this->period->getLabel() != 'day') {
+            $purgeArchivesOlderThan = Piwik_ArchiveProcessor_Rules::doPurgeOutdatedArchives($this->dateStart);
+            if($purgeArchivesOlderThan) {
+                Piwik_DataAccess_ArchiveSelector::purgeOutdatedArchives($this->dateStart, $purgeArchivesOlderThan);
+            }
+        }
+    }
+
+    protected function deletePreviousArchiveStatus()
+    {
+        Piwik_Query("DELETE FROM " . $this->numericTable . "
+					WHERE idarchive = ? AND (name = '" . $this->doneFlag . "' OR name LIKE '" . self::PREFIX_SQL_LOCK . "%')",
+            array($this->getIdArchive())
+        );
+    }
+
+    protected function logArchiveStatusAsFinal()
+    {
+        $status = Piwik_ArchiveProcessor::DONE_OK;
+        if ($this->isArchiveTemporary) {
+            $status = Piwik_ArchiveProcessor::DONE_OK_TEMPORARY;
+        }
+        $this->insertRecord($this->doneFlag, $status);
+    }
+
+    protected function releaseArchiveProcessorLock()
+    {
+        $lockName = $this->getArchiveProcessorLockName();
+        return Piwik_ReleaseDbLock($lockName);
+    }
+
+    public function insertBulkRecords($records)
+    {
+        // Using standard plain INSERT if there is only one record to insert
+        if ($DEBUG_DO_NOT_USE_BULK_INSERT = false
+            || count($records) == 1
+        ) {
+            foreach ($records as $record) {
+                $this->insertRecord($record[0], $record[1]);
+            }
+            return true;
+        }
+        $bindSql = $this->getInsertRecordBind();
+        $values = array();
+
+        $valueSeen = false;
+        foreach ($records as $record) {
+            // don't record zero
+            if (empty($record[1])) continue;
+
+            $bind = $bindSql;
+            $bind[] = $record[0]; // name
+            $bind[] = $record[1]; // value
+            $values[] = $bind;
+
+            $valueSeen = $record[1];
+        }
+        if (empty($values)) return true;
+
+        $tableName = $this->getTableNameToInsert($valueSeen);
+
+        Piwik::tableInsertBatch($tableName, $this->getInsertFields(), $values);
+        return true;
+    }
+
+    /**
+     * Inserts a record in the right table (either NUMERIC or BLOB)
+     *
+     * @param string $name
+     * @param mixed $value
+     */
+    public function insertRecord($name, $value)
+    {
+        if ($this->isRecordZero($value)) {
+            return false;
+        }
+
+        $tableName = $this->getTableNameToInsert($value);
+
+        // duplicate idarchives are Ignored, see http://dev.piwik.org/trac/ticket/987
+
+        $query = "INSERT IGNORE INTO " . $tableName . "
+					(" . implode(", ", $this->getInsertFields()) . ")
+					VALUES (?,?,?,?,?,?,?,?)";
+        $bindSql = $this->getInsertRecordBind();
+        $bindSql[] = $name;
+        $bindSql[] = $value;
+        Piwik_Query($query, $bindSql);
+        return true;
+    }
+
+    protected function getInsertRecordBind()
+    {
+        return array($this->getIdArchive(),
+                     $this->idSite,
+                     $this->dateStart->toString('Y-m-d'),
+                     $this->period->getDateEnd()->toString('Y-m-d'),
+                     $this->period->getId(),
+                     date("Y-m-d H:i:s"));
+    }
+
+    protected function getTableNameToInsert($value)
+    {
+        if (is_numeric($value)) {
+            return $this->numericTable;
+        }
+        return $this->blobTable;
+    }
+
+    protected function getInsertFields()
+    {
+        return $this->fields;
+    }
+
+    protected function isRecordZero($value)
+    {
+        return ($value === '0' || $value === false || $value === 0 || $value === 0.0);
+    }
+
+
+}
\ No newline at end of file
-- 
GitLab