protected function execute(InputInterface $input, OutputInterface $output) { $property = $input->getArgument('property'); $model = null; // "Volkszaehler\\Model\\Channel" $entity_groups = array(); echo "Reporting property usage of '" . $property . "'\n"; foreach (Definition\EntityDefinition::get() as $entity) { if ($model && $entity->getModel() !== $model) { continue; } if (!isset($entity_groups[$entity->getInterpreter()])) { $entity_groups[$entity->getInterpreter()] = array(); } $entity_groups[$entity->getInterpreter()][] = $entity; } foreach ($entity_groups as $group => $entities) { echo "\n== " . $group . " ==\n"; foreach ($entities as $entity) { echo str_pad($entity->getName() . ":", 16); if (in_array($property, $entity->required)) { echo "required\n"; } elseif (in_array($property, $entity->optional)) { echo "optional\n"; } else { echo "not allowed\n"; } } echo "\n"; } }
/** * @todo * @param string $capabilities * @param string $sub */ public function get($section = NULL) { $capabilities = array(); if (is_null($section) || $section == 'configuration') { $configuration = array('precision' => View\View::PRECISION, 'database' => Util\Configuration::read('db.driver'), 'debug' => Util\Configuration::read('debug'), 'devmode' => Util\Configuration::read('devmode')); $capabilities['configuration'] = $configuration; } if (is_null($section) || $section == 'formats') { $capabilities['formats'] = array_keys(\Volkszaehler\Router::$viewMapping); } if (is_null($section) || $section == 'contexts') { $capabilities['contexts'] = array_keys(\Volkszaehler\Router::$controllerMapping); } if (is_null($section) || $section == 'definitions') { if (!is_null($section)) { // only caching when we doesn't request dynamic informations $this->view->setCaching('expires', time() + 2 * 7 * 24 * 60 * 60); // cache for 2 weeks } $capabilities['definitions']['entities'] = Definition\EntityDefinition::get(); $capabilities['definitions']['properties'] = Definition\PropertyDefinition::get(); } if (count($capabilities) == 0) { throw new \Exception('Invalid capability identifier: \'' . $section . '\''); } return array('capabilities' => $capabilities); }
protected function execute(InputInterface $input, OutputInterface $output) { $property = $input->getArgument('property'); $model = null; // "Volkszaehler\\Model\\Channel" $entity_groups = array(); echo "Reporting property usage of '" . $property . "'\n"; foreach (Definition\EntityDefinition::get() as $entity) { if ($model && $entity->getModel() !== $model) { continue; } if (!isset($entity_groups[$entity->getInterpreter()])) { $entity_groups[$entity->getInterpreter()] = array(); } $entity_groups[$entity->getInterpreter()][] = $entity; } foreach ($entity_groups as $group => $entities) { echo "\n== " . $group . " ==\n"; foreach ($entities as $entity) { $name = $entity->getName(); echo str_pad($name . ":", 20); $value = isset($entity->{$property}) ? $entity->{$property} : ''; if ($property == "optional") { // meta definition if (is_array($value)) { $value = sprintf("[%s]", join(',', $value)); } printf("%s\n", $value); } else { // actual property if (in_array($property, $entity->required)) { $required = "required"; } elseif (in_array($property, $entity->optional)) { $required = "optional"; } else { $required = "not allowed"; } printf("%s\t%s\n", $required, $value); } } echo "\n"; } }
/** * @todo * @param string $capabilities * @param string $sub */ public function get($section = NULL) { $capabilities = array(); if (is_null($section) || $section == 'configuration') { $configuration = array('precision' => View\View::PRECISION, 'database' => Util\Configuration::read('db.driver'), 'debug' => Util\Configuration::read('debug'), 'devmode' => Util\Configuration::read('devmode')); if ($commit = Util\Debug::getCurrentCommit()) { $configuration['commit'] = $commit; } $capabilities['configuration'] = $configuration; } // db statistics - only if specifically requested if ($section == 'database') { $conn = $this->em->getConnection(); // get DBAL connection from EntityManager // estimate InnoDB tables to avoid performance penalty $rows = $conn->fetchAssoc('EXPLAIN SELECT COUNT(id) FROM data USE INDEX (PRIMARY)'); if (isset($rows['rows'])) { $rows = $rows['rows']; } else { // get correct values for MyISAM $rows = $conn->fetchColumn('SELECT COUNT(1) FROM data'); } // database disc space consumption $sql = 'SELECT SUM(data_length + index_length) ' . 'FROM information_schema.tables ' . 'WHERE table_schema = ?'; $size = $conn->fetchColumn($sql, array(Util\Configuration::read('db.dbname'))); $aggregation = Util\Configuration::read('aggregation'); $database = array('data_rows' => $rows, 'data_size' => $size, 'aggregation_enabled' => $aggregation ? 1 : 0); // aggregation table size if ($aggregation) { $agg_rows = $conn->fetchColumn('SELECT COUNT(1) FROM aggregate'); $database['aggregation_rows'] = $agg_rows; $database['aggregation_ratio'] = $agg_rows ? $rows / $agg_rows : 0; } $capabilities['database'] = $database; } if (is_null($section) || $section == 'formats') { $capabilities['formats'] = array_keys(Router::$viewMapping); } if (is_null($section) || $section == 'contexts') { $capabilities['contexts'] = array_keys(Router::$controllerMapping); } if (is_null($section) || $section == 'definitions') { // unresolved artifact from Symfony migration // if (!is_null($section)) { // only caching when we don't request dynamic informations // $this->view->setCaching('expires', time()+2*7*24*60*60); // cache for 2 weeks // } $capabilities['definitions']['entities'] = Definition\EntityDefinition::get(); $capabilities['definitions']['properties'] = Definition\PropertyDefinition::get(); } if (count($capabilities) == 0) { throw new \Exception('Invalid capability identifier: \'' . $section . '\''); } return array('capabilities' => $capabilities); }
public function getDefinition() { return Definition\EntityDefinition::get($this->type); }
/** * Core data aggregation wrapper * * @param string $uuid channel UUID * @param string $level aggregation level (e.g. 'day') * @param string $mode 'full' or 'delta' aggretation * @param int $period number of prior periods to aggregate in delta mode * @return int number of affected rows */ public function aggregate($uuid = null, $level = 'day', $mode = 'full', $period = null) { // validate settings if (!in_array($mode, array('full', 'delta'))) { throw new \RuntimeException('Unsupported aggregation mode ' . $mode); } if (!$this->isValidAggregationLevel($level)) { throw new \RuntimeException('Unsupported aggregation level ' . $level); } // get channel definition to select correct aggregation function $sqlParameters = array('channel'); $sql = 'SELECT id, uuid, type FROM entities WHERE class = ?'; if ($uuid) { $sqlParameters[] = $uuid; $sql .= ' AND uuid = ?'; } $rows = 0; // aggregate each channel foreach ($this->conn->fetchAll($sql, $sqlParameters) as $row) { $entity = Definition\EntityDefinition::get($row['type']); $interpreter = $entity->getInterpreter(); $rows += $this->aggregateChannel($row['id'], $interpreter, $mode, $level, $period); } return $rows; }
private function compressChannel($channel) { if (null == ($definition = Definition\EntityDefinition::get($channel['type']))) { trigger_error('Could not find definition for type ' . $channel['type'], E_USER_WARNING); return false; } // interpreter class - provides grouping function $interpreter = $definition->interpreter; // Detect compressscheme if (isset($this->config['compressscheme'][$channel['uuid']])) { $cs = $this->config['compressscheme'][$channel['uuid']]; } else { $cs = $this->config['compressscheme']['default']; } // Prepare compressscheme ksort($cs); $times = array_keys($cs); $times[] = 0; $timestamp = time(); // Local timestamp should be consistent during our transactions // Run compression passes for ($i = 0; $i < count($times) - 1; $i++) { if ($cs[$times[$i]] == 0) { continue; } // Step 1: Detect oldest and newest dataset $datatimes = $this->sql_query("SELECT MIN(timestamp) AS min, MAX(timestamp) AS max FROM data WHERE channel_id = ? AND timestamp <= ? AND timestamp > ?", array($channel['id'], ($timestamp - $times[$i]) * 1000, $times[$i + 1] > 0 ? ($timestamp - $times[$i + 1]) * 1000 : 0)); if ((double) $datatimes[0]['max'] == 0) { $this->out(' Skipping compression pass for data points between ' . $this->strftime($timestamp - $times[$i + 1]) . ' and ' . $this->strftime($timestamp - $times[$i]) . ' using a ' . $cs[$times[$i]] . ' seconds window: No data points found'); continue; } // Caching $from = (double) $datatimes[0]['min']; $lastrun = (double) $this->cache_read($channel['id'], $times[$i]); if ($lastrun && (double) $lastrun >= $from) { $this->out(' Skipping data points between ' . $this->strftime($from / 1000) . ' and ' . $this->strftime((double) $lastrun / 1000) . ' (Cached)'); (double) ($datatimes[0]['min'] = $lastrun); } $this->out(' Compressing data points between ' . $this->strftime($from / 1000) . ' and ' . $this->strftime((double) $datatimes[0]['max'] / 1000) . ' using a ' . $cs[$times[$i]] . ' seconds window'); // Step 2: Loop new possible timeframes $curtime = (double) $datatimes[0]['min']; $lastpurgecount = $this->purgecounter; $steps = ((double) $datatimes[0]['max'] / 1000 - $from / 1000) / $cs[$times[$i]]; if ($steps == 0) { continue; } $step = 0; $passstart = time(); do { // Step 2.1: Increase timestamps $lastcurtime = $curtime; $curtime += $cs[$times[$i]] * 1000; $step++; // Print status if ($this->config['verbose']) { $this->out(' Processing: ' . $this->strftime($lastcurtime / 1000) . ' - ' . $this->strftime($curtime / 1000) . ' (' . round(100 / $steps * $step) . '%)...', "\r"); } // Step 2.1: Get new Value for timeframe $newset = $this->sql_query("SELECT " . $interpreter::groupExprSQL("value") . " AS newval, COUNT(value) AS datapoints, MAX(id) AS updateid " . "FROM data WHERE channel_id = ? AND timestamp > ? AND timestamp <= ?", array($channel['id'], $lastcurtime, $curtime)); // Step 2.2: Skip if current timeframe has no or already just one datapoint if (count($newset) == 0 || $newset[0]['datapoints'] < 2) { continue; } // wrap inside transaction $this->conn->transactional(function () use($channel, $newset, $curtime, $lastcurtime) { // Step 2.3: Delete old data points $this->sql_exec('DELETE FROM data WHERE channel_id = ? AND timestamp > ? AND timestamp <= ? AND id != ?', array($channel['id'], $lastcurtime, $curtime, $newset[0]['updateid'])); $this->purgecounter += $newset[0]['datapoints'] - 1; // Step 2.4: Update oldest Datapoint // Note: Use UPDATE instead of INSERT to avoid filling up our id-pool $this->sql_exec('UPDATE data SET timestamp = ?, value = ? WHERE channel_id = ? AND id = ?', array($curtime - 1, $newset[0]['newval'], $channel['id'], $newset[0]['updateid'])); }); } while ($curtime <= (double) $datatimes[0]['max']); $this->out(' Removed ' . ($this->purgecounter - $lastpurgecount) . ' data points in ' . (time() - $passstart) . ' seconds.', "\r"); $this->cache_write($channel['id'], $times[$i], (double) $datatimes[0]['max']); } }
/** * @param string $section select specific sub section for output */ public function get($section = NULL) { $capabilities = array(); if (is_null($section) || $section == 'configuration') { $configuration = array('precision' => View\View::PRECISION, 'database' => Util\Configuration::read('db.driver'), 'debug' => Util\Configuration::read('debug'), 'devmode' => Util\Configuration::read('devmode')); if ($commit = Util\Debug::getCurrentCommit()) { $configuration['commit'] = $commit; } $capabilities['configuration'] = $configuration; } // db statistics - only if specifically requested if ($section == 'database') { $conn = $this->em->getConnection(); // get DBAL connection from EntityManager // estimate InnoDB tables to avoid performance penalty $rows = $this->sqlCount($conn, 'data'); $size = $this->dbSize($conn, 'data'); $aggregation = Util\Configuration::read('aggregation'); $database = array('data_rows' => $rows, 'data_size' => $size, 'aggregation_enabled' => $aggregation ? 1 : 0); // aggregation table size if ($aggregation) { $agg_rows = $this->sqlCount($conn, 'aggregate'); $agg_size = $this->dbSize($conn, 'aggregate'); $database['aggregation_rows'] = $agg_rows; $database['aggregation_size'] = $agg_size; $database['aggregation_ratio'] = $agg_rows ? $rows / $agg_rows : 0; } $capabilities['database'] = $database; } if (is_null($section) || $section == 'formats') { $capabilities['formats'] = array_keys(Router::$viewMapping); } if (is_null($section) || $section == 'contexts') { $capabilities['contexts'] = array_keys(Router::$controllerMapping); } if (is_null($section) || $section == 'definitions') { // unresolved artifact from Symfony migration if (!is_null($section)) { // only caching when we don't request dynamic informations $this->view->setCaching('expires', time() + 2 * 7 * 24 * 60 * 60); // cache for 2 weeks } $capabilities['definitions']['entities'] = Definition\EntityDefinition::get(); $capabilities['definitions']['properties'] = Definition\PropertyDefinition::get(); } if (count($capabilities) == 0) { throw new \Exception('Invalid capability identifier: \'' . $section . '\''); } return array('capabilities' => $capabilities); }