summaryrefslogtreecommitdiffstats
path: root/library/Director/Db/Cache
diff options
context:
space:
mode:
Diffstat (limited to 'library/Director/Db/Cache')
-rw-r--r--library/Director/Db/Cache/CustomVariableCache.php84
-rw-r--r--library/Director/Db/Cache/GroupMembershipCache.php104
-rw-r--r--library/Director/Db/Cache/PrefetchCache.php166
3 files changed, 354 insertions, 0 deletions
diff --git a/library/Director/Db/Cache/CustomVariableCache.php b/library/Director/Db/Cache/CustomVariableCache.php
new file mode 100644
index 0000000..243ecae
--- /dev/null
+++ b/library/Director/Db/Cache/CustomVariableCache.php
@@ -0,0 +1,84 @@
+<?php
+
+namespace Icinga\Module\Director\Db\Cache;
+
+use Icinga\Application\Benchmark;
+use Icinga\Module\Director\CustomVariable\CustomVariables;
+use Icinga\Module\Director\Db;
+use Icinga\Module\Director\Objects\IcingaObject;
+
+class CustomVariableCache
+{
+ protected $type;
+
+ protected $rowsById = array();
+
+ protected $varsById = array();
+
+ public function __construct(IcingaObject $object)
+ {
+ Benchmark::measure('Initializing CustomVariableCache');
+ $connection = $object->getConnection();
+ $db = $connection->getDbAdapter();
+
+ $columns = array(
+ 'id' => sprintf('v.%s', $object->getVarsIdColumn()),
+ 'varname' => 'v.varname',
+ 'varvalue' => 'v.varvalue',
+ 'format' => 'v.format',
+ 'checksum' => '(NULL)',
+ );
+
+ if ($connection->isPgsql()) {
+ if ($connection->hasPgExtension('pgcrypto')) {
+ $columns['checksum'] = "DIGEST(v.varvalue || ';' || v.format, 'sha1')";
+ }
+ } else {
+ $columns['checksum'] = "UNHEX(SHA1(v.varvalue || ';' || v.format))";
+ }
+
+ $query = $db->select()->from(
+ array('v' => $object->getVarsTableName()),
+ $columns
+ );
+
+ foreach ($db->fetchAll($query) as $row) {
+ $id = $row->id;
+ unset($row->id);
+
+ if (is_resource($row->checksum)) {
+ $row->checksum = stream_get_contents($row->checksum);
+ }
+
+ if (array_key_exists($id, $this->rowsById)) {
+ $this->rowsById[$id][] = $row;
+ } else {
+ $this->rowsById[$id] = array($row);
+ }
+ }
+
+ Benchmark::measure('Filled CustomVariableCache');
+ }
+
+ public function getVarsForObject(IcingaObject $object)
+ {
+ $id = $object->id;
+
+ if (array_key_exists($id, $this->rowsById)) {
+ if (! array_key_exists($id, $this->varsById)) {
+ $this->varsById[$id] = CustomVariables::forStoredRows(
+ $this->rowsById[$id]
+ );
+ }
+
+ return $this->varsById[$id];
+ } else {
+ return new CustomVariables();
+ }
+ }
+
+ public function __destruct()
+ {
+ unset($this->db);
+ }
+}
diff --git a/library/Director/Db/Cache/GroupMembershipCache.php b/library/Director/Db/Cache/GroupMembershipCache.php
new file mode 100644
index 0000000..d6d9e8b
--- /dev/null
+++ b/library/Director/Db/Cache/GroupMembershipCache.php
@@ -0,0 +1,104 @@
+<?php
+
+namespace Icinga\Module\Director\Db\Cache;
+
+use Icinga\Application\Benchmark;
+use Icinga\Module\Director\Db;
+use Icinga\Module\Director\Objects\IcingaObject;
+
+class GroupMembershipCache
+{
+ protected $type;
+
+ protected $table;
+
+ protected $groupClass;
+
+ protected $memberships;
+
+ /** @var Db Director database connection */
+ protected $connection;
+
+ public function __construct(IcingaObject $object)
+ {
+ $this->table = $object->getTableName();
+ $this->type = $object->getShortTableName();
+
+ $this->groupClass = 'Icinga\\Module\\Director\\Objects\\Icinga'
+ . ucfirst($this->type) . 'Group';
+
+ Benchmark::measure('Initializing GroupMemberShipCache');
+ $this->connection = $object->getConnection();
+ $this->loadAllMemberships();
+ Benchmark::measure('Filled GroupMemberShipCache');
+ }
+
+ protected function loadAllMemberships()
+ {
+ $db = $this->connection->getDbAdapter();
+ $this->memberships = array();
+
+ $type = $this->type;
+ $table = $this->table;
+
+ $query = $db->select()->from(
+ array('o' => $table),
+ array(
+ 'object_id' => 'o.id',
+ 'group_id' => 'g.id',
+ 'group_name' => 'g.object_name',
+ )
+ )->join(
+ array('go' => $table . 'group_' . $type),
+ 'o.id = go.' . $type . '_id',
+ array()
+ )->join(
+ array('g' => $table . 'group'),
+ 'go.' . $type . 'group_id = g.id',
+ array()
+ )->order('g.object_name');
+
+ foreach ($db->fetchAll($query) as $row) {
+ if (! array_key_exists($row->object_id, $this->memberships)) {
+ $this->memberships[$row->object_id] = array();
+ }
+
+ $this->memberships[$row->object_id][$row->group_id] = $row->group_name;
+ }
+ }
+
+ public function listGroupNamesForObject(IcingaObject $object)
+ {
+ if (array_key_exists($object->id, $this->memberships)) {
+ return array_values($this->memberships[$object->id]);
+ }
+
+ return array();
+ }
+
+ public function listGroupIdsForObject(IcingaObject $object)
+ {
+ if (array_key_exists($object->id, $this->memberships)) {
+ return array_keys($this->memberships[$object->id]);
+ }
+
+ return array();
+ }
+
+ public function getGroupsForObject(IcingaObject $object)
+ {
+ $groups = array();
+ $class = $this->groupClass;
+ foreach ($this->listGroupIdsForObject($object) as $id) {
+ $object = $class::loadWithAutoIncId($id, $this->connection);
+ $groups[$object->object_name] = $object;
+ }
+
+ return $groups;
+ }
+
+ public function __destruct()
+ {
+ unset($this->connection);
+ }
+}
diff --git a/library/Director/Db/Cache/PrefetchCache.php b/library/Director/Db/Cache/PrefetchCache.php
new file mode 100644
index 0000000..aa9f950
--- /dev/null
+++ b/library/Director/Db/Cache/PrefetchCache.php
@@ -0,0 +1,166 @@
+<?php
+
+namespace Icinga\Module\Director\Db\Cache;
+
+use Icinga\Module\Director\CustomVariable\CustomVariable;
+use Icinga\Module\Director\Data\Db\DbObject;
+use Icinga\Module\Director\Db;
+use Icinga\Module\Director\Objects\IcingaObject;
+use Icinga\Module\Director\Resolver\HostServiceBlacklist;
+use Icinga\Module\Director\Resolver\TemplateTree;
+use LogicException;
+
+/**
+ * Central prefetch cache
+ *
+ * Might be improved, accept various caches based on an interface and then
+ * finally replace prefetch logic in DbObject itself. This would also allow
+ * to get rid of IcingaObject-related code in this place
+ */
+class PrefetchCache
+{
+ protected $db;
+
+ protected static $instance;
+
+ protected $varsCaches = array();
+
+ protected $groupsCaches = array();
+
+ protected $templateResolvers = array();
+
+ protected $renderedVars = array();
+
+ protected $templateTrees = array();
+
+ protected $hostServiceBlacklist;
+
+ public static function initialize(Db $db)
+ {
+ self::forget();
+ self::$instance = new static($db);
+ }
+
+ protected function __construct(Db $db)
+ {
+ $this->db = $db;
+ }
+
+ /**
+ * @throws LogicException
+ *
+ * @return self
+ */
+ public static function instance()
+ {
+ if (static::$instance === null) {
+ throw new LogicException('Prefetch cache has not been loaded');
+ }
+
+ return static::$instance;
+ }
+
+ public static function forget()
+ {
+ DbObject::clearAllPrefetchCaches();
+ self::$instance = null;
+ }
+
+ public static function shouldBeUsed()
+ {
+ return self::$instance !== null;
+ }
+
+ public function vars(IcingaObject $object)
+ {
+ return $this->varsCache($object)->getVarsForObject($object);
+ }
+
+ public function groups(IcingaObject $object)
+ {
+ return $this->groupsCache($object)->getGroupsForObject($object);
+ }
+
+ /* Hint: not implemented, this happens in DbObject right now
+ public function byObjectType($type)
+ {
+ if (! array_key_exists($type, $this->caches)) {
+ $this->caches[$type] = new ObjectCache($type);
+ }
+
+ return $this->caches[$type];
+ }
+ */
+
+ public function renderVar(CustomVariable $var, $renderExpressions = false)
+ {
+ $checksum = $var->getChecksum();
+ if (null === $checksum) {
+ return $var->toConfigString($renderExpressions);
+ } else {
+ $checksum .= (int) $renderExpressions;
+ if (! array_key_exists($checksum, $this->renderedVars)) {
+ $this->renderedVars[$checksum] = $var->toConfigString($renderExpressions);
+ }
+
+ return $this->renderedVars[$checksum];
+ }
+ }
+
+ public function hostServiceBlacklist()
+ {
+ if ($this->hostServiceBlacklist === null) {
+ $this->hostServiceBlacklist = new HostServiceBlacklist($this->db);
+ $this->hostServiceBlacklist->preloadMappings();
+ }
+
+ return $this->hostServiceBlacklist;
+ }
+
+ /**
+ * @param IcingaObject $object
+ * @return CustomVariableCache
+ */
+ protected function varsCache(IcingaObject $object)
+ {
+ $key = $object->getShortTableName();
+
+ if (! array_key_exists($key, $this->varsCaches)) {
+ $this->varsCaches[$key] = new CustomVariableCache($object);
+ }
+
+ return $this->varsCaches[$key];
+ }
+
+ protected function groupsCache(IcingaObject $object)
+ {
+ $key = $object->getShortTableName();
+
+ if (! array_key_exists($key, $this->groupsCaches)) {
+ $this->groupsCaches[$key] = new GroupMembershipCache($object);
+ }
+
+ return $this->groupsCaches[$key];
+ }
+
+ protected function templateTree(IcingaObject $object)
+ {
+ $key = $object->getShortTableName();
+ if (! array_key_exists($key, $this->templateTrees)) {
+ $this->templateTrees[$key] = new TemplateTree(
+ $key,
+ $object->getConnection()
+ );
+ }
+
+ return $this->templateTrees[$key];
+ }
+
+ public function __destruct()
+ {
+ unset($this->groupsCaches);
+ unset($this->varsCaches);
+ unset($this->templateResolvers);
+ unset($this->renderedVars);
+ }
+}