Skip to content

Commit

Permalink
#940 TApplicationComponent::getClassFxEvents update and TDBCache::set…
Browse files Browse the repository at this point in the history
…Value uses atomic SQL (#952)

* #940 TApplicationComponent::getClassFxEvents

This is a better implementation of getClassFXEvents.  it shaves a few milliseconds from the testing time.  woot.

* #940 TDBCache::setValue uses Atomic SQL "INSERT... ON DUPLICATE"

* TDBCache::setValue uses "REPLACE" rather than "INSERT INTO  ON DUPLICATE KEY UPDATE"

* shortened the sql

* TDBCache::setValue selects on database type for SQL, fallback to transaction delete/add

And corrected a "/" into "DIRECTORY_SEPARATOR" in TApplicationStatePersister

* TApplicationComponent::getClassFxEvents uses runtime file cache

Rather than waiting for TDBCache module to load, this uses a runtime file cache to store the fxEvents.

* remove testing

* getClassFXEvents doesn't cache in Debug Mode

* removed cleanup that doesn't need to happen for Debug mode

* no change to the ticket 589test
  • Loading branch information
belisoful authored May 17, 2023
1 parent 94ecb99 commit a833148
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 23 deletions.
53 changes: 51 additions & 2 deletions framework/Caching/TDbCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -492,8 +492,57 @@ protected function getValue($key)
*/
protected function setValue($key, $value, $expire)
{
$this->deleteValue($key);
return $this->addValue($key, $value, $expire);
if (!$this->_cacheInitialized) {
$this->initializeCache();
}
$db = $this->getDbConnection();
$driver = $db->getDriverName();
if (in_array($driver, ['mysql', 'mysqli', 'sqlite', 'ibm', 'oci', 'sqlsrv', 'mssql', 'dblib', 'pgsql'])) {
$expire = ($expire <= 0) ? 0 : time() + $expire;
if (in_array($driver, ['mysql', 'mysqli', 'sqlite'])) {
$sql = "REPLACE INTO {$this->_cacheTable} (itemkey,value,expire) VALUES (:key,:value,$expire)";
} elseif ($driver === 'pgsql') {
$sql = "INSERT INTO {$this->_cacheTable} (itemkey, value, expire) VALUES (:key, :value, :expire) " .
"ON CONFLICT (itemkey) DO UPDATE SET value = EXCLUDED.value, expire = EXCLUDED.expire";
} else {
$sql = "MERGE INTO {$this->_cacheTable} AS c " .
"USING (SELECT :key AS itemkey, :value AS value, $expire AS expire) AS data " .
"ON c.itemkey = data.itemkey " .
"WHEN MATCHED THEN " .
"UPDATE SET c.value = data.value, c.expire = data.expire " .
"WHEN NOT MATCHED THEN " .
"INSERT (itemkey, value, expire) " .
"VALUES (data.itemkey, data.value, data.expire)";
}
$command = $db->createCommand($sql);
$command->bindValue(':key', $key, \PDO::PARAM_STR);
$command->bindValue(':value', serialize($value), \PDO::PARAM_LOB);

try {
$command->execute();
return true;
} catch (\Exception $e) {
try {
$this->initializeCache(true);
$command->execute();
return true;
} catch (\Exception $e) {
return false;
}
}
} else {
$isCurrentTransaction = $this->getDbConnection()->getCurrentTransaction();
$transaction = $this->getDbConnection()->getCurrentTransaction() ?? $this->getDbConnection()->beginTransaction();

$this->deleteValue($key);
$return = $this->addValue($key, $value, $expire);

if (!$isCurrentTransaction) {
$transaction->commit();
}

return $return;
}
}

/**
Expand Down
53 changes: 33 additions & 20 deletions framework/TApplicationComponent.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
*/
class TApplicationComponent extends \Prado\TComponent
{
public const APP_COMPONENT_FX_CACHE = 'prado:applicationcomponent:fxcache';
public const FX_CACHE_FILE = 'fxevent.cache';
/**
* TApplicationComponents auto listen to global events.
*
Expand All @@ -46,34 +46,47 @@ public function getAutoGlobalListen()

/**
* This caches the 'fx' events for PRADO classes in the application cache
* @param object $class
* @param object $class The object to get the 'fx' events.
* @return string[] fx events from a specific class
*/
protected function getClassFxEvents($class)
{
static $_classfx = null;
static $_classfx = [];
static $_classfxSize = 0;
static $_loaded = false;

$app = $this->getApplication();
$mode = $className = $cache = null;
if ($app && (($mode = $app->getMode()) === TApplicationMode::Normal || $mode === TApplicationMode::Performance) && ($cache = $app->getCache())) {
if ($_classfx === null) {
$_classfx = $cache->get(self::APP_COMPONENT_FX_CACHE) ?? [];
}
$className = $class::class;
if (isset($_classfx[$className])) {
return $_classfx[$className];
$cacheFile = $mode = null;
if ($app) {
$cacheFile = $app->getRuntimePath() . DIRECTORY_SEPARATOR . self::FX_CACHE_FILE;
if((($mode = $app->getMode()) === TApplicationMode::Normal || $mode === TApplicationMode::Performance) && !$_loaded) {
$_loaded = true;
if (($content = @file_get_contents($cacheFile)) !== false) {
$_classfx = @unserialize($content) ?? [];
$_classfxSize = count($_classfx);
}
}
}
$className = $class::class;
if (array_key_exists($className, $_classfx)) {
return $_classfx[$className];
}
$fx = parent::getClassFxEvents($class);
if ($cache) {
if ($pos = strrpos($className, '\\')) {
$baseClassName = substr($className, $pos + 1);
} else {
$baseClassName = $className;
}
if ($mode === TApplicationMode::Performance || isset(Prado::$classMap[$baseClassName])) {
$_classfx[$className] = $fx;
$cache->set(self::APP_COMPONENT_FX_CACHE, $_classfx);
$_classfx[$className] = $fx;
if ($cacheFile) {
if ($mode === TApplicationMode::Performance) {
file_put_contents($cacheFile, serialize($_classfx), LOCK_EX);
} elseif ($mode === TApplicationMode::Normal) {
static $_flipClassMap = null;

if ($_flipClassMap === null) {
$_flipClassMap = array_flip(Prado::$classMap);
}
$classData = array_intersect_key($_classfx, $_flipClassMap);
if (($c = count($classData)) > $_classfxSize) {
$_classfxSize = $c;
file_put_contents($cacheFile, serialize($_classfx), LOCK_EX);
}
}
}
return $fx;
Expand Down
2 changes: 1 addition & 1 deletion framework/TApplicationStatePersister.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public function init($config)
*/
protected function getStateFilePath()
{
return $this->getApplication()->getRuntimePath() . '/global.cache';
return $this->getApplication()->getRuntimePath() . DIRECTORY_SEPARATOR . 'global.cache';
}

/**
Expand Down

0 comments on commit a833148

Please sign in to comment.