diff --git a/app/main/controller/ccp/universe.php b/app/main/controller/ccp/universe.php index c5f08128..aab4a4a3 100644 --- a/app/main/controller/ccp/universe.php +++ b/app/main/controller/ccp/universe.php @@ -144,12 +144,22 @@ class Universe extends Controller { * @var $system Model\Universe\SystemModel */ $system = Model\Universe\BasicUniverseModel::getNew('SystemModel'); + $indexData = []; foreach($systemIds as $systemId){ $system->getById($systemId); - $system->buildIndex(); - $system->reset(); + if($hashKeyId = $system->getHashKey()){ + $indexData[$hashKeyId] = $system->getData(); + } + // offset must increase otherwise we get a endless loop + // -> see /setup ajax build loop function $offset++; } + + $this->getF3()->mset($indexData, '', $system::CACHE_INDEX_EXPIRE_KEY); + + // ... add hashKeys for all table rows to tableIndex as well + $system::buildTableIndex($system, array_keys($indexData)); + return ['countAll' => $systemsAll, 'countBuild' => count($systemIds), 'offset' => $offset]; } @@ -179,15 +189,16 @@ class Universe extends Controller { /** * get complete system index (all systems) + * @param bool $all * @return array */ - public function getSystemsIndex() : array { + public function getSystemsIndex(bool $all = false) : array { $index = []; $cacheKeyTable = Model\Universe\BasicUniverseModel::generateHashKeyTable('system'); if($this->getF3()->exists($cacheKeyTable,$cacheKeys)){ foreach((array)$cacheKeys as $cacheKeyRow){ if(($data = $this->get($cacheKeyRow)) && is_object($data)){ - $index[$data->id] = $data; + $index[] = $all ? $data : $data->id; } } } diff --git a/app/main/controller/setup.php b/app/main/controller/setup.php index db954059..adbd890e 100644 --- a/app/main/controller/setup.php +++ b/app/main/controller/setup.php @@ -166,13 +166,7 @@ class Setup extends Controller { $f3->set('tplJsView', 'setup'); // set render functions (called within template) - $f3->set('cacheType', function(){ - $cacheType = $this->getF3()->get('CACHE'); - if( strpos($cacheType, 'redis') !== false ){ - $cacheType = 'redis'; - } - return $cacheType; - }); + $f3->set('cacheType', $this->getCacheType($f3)); // simple counter (called within template) $counter = 0; @@ -188,6 +182,19 @@ class Setup extends Controller { echo \Template::instance()->render( Config::getPathfinderData('view.index') ); } + /** + * get Cache backend type for F3 + * @param \Base $f3 + * @return string + */ + protected function getCacheType(\Base &$f3) : string { + $cacheType = $f3->get('CACHE'); + if(strpos($cacheType, 'redis') !== false){ + $cacheType = 'redis'; + } + return $cacheType; + } + /** * main setup route handler * works as dispatcher for setup functions @@ -255,6 +262,9 @@ class Setup extends Controller { // set cache size $f3->set('cacheSize', $this->getCacheData($f3)); + + // set Redis config check information + $f3->set('checkRedisConfig', $this->checkRedisConfig($f3)); } /** @@ -337,8 +347,8 @@ class Setup extends Controller { 'value' => $f3->get('PORT') ], 'protocol' => [ - 'label' => 'Protocol', - 'value' => strtoupper( $f3->get('SCHEME') ) + 'label' => 'Protocol - scheme', + 'value' => $f3->get('SERVER.SERVER_PROTOCOL') . ' - ' . $f3->get('SCHEME') ] ]; @@ -431,11 +441,8 @@ class Setup extends Controller { 'version' => (extension_loaded('curl') && function_exists('curl_version')) ? 'installed' : 'missing', 'check' => (extension_loaded('curl') && function_exists('curl_version')) ], - [ - 'label' => 'Redis Server [optional]' - ], 'ext_redis' => [ - 'label' => 'Redis', + 'label' => 'Redis [optional]', 'required' => $f3->get('REQUIREMENTS.PHP.REDIS'), 'version' => extension_loaded('redis') ? phpversion('redis') : 'missing', 'check' => version_compare( phpversion('redis'), $f3->get('REQUIREMENTS.PHP.REDIS'), '>='), @@ -593,6 +600,81 @@ class Setup extends Controller { return $phpConfig; } + /** + * check Redis (cache) config + * -> only visible if Redis is used as Cache backend + * @param \Base $f3 + * @return array + */ + protected function checkRedisConfig(\Base $f3): array { + $redisConfig = []; + if($this->getCacheType($f3) === 'redis'){ + // we need to access the "protected" member $ref from F3´s Cache class + // to get access to the underlying Redis() class + $ref = new \ReflectionObject($cache = \Cache::instance()); + $prop = $ref->getProperty('ref'); + $prop->setAccessible(true); + /** + * @var $redis \Redis + */ + $redis = $prop->getValue($cache); + + $redisServerInfo = (array)$redis->info('SERVER'); + $redisMemoryInfo = (array)$redis->info('MEMORY'); + $redisStatsInfo = (array)$redis->info('STATS'); + + $redisConfig = [ + 'redisVersion' => [ + 'label' => 'redis_version', + 'required' => number_format((float)$f3->get('REQUIREMENTS.REDIS.VERSION'), 1, '.', ''), + 'version' => $redisServerInfo['redis_version'], + 'check' => version_compare( $redisServerInfo['redis_version'], $f3->get('REQUIREMENTS.REDIS.VERSION'), '>='), + 'tooltip' => 'Redis server version' + ], + 'maxMemory' => [ + 'label' => 'maxmemory', + 'required' => $this->convertBytes($f3->get('REQUIREMENTS.REDIS.MAX_MEMORY')), + 'version' => $this->convertBytes($redisMemoryInfo['maxmemory']), + 'check' => $redisMemoryInfo['maxmemory'] >= $f3->get('REQUIREMENTS.REDIS.MAX_MEMORY'), + 'tooltip' => 'Max memory limit for Redis' + ], + 'usedMemory' => [ + 'label' => 'used_memory', + 'version' => $this->convertBytes($redisMemoryInfo['used_memory']), + 'check' => $redisMemoryInfo['used_memory'] < $redisMemoryInfo['maxmemory'], + 'tooltip' => 'Current memory used by Redis' + ], + 'usedMemoryPeak' => [ + 'label' => 'used_memory_peak', + 'version' => $this->convertBytes($redisMemoryInfo['used_memory_peak']), + 'check' => $redisMemoryInfo['used_memory_peak'] <= $redisMemoryInfo['maxmemory'], + 'tooltip' => 'Peak memory used by Redis' + ], + 'maxmemoryPolicy' => [ + 'label' => 'maxmemory_policy', + 'required' => $f3->get('REQUIREMENTS.REDIS.MAXMEMORY_POLICY'), + 'version' => $redisMemoryInfo['maxmemory_policy'], + 'check' => $redisMemoryInfo['maxmemory_policy'] == $f3->get('REQUIREMENTS.REDIS.MAXMEMORY_POLICY'), + 'tooltip' => 'How Redis behaves if \'maxmemory\' limit reached' + ], + 'evictedKeys' => [ + 'label' => 'evicted_keys', + 'version' => $redisStatsInfo['evicted_keys'], + 'check' => !(bool)$redisStatsInfo['evicted_keys'], + 'tooltip' => 'Number of evicted keys due to maxmemory limit' + ], + 'dbSize' . $redis->getDbNum() => [ + 'label' => 'Size DB (' . $redis->getDbNum() . ')', + 'version' => $redis->dbSize(), + 'check' => $redis->dbSize() > 0, + 'tooltip' => 'Keys found in DB (' . $redis->getDbNum() . ') [Cache DB]' + ] + ]; + } + + return $redisConfig; + } + /** * check system environment vars * -> mostly relevant for development/build/deployment @@ -1419,8 +1501,8 @@ class Setup extends Controller { $result = '0'; if($bytes){ $base = log($bytes, 1024); - $suffixes = array('', 'KB', 'MB', 'GB', 'TB'); - $result = round(pow(1024, $base - floor($base)), $precision) .' '. $suffixes[floor($base)]; + $suffixes = array('', 'KB', 'M', 'GB', 'TB'); + $result = round(pow(1024, $base - floor($base)), $precision) .''. $suffixes[floor($base)]; } return $result; } diff --git a/app/main/model/universe/basicuniversemodel.php b/app/main/model/universe/basicuniversemodel.php index fe27aa16..7fa78bf7 100644 --- a/app/main/model/universe/basicuniversemodel.php +++ b/app/main/model/universe/basicuniversemodel.php @@ -100,28 +100,32 @@ abstract class BasicUniverseModel extends BasicModel { */ public function buildIndex(){ $data = null; - if($hashKeyId = $this->getHashKey()){ - $hashKeyTable = self::generateHashKeyTable($this->getTable()); - - if( !self::existsCacheValue($hashKeyTable, $cachedData) ){ - $cachedData = []; - } - - if( !in_array($hashKeyId, $cachedData) ){ - $cachedData[] = $hashKeyId; - } - $data = $this->getData(); + $this->getF3()->set($hashKeyId, $data, self::CACHE_INDEX_EXPIRE_KEY); - // straight into cache (no $f->set() ), no sync with hive here -> save ram - self::setCacheValue($hashKeyId, $data, self::CACHE_INDEX_EXPIRE_KEY); - self::setCacheValue($hashKeyTable, $cachedData, self::CACHE_INDEX_EXPIRE_KEY); + // ... add hashKey for this rows to tableIndex as well + self::buildTableIndex($this, [$hashKeyId]); } return $data; } + /** + * add $rowKeys (hashKeys) to a search index that holds all rowKeys of a table + * @param BasicUniverseModel $model + * @param array $rowKeys + */ + public static function buildTableIndex(BasicUniverseModel $model, array $rowKeys = []){ + $hashKeyTable = self::generateHashKeyTable($model->getTable()); + if( !self::getF3()->exists($hashKeyTable, $cachedData) ){ + $cachedData = []; + } + $cachedData = array_unique(array_merge($cachedData, $rowKeys)); + + self::getF3()->set($hashKeyTable, $cachedData, self::CACHE_INDEX_EXPIRE_KEY); + } + /** * get data from "search" index for this model * -> if data not found -> try to build up index for this model diff --git a/app/requirements.ini b/app/requirements.ini index fec3a4f0..4f7d4b7e 100644 --- a/app/requirements.ini +++ b/app/requirements.ini @@ -9,7 +9,6 @@ APACHE.VERSION = 2.5 NGINX.VERSION = 1.9 [REQUIREMENTS.PHP] -; recommended is >= 5.6 VERSION = 7.0 ; 64-bit version of PHP (4 = 32-bit, 8 = 64-bit) @@ -50,7 +49,6 @@ MAX_INPUT_VARS = 3000 HTML_ERRORS = 0 [REQUIREMENTS.LIBS] - ZMQ = 4.1.3 [REQUIREMENTS.MYSQL] @@ -72,6 +70,14 @@ COLLATION_DATABASE = utf8_general_ci COLLATION_CONNECTION = utf8_general_ci FOREIGN_KEY_CHECKS = ON +[REQUIREMENTS.REDIS] +VERSION = 3.0 +; max memory limit (Bytes) "binary" (default: 128M) +MAX_MEMORY = 134217728 +; how Redis behaves if "maxmemory" limit reached +; https://redis.io/topics/lru-cache +MAXMEMORY_POLICY = allkeys-lru + [REQUIREMENTS.PATH] NODE = 6.0 NPM = 3.10.0 diff --git a/public/templates/view/setup.html b/public/templates/view/setup.html index 1e5e1f37..15de5260 100644 --- a/public/templates/view/setup.html +++ b/public/templates/view/setup.html @@ -142,10 +142,8 @@