예제 #1
0
 /**
  * @test
  * @group DbHelper
  * @group reusesDbConnection
  * @group reuseDb
  */
 public function reusesDbConnection()
 {
     $config = Hashmark::getConfig('DbHelper');
     $link = new mysqli($config['profile']['unittest']['params']['host'], $config['profile']['unittest']['params']['username'], $config['profile']['unittest']['params']['password'], $config['profile']['unittest']['params']['dbname'], $config['profile']['unittest']['params']['port']);
     $db = Hashmark::getModule('DbHelper')->reuseDb($link, 'Mysqli');
     $this->assertEquals('mysqli', get_class($db->getConnection()));
 }
예제 #2
0
 /**
  * Resources needed for most tests.
  *
  * @return void
  */
 protected function setUp()
 {
     parent::setUp();
     $this->_partition = Hashmark::getModule('Partition', '', $this->_db);
     $this->_core = Hashmark::getModule('Core', '', $this->_db);
     $this->_mergeTablePrefix = Hashmark::getConfig('Partition', '', 'mergetable_prefix');
 }
예제 #3
0
 /**
  * Called by Hashmark::getModule() to inject dependencies.
  *
  * @param mixed                 $db         Connection object/resource.
  * @param string                $dbName     Database selection, unquoted. [optional]
  * @param Hashmark_Partition    $partition  Initialized instance.
  * @return boolean  False if module could not be initialized and is unusable.
  *                  Hashmark::getModule() will also then return false.
  */
 public function initModule($db, $partition = '')
 {
     parent::initModule($db);
     $this->_partition = $partition;
     $dbHelperConfig = Hashmark::getConfig('DbHelper');
     $this->_divPrecisionIncr = $dbHelperConfig['div_precision_increment'];
     return true;
 }
예제 #4
0
 /**
  * @test
  * @group Cron
  * @group collectsGarbageMergeTables
  * @group getAllMergeTables
  */
 public function collectsGarbageMergeTables()
 {
     $partition = Hashmark::getModule('Partition', '', $this->_db);
     $mergeTablePrefix = Hashmark::getConfig('Partition', '', 'mergetable_prefix');
     // Drop all merge tables to clear the slate.
     $priorMergeTables = $partition->getTablesLike($mergeTablePrefix . '%');
     if ($priorMergeTables) {
         $partition->dropTable($priorMergeTables);
     }
     $scalar = array();
     $scalar['name'] = self::randomString();
     $scalar['type'] = 'decimal';
     $scalarId = Hashmark::getModule('Core', '', $this->_db)->createScalar($scalar);
     $regTableName = 'test_samples_' . self::randomString();
     $partition->createTable($scalarId, $regTableName, $scalar['type']);
     $now = time();
     $start = '2008-04-01 01:45:59';
     $mergeTableNames = array();
     // Create several merge tables from the same single normal table.
     // Space them 1 day apart.
     // Vary $end to make the merge table names unique.
     for ($t = 0; $t < 5; $t++) {
         $end = "2009-06-1{$t} 01:45:59";
         $comment = gmdate(HASHMARK_DATETIME_FORMAT, $now - $t * 86400);
         $mergeTableNames[$t] = $mergeTablePrefix . "{$scalarId}_20080401_2009061{$t}";
         $actualTable = $partition->createMergeTable($scalarId, $start, $end, array($regTableName), $comment);
         $this->assertEquals($mergeTableNames[$t], $actualTable);
     }
     $maxDays = 3;
     $maxCount = 2;
     ob_start();
     require HASHMARK_ROOT_DIR . '/Cron/gcMergeTables.php';
     ob_end_clean();
     for ($t = 0; $t < 5; $t++) {
         if ($t < 2) {
             $this->assertTrue($partition->tableExists($mergeTableNames[$t]), "Expected {$mergeTableNames[$t]} to exist");
         } else {
             $this->assertFalse($partition->tableExists($mergeTableNames[$t]), "Expected {$mergeTableNames[$t]} to be missing");
         }
     }
 }
예제 #5
0
 /**
  * Return minimum based on bccomp().
  *
  * @param Array     $values
  * @return string   Minimum value.
  * @throws  Exception if $values is not a populated Array.
  */
 public static function min($values)
 {
     if (!is_array($values) || empty($values)) {
         throw new Exception('min() requires a populated Array.', HASHMARK_EXCEPTION_VALIDATION);
     }
     bcscale(Hashmark::getConfig('DbHelper', '', 'decimal_right_width'));
     usort($values, 'bccomp');
     return $values[0];
 }
예제 #6
0
 * @package     Hashmark
 * @subpackage  Cron
 * @version     $Id$
*/
/**
 * For getModule() and cron constants.
 */
require_once dirname(__FILE__) . '/../Hashmark.php';
// Max. table age in days.
if (!isset($maxDays)) {
    $maxDays = Hashmark::getConfig('Cron', '', 'merge_gc_max_days');
}
// Max. table count. Non-expired tables will be sorted
// by age descending and then pruned.
if (!isset($maxCount)) {
    $maxCount = Hashmark::getConfig('Cron', '', 'merge_gc_max_count');
}
$db = Hashmark::getModule('DbHelper')->openDb('cron');
$partition = Hashmark::getModule('Partition', '', $db);
$garbageTables = array();
$keepTables = array();
$now = time();
$all = $partition->getAllMergeTables();
foreach ($all as $table) {
    $unixTime = strtotime($table['TABLE_COMMENT'] . ' UTC');
    // Ex. merge tables who no longer match an updated partition schema.
    if (!$unixTime) {
        $garbageTables[] = $table['TABLE_NAME'];
        continue;
    }
    if ($unixTime + $maxDays * 86400 < $now) {
예제 #7
0
 /**
  * Testable logic for assertDecimalEquals().
  *
  * @param string    $expected
  * @param string    $actual
  * @return boolean  True if equal.
  */
 public static function checkDecimalEquals($expected, $actual)
 {
     if (!is_string($expected) || !is_string($actual)) {
         return false;
     }
     bcscale(Hashmark::getConfig('DbHelper', '', 'decimal_right_width'));
     return 0 === bccomp($expected, $actual);
 }
예제 #8
0
 *      -   @name macros will not be escaped nor quoted, ex. SQL functions.
 *      -   ~name table name macros will be backtick-quoted.
 *      -   To set the destination columns for the INSERT INTO ... SELECT
 *          that populates a temp. table with macro named ~exampleTemp~,
 *          define macro @exampleTempCols, ex. w/ value: `x`, `y`
 *      -   ROUND() used to avoid truncation warnings.
 *
 * @filesource
 * @copyright   Copyright (c) 2008-2011 David Smith
 * @license     http://www.opensource.org/licenses/mit-license.php MIT License
 * @package     Hashmark
 * @subpackage  Sql
 * @version     $Id$
*/
$decimalTotalWidth = Hashmark::getConfig('DbHelper', '', 'decimal_total_width');
$decimalRightWidth = Hashmark::getConfig('DbHelper', '', 'decimal_right_width');
$sql = array();
$sql['values'] = 'SELECT `end` AS `x`, ' . '`value` AS `y` ' . 'FROM ~samples ' . 'WHERE `end` >= ? ' . 'AND `end` <= ? ';
/**
 *  -   Self-join allows us to pull the most recent row from inside each
 *      interval to reprsent the whole.
 *  -   Duplicate the start/end conditions in the self-join
 *      in order to narrow `s2` scan.
 */
$sql['valuesAtInterval'] = 'SELECT `s1`.`end` AS `x`, ' . '`s1`.`value` AS `y` ' . 'FROM ~samples AS `s1` ' . 'LEFT JOIN ~samples AS `s2` ' . 'ON DATE_FORMAT(`s1`.`end`, ?) = DATE_FORMAT(`s2`.`end`, ?) ' . 'AND `s1`.`end` < `s2`.`end` ' . 'AND `s2`.`end` >= ? ' . 'AND `s2`.`end` <= ? ' . 'WHERE `s1`.`end` >= ? ' . 'AND `s1`.`end` <= ? ' . 'AND `s2`.`end` IS NULL ';
$sql['valuesAgg'] = 'SELECT ROUND(@aggFunc(@distinct`value`), ' . $decimalRightWidth . ') AS `y` ' . 'FROM ~samples ' . 'WHERE `end` >= ? ' . 'AND `end` <= ? ';
$sql['valuesAggAtInterval'] = 'SELECT DATE_FORMAT(`end`, ?) AS `x`, ' . 'ROUND(@aggFunc(@distinct`value`), ' . $decimalRightWidth . ') AS `y` ' . 'FROM ~samples ' . 'WHERE `end` >= ? ' . 'AND `end` <= ? ' . 'GROUP BY `x` ';
$sql['valuesNestedAggAtInterval'] = 'SELECT ROUND(@aggFunc(@distinct`y2`), ' . $decimalRightWidth . ') AS `y2` ' . 'FROM ~valuesAggAtInterval ';
$sql['valuesAggAtRecurrence'] = 'SELECT @recurFunc(`end`) AS `x`, ' . 'ROUND(@aggFunc(@distinct`value`), ' . $decimalRightWidth . ') AS `y` ' . 'FROM ~samples ' . 'WHERE `end` >= ? ' . 'AND `end` <= ? ' . 'GROUP BY @recurFunc(`end`) ';
/**
 *  -   Duplicate the start/end conditions in the self-join
예제 #9
0
 */
$modList = array('BcMath' => '', 'Cache' => '', 'Client' => '', 'Core' => '', 'DbHelper' => '', 'Partition' => '', 'Agent' => 'YahooWeather', 'Test' => 'FakeModuleType');
foreach ($modList as $baseName => $typeName) {
    // Cache modules don't use the DB argument,
    // but it should have no effect.
    $inst = Hashmark::getModule($baseName, $typeName, $mockDb);
    if ($typeName) {
        $className = "Hashmark_{$baseName}_{$typeName}";
    } else {
        $className = "Hashmark_{$baseName}";
    }
    $testDetail = "{$className} module.\n";
    if ($inst instanceof $className) {
        echo "pass: Loaded {$testDetail}";
    } else {
        echo "====> FAIL: Could not load {$testDetail}";
    }
}
/**
 *
 * Misc. configuration value checks.
 *
 */
$mockScalarId = 1234;
$partitionTableName = Hashmark::getModule('Partition', '', $mockDb)->getIntervalTableName($mockScalarId);
$testDetail = "partition name with '" . Hashmark::getConfig('Partition', '', 'interval') . "' setting in Config/Partition.php.\n";
if ($partitionTableName) {
    echo "pass: Built {$partitionTableName} {$testDetail}";
} else {
    echo "====> FAIL: Could not build {$testDetail}";
}
예제 #10
0
 /**
  * Increment a scalar identified by name.
  *
  * @param string    $name
  * @param string    $amount
  * @param boolean   $newSample  If true, a new sample partition row is inserted
  *                              `scalars` is updated.
  * @return boolean  True on success.
  * @throws Exception On query error or non-string $scalarName.
  */
 public function incr($scalarName, $amount = '1', $newSample = false)
 {
     if (!is_string($scalarName)) {
         throw new Exception('Cannot look up scalar with a non-string name.', HASHMARK_EXCEPTION_VALIDATION);
     }
     if (!preg_match('/[0-9.-]+/', $amount)) {
         throw new Exception('Cannot increment/decrement a scalar an invalid amount.', HASHMARK_EXCEPTION_VALIDATION);
     }
     if ($this->_createScalarIfNotExists) {
         $core = $this->getModule('Core');
         $scalarId = $core->getScalarIdByName($scalarName);
         if (!$scalarId) {
             $fields = array('name' => $scalarName, 'type' => 'decimal', 'value' => $amount, 'description' => 'Auto-created by client');
             $scalarId = $core->createScalar($fields);
             if (!$scalarId) {
                 throw new Exception("Scalar '{$scalarName}' was not auto-created", HASHMARK_EXCEPTION_SQL);
             }
             if ($newSample) {
                 $sql = 'INSERT INTO ~samples ' . '(`value`, `end`) ' . "VALUES ({$amount}, UTC_TIMESTAMP())";
                 $partition = $this->getModule('Partition');
                 $partition->queryCurrent($scalarId, $sql);
             }
             return true;
         }
     }
     $dbHelperConfig = Hashmark::getConfig('DbHelper');
     $sum = 'CONVERT(`value`, DECIMAL' . "({$dbHelperConfig['decimal_total_width']},{$dbHelperConfig['decimal_right_width']})) + " . $this->escape($amount);
     if ($newSample) {
         $sql = "UPDATE {$this->_dbName}`scalars` " . "SET `value` = {$sum}, " . '`last_inline_change` = UTC_TIMESTAMP() ' . 'WHERE `name` = ? ' . 'AND `type` = "decimal"';
         $stmt = $this->_db->query($sql, array($scalarName));
         if (!$stmt->rowCount()) {
             return false;
         }
         unset($stmt);
         $currentScalarValue = "SELECT `value` FROM {$this->_dbName}`scalars` WHERE `name` = ? LIMIT 1";
         $sql = 'INSERT INTO ~samples ' . '(`value`, `end`) ' . "VALUES (({$currentScalarValue}), UTC_TIMESTAMP())";
         $scalarId = $this->getModule('Core')->getScalarIdByName($scalarName);
         $partition = $this->getModule('Partition');
         $stmt = $partition->queryCurrent($scalarId, $sql, array($scalarName));
     } else {
         $sql = "UPDATE {$this->_dbName}`scalars` " . "SET `value` = {$sum}, " . '`last_inline_change` = UTC_TIMESTAMP() ' . 'WHERE `name` = ? ' . 'AND `type` = "decimal"';
         $stmt = $this->_db->query($sql, array($scalarName));
     }
     return 1 == $stmt->rowCount();
 }