Index: t3lib/config_default.php =================================================================== --- t3lib/config_default.php (Revision 4168) +++ t3lib/config_default.php (Revision 4291) @@ -101,7 +101,7 @@ 'reverseProxySSL' => '', // String: '*' or list of IP addresses of proxies that use SSL (https) for the connection to the client, but an unencrypted connection (http) to the server. If '*' all proxies defined in SYS[reverseProxyIP] use SSL. 'reverseProxyPrefixSSL' => '', // String: prefix to be added to the internal URL (SCRIPT_NAME and REQUEST_URI) when accessing the server via an SSL proxy. This setting overrides SYS[reverseProxyPrefix]. 'caching' => array( - 'caches' => array( + 'cacheFrontends' => array( 't3lib_cache_VariableCache' => 't3lib/cache/class.t3lib_cache_variablecache.php:t3lib_cache_VariableCache' ), 'cacheBackends' => array( @@ -110,6 +110,38 @@ 't3lib_cache_backend_Globals' => 't3lib/cache/backend/class.t3lib_cache_backend_globals.php:t3lib_cache_backend_Globals', 't3lib_cache_backend_Memcached' => 't3lib/cache/backend/class.t3lib_cache_backend_memcached.php:t3lib_cache_backend_Memcached', 't3lib_cache_backend_Null' => 't3lib/cache/backend/class.t3lib_cache_backend_null.php:t3lib_cache_backend_Null' + ), + 'cacheBackendAssignments' => array( + 'cache_hash' => array( + 'backend' => 't3lib_cache_backend_Db', + 'options' => array( + 'cacheTable' => 'cache_hash' + ) + ), + 'cache_pages' => array( + 'backend' => 't3lib_cache_backend_Db', + 'options' => array( + 'cacheTable' => 'cache_pages' + ) + ), + 'cache_pagesection' => array( + 'backend' => 't3lib_cache_backend_Db', + 'options' => array( + 'cacheTable' => 'cache_pagesection' + ) + ) + /* + For memcached, use: + ============= + 'cache_pages' => array( + 'backend' => 't3lib_cache_backend_Memcached', + 'options' => array( + 'servers' => array('localhost:11211', 'otherhost:11211', 'thirdhost:11211'), // port is mandatory! + ) + ), + ============= + You need to have memcached installed as a daemon and also as a PHP extension! + */ ) ) ), @@ -263,7 +295,6 @@ 'pageOverlayFields' => 'uid,title,subtitle,nav_title,media,keywords,description,abstract,author,author_email', // List of fields from the table "pages_language_overlay" which should be overlaid on page records. See t3lib_page::getPageOverlay() 'hidePagesIfNotTranslatedByDefault' => FALSE, // If TRUE, pages that has no translation will be hidden by default. Basically this will inverse the effect of the page localization setting "Hide page if no translation for current language exists" to "Show page even if no translation exists" 'eID_include' => array(), // Array of key/value pairs where key is "tx_[ext]_[optional suffix]" and value is relative filename of class to include. Key is used as "?eID=" for index_ts.php to include the code file which renders the page from that point. (Useful for functionality that requires a low initialization footprint, eg. frontend ajax applications) - 'pageCacheToExternalFiles' => FALSE, // If set, page cache entries will be stored in typo3temp/cache_pages/ab/ instead of the database. Still, "cache_pages" will be filled in database but the "HTML" field will be empty. When the cache is flushed the files in cache_pages/ab/ will not be flush - you will have to garbage clean manually once in a while. 'disableNoCacheParameter' => false, // Boolean. If set, the no_cache request parameter will become ineffective. This is currently still an experimental feature and will require a website only with plugins that don't use this parameter. However, using "&no_cache=1" should be avoided anyway because there are better ways to disable caching for a certain part of the website (see COA_INT/USER_INT documentation in TSref). 'workspacePreviewLogoutTemplate' => '', // If set, points to an HTML file relative to the TYPO3_site root which will be read and outputted as template for this message. Example: fileadmin/templates/template_workspace_preview_logout.html. Inside you can put the marker %1$s to insert the URL to go back to. Use this in Go back... links 'XCLASS' => Array(), // See 'Inside TYPO3' document for more information. Index: t3lib/stddb/tables.sql =================================================================== --- t3lib/stddb/tables.sql (Revision 4168) +++ t3lib/stddb/tables.sql (Revision 4291) @@ -122,11 +122,14 @@ # Table structure for table 'cache_hash' # CREATE TABLE cache_hash ( - hash varchar(32) DEFAULT '' NOT NULL, - content mediumblob, - tstamp int(11) unsigned DEFAULT '0' NOT NULL, - ident varchar(20) DEFAULT '' NOT NULL, - PRIMARY KEY (hash) + id int(11) unsigned NOT NULL auto_increment, + identifier varchar(32) DEFAULT '' NOT NULL, + crdate int(11) unsigned DEFAULT '0' NOT NULL, + content mediumtext, + tags mediumtext, + lifetime int(11) unsigned DEFAULT '0' NOT NULL, + PRIMARY KEY (id), + KEY cache_id (identifier) ) ENGINE=InnoDB; # Index: t3lib/cache/class.t3lib_cache_abstractcache.php =================================================================== --- t3lib/cache/class.t3lib_cache_abstractcache.php (Revision 4168) +++ t3lib/cache/class.t3lib_cache_abstractcache.php (Revision 4291) @@ -93,7 +93,7 @@ * @return void * @author Robert Lemke */ - abstract public function save($entryIdentifier, $data, array $tags = array()); + abstract public function save($entryIdentifier, $data, array $tags = array(), $lifetime = null); /** * Loads data from the cache. @@ -129,10 +129,22 @@ * The asterisk ("*") is allowed as a wildcard at the beginning and the end of * a tag. * + * @param string The tag to search for, the "*" wildcard is supported + * @return array An array with identifiers of all matching entries. An empty array if no entries matched + */ + public function findEntriesByTag($tag) { + return $this->backend->findEntriesByTag($tag); + } + + /** + * Finds and returns all cache entry identifiers which are tagged by the specified tags. + * The asterisk ("*") is allowed as a wildcard at the beginning and the end of + * a tag. + * * @param array Array of tags to search for, the "*" wildcard is supported * @return array An array with identifiers of all matching entries. An empty array if no entries matched */ - public function findEntriesByTag(array $tags) { + public function findEntriesByTags(array $tags) { return $this->backend->findEntriesByTags($tags); } @@ -175,6 +187,16 @@ $this->backend->flushByTag($tag); } + /** + * Removes all cache entries of this cache which are tagged by the specified tag. + * + * @param array Array of tags to search for and to remove the cache entries, the "*" wildcard is supported + * @return void + * @author Ingo Renner + */ + public function flushByTags(array $tags) { + $this->backend->flushByTags($tags); + } } Index: t3lib/cache/class.t3lib_cache_factory.php =================================================================== --- t3lib/cache/class.t3lib_cache_factory.php (Revision 4168) +++ t3lib/cache/class.t3lib_cache_factory.php (Revision 4291) @@ -88,11 +88,10 @@ ); } - // loading the cache frontend file and class list($cacheFile, $cacheClassReference) = explode( ':', - $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['caches'][$cacheName] + $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheFrontends'][$cacheName] ); $cacheRequireFile = t3lib_div::getFileAbsFileName($cacheFile); Index: t3lib/cache/class.t3lib_cache_variablecache.php =================================================================== --- t3lib/cache/class.t3lib_cache_variablecache.php (Revision 4168) +++ t3lib/cache/class.t3lib_cache_variablecache.php (Revision 4291) @@ -44,8 +44,8 @@ * @return void * @author Robert Lemke */ - public function save($entryIdentifier, $variable, array $tags = array()) { - $this->backend->save($entryIdentifier, serialize($variable), $tags); + public function save($entryIdentifier, $variable, array $tags = array(), $lifetime = null) { + $this->backend->save($entryIdentifier, serialize($variable), $tags, $lifetime); } /** Index: t3lib/cache/class.t3lib_cache_abstractbackend.php =================================================================== --- t3lib/cache/class.t3lib_cache_abstractbackend.php (Revision 4168) +++ t3lib/cache/class.t3lib_cache_abstractbackend.php (Revision 4291) @@ -137,6 +137,14 @@ abstract public function flushByTag($tag); /** + * Removes all cache entries of this cache which are tagged by the specified tags. + * + * @param array The tags the entries must have + * @return void + */ + abstract public function flushByTags(array $tags); + + /** * Finds and returns all cache entry identifiers which are tagged by the specified tag. * The asterisk ("*") is allowed as a wildcard at the beginning and the end of * the tag. Index: t3lib/cache/backend/class.t3lib_cache_backend_file.php =================================================================== --- t3lib/cache/backend/class.t3lib_cache_backend_file.php (Revision 4168) +++ t3lib/cache/backend/class.t3lib_cache_backend_file.php (Revision 4291) @@ -66,26 +66,27 @@ * @author Robert Lemke */ public function setCacheDirectory($cacheDirectory) { + $typo3DocumentRoot = t3lib_div::getIndpEnv('TYPO3_DOCUMENT_ROOT') . '/'; if ($cacheDirectory{strlen($cacheDirectory) - 1} !== '/') { $cacheDirectory .= '/'; } - if (!is_writable($cacheDirectory)) { + if (!is_writable($typo3DocumentRoot . $cacheDirectory)) { t3lib_div::mkdir_deep( - t3lib_div::getIndpEnv('TYPO3_DOCUMENT_ROOT') . '/', + $typo3DocumentRoot, $cacheDirectory ); } - if (!is_dir($cacheDirectory)) { + if (!is_dir($typo3DocumentRoot . $cacheDirectory)) { throw new t3lib_cache_Exception( 'The directory "' . $cacheDirectory . '" does not exist.', 1203965199 ); } - if (!is_writable($cacheDirectory)) { + if (!is_writable($typo3DocumentRoot . $cacheDirectory)) { throw new t3lib_cache_Exception( 'The directory "' . $cacheDirectory . '" is not writable.', 1203965200 @@ -96,12 +97,12 @@ if (!is_writable($tagsDirectory)) { t3lib_div::mkdir_deep( - t3lib_div::getIndpEnv('TYPO3_DOCUMENT_ROOT') . '/', + $typo3DocumentRoot, $tagsDirectory ); } - $this->cacheDirectory = $cacheDirectory; + $this->cacheDirectory = $typo3DocumentRoot . $cacheDirectory; } /** @@ -173,7 +174,7 @@ if (!is_writable($cacheEntryPath)) { try { t3lib_div::mkdir_deep( - t3lib_div::getIndpEnv('TYPO3_DOCUMENT_ROOT') . '/', + '/', $cacheEntryPath ); } catch(Exception $exception) { @@ -210,13 +211,17 @@ } foreach ($tags as $tag) { - $tagPath = $this->cacheDirectory . 'tags/' . $tag . '/'; + $tagPath = $this->cacheDirectory . 'tags/' + . $this->cache->getIdentifier() . '/' . $tag . '/'; if (!is_writable($tagPath)) { - mkdir($tagPath); + t3lib_div::mkdir_deep( + '/', + $tagPath + ); } - touch($tagPath . $this->cache->getIdentifier() . '_' . $entryIdentifier); + touch($tagPath . $entryIdentifier); } } @@ -303,8 +308,9 @@ ); } - $path = $this->cacheDirectory . 'tags/'; - $pattern = $path . $tag . '/*'; + $path = $this->cacheDirectory . 'tags/' + . $this->cache->getIdentifier() . '/' . $tag . '/'; + $pattern = $path . '*'; $filesFound = glob($pattern); if ($filesFound === FALSE || count($filesFound) == 0) { @@ -360,18 +366,11 @@ ); } - $path = $this->cacheDirectory . 'data/' . $this->cache->getIdentifier() . '/'; - $pattern = $path . '*/*/*'; - $filesFound = glob($pattern); + $dataPath = $this->cacheDirectory . 'data/' . $this->cache->getIdentifier() . '/'; + $tagsPath = $this->cacheDirectory . 'tags/' . $this->cache->getIdentifier() . '/'; - if ($filesFound === FALSE || count($filesFound) == 0) { - return; - } - - foreach($filesFound as $filename) { - list(,$entryIdentifier) = explode('_', basename($filename)); - $this->remove($entryIdentifier); - } + t3lib_div::rmdir($dataPath, true); + t3lib_div::rmdir($tagsPath, true); } /** @@ -382,17 +381,35 @@ * @author Ingo Renner */ public function flushByTag($tag) { - $path = $this->cacheDirectory . 'tags/' . $tag . '/'; + $path = $this->cacheDirectory . 'tags/' + . $this->cache->getIdentifier() . '/' . $tag . '/'; $pattern = $path . '*'; $filesFound = glob($pattern); foreach ($filesFound as $file) { + $pathAndFile = explode('/', $file); + $identifier = $pathAndFile[count($pathAndFile) - 1]; + unlink($file); + $this->remove($identifier); } rmdir($path); } /** + * Removes all cache entries of this cache which are tagged by the specified tag. + * + * @param array The tags the entries must have + * @return void + * @author Ingo Renner + */ + public function flushByTags(array $tags) { + foreach ($tags as $tag) { + $this->flushByTag($tag); + } + } + + /** * Renders a file name for the specified cache entry * * @param string Identifier for the cache entry Index: t3lib/cache/backend/class.t3lib_cache_backend_globals.php =================================================================== --- t3lib/cache/backend/class.t3lib_cache_backend_globals.php (Revision 4168) +++ t3lib/cache/backend/class.t3lib_cache_backend_globals.php (Revision 4291) @@ -225,6 +225,19 @@ public function flushByTag($tag) { unset($GLOBALS['typo3CacheStorage'][$this->cache->getIdentifier()]['tags'][$tag]); } + + /** + * Removes all cache entries of this cache which are tagged by the specified tag. + * + * @param array The tags the entries must have + * @return void + * @author Ingo Renner + */ + public function flushByTags(array $tags) { + foreach ($tags as $tag) { + $this->flushByTag($tag); + } + } } Index: t3lib/cache/backend/class.t3lib_cache_backend_db.php =================================================================== --- t3lib/cache/backend/class.t3lib_cache_backend_db.php (Revision 4168) +++ t3lib/cache/backend/class.t3lib_cache_backend_db.php (Revision 4291) @@ -57,7 +57,7 @@ array( 'identifier' => $entryIdentifier, 'crdate' => time(), - 'data' => $data, + 'content' => $data, 'tags' => implode(',', $tags), 'lifetime' => $lifetime ) @@ -68,21 +68,21 @@ * Loads data from a cache file. * * @param string An identifier which describes the cache entry to load - * @return mixed The cache entry's content as a string or FALSE if the cache entry could not be loaded + * @return mixed The cache entry's data as a string or FALSE if the cache entry could not be loaded * @author Ingo Renner */ public function load($entryIdentifier) { $cacheEntry = false; $caheEntries = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows( - 'data', + 'content', $this->cacheTable, 'identifier = ' . $GLOBALS['TYPO3_DB']->fullQuoteStr($entryIdentifier, $this->cacheTable) . ' ' - . 'AND (crdate + lifetime) >= ' . time() + . 'AND ((crdate + lifetime) >= ' . time() . ' OR lifetime = 0)' ); if (count($caheEntries) == 1) { - $cacheEntry = $caheEntries[0]['data']; + $cacheEntry = $caheEntries[0]['content']; } return $cacheEntry; @@ -99,7 +99,7 @@ $hasEntry = false; $caheEntries = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows( - 'data', + 'content', $this->cacheTable, 'identifier = ' . $GLOBALS['TYPO3_DB']->fullQuoteStr($entryIdentifier, $this->cacheTable) . ' ' . 'AND (crdate + lifetime) >= ' . time() @@ -150,7 +150,7 @@ $cacheEntryRows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows( 'identifier', $this->cacheTable, - $GLOBALS['TYPO3_DB']->listQuery('tags', $tag, $this->cacheTable) + $this->getListQueryForTag($tag) ); foreach ($cacheEntryRows as $cacheEntryRow) { @@ -174,7 +174,7 @@ $whereClause = array(); foreach ($tags as $tag) { - $whereClause[] = $GLOBALS['TYPO3_DB']->listQuery('tags', $tag, $this->cacheTable); + $whereClause[] = $this->getListQueryForTag($tag); } $cacheEntryRows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows( @@ -213,9 +213,34 @@ } } + /** + * Removes all cache entries of this cache which are tagged by the specified tags. + * + * @param array The tags the entries must have + * @return void + * @author Ingo Renner + */ + public function flushByTags(array $tags) { + foreach ($this->findEntriesByTags($tags) as $entryIdentifier) { + $this->remove($entryIdentifier); + } + } + protected function setCacheTable($cacheTable) { $this->cacheTable = $cacheTable; } + + /** + * Gets the query to be used for selecting entries by a tag. The asterisk ("*") + * is allowed as a wildcard at the beginning and the end of a tag. + * + * @param string The tag to search for, the "*" wildcard is supported + * @return string the query to be used for selecting entries + * @author Oliver Hader + */ + protected function getListQueryForTag($tag) { + return str_replace('*', '%', $GLOBALS['TYPO3_DB']->listQuery('tags', $tag, $this->cacheTable)); + } } Index: t3lib/cache/backend/class.t3lib_cache_backend_memcached.php =================================================================== --- t3lib/cache/backend/class.t3lib_cache_backend_memcached.php (Revision 4168) +++ t3lib/cache/backend/class.t3lib_cache_backend_memcached.php (Revision 4291) @@ -55,6 +55,11 @@ protected $identifierPrefix; /** + * @var string The ID of this TYPO3 server. If many sites are using the same memcached, it prevents conflicts + */ + protected $serverId; + + /** * Constructs this backend * * @param string $context FLOW3's application context @@ -69,12 +74,16 @@ ); } + // Set default value for the server ID + $this->serverId = t3lib_div::getIndpEnv('HTTP_HOST'); + parent::__construct($options); $this->memcache = new Memcache(); $this->identifierPrefix = 'TYPO3_' . md5( t3lib_div::getIndpEnv('SCRIPT_FILENAME') . php_sapi_name() + . $this->serverId ) . '_'; if (!count($this->servers)) { @@ -91,6 +100,16 @@ } /** + * Setter for serverId property. + * + * @param int $serverId The value of the property + * @return void + */ + protected function setServerId($serverId) { + $this->serverId = $serverId; + } + + /** * setter for servers property * should be an array of entries like host:port * @@ -250,7 +269,34 @@ return $entries; } + /** + * Finds and returns all cache entry identifiers which are tagged by the specified tags. + * The asterisk ("*") is allowed as a wildcard at the beginning and the end of + * a tag. + * + * @param array Array of tags to search for, the "*" wildcard is supported + * @return array An array with identifiers of all matching entries. An empty array if no entries matched + * @author Ingo Renner + */ + public function findEntriesByTags(array $tags) { + $taggedEntries = array(); + $foundEntries = array(); + + foreach ($tags as $tag) { + $taggedEntries[$tag] = $this->findEntriesByTag($tag); + } + + $intersectedTaggedEntries = call_user_func_array('array_intersect', $taggedEntries); + + foreach ($intersectedTaggedEntries as $entryIdentifier) { + $foundEntries[$entryIdentifier] = $entryIdentifier; + } + + return $foundEntries; + } + + /** * Removes all cache entries of this cache. * * Beware that this flushes the complete memcached, not only the cache @@ -279,7 +325,21 @@ } } + /** + * Removes all cache entries of this cache which are tagged by the specified tag. + * + * @param array The tags the entries must have + * @return void + * @author Ingo Renner + */ + public function flushByTags(array $tags) { + foreach ($tags as $tag) { + $this->flushByTag($tag); + } + } + + /** * Returns an array with all known tags * * @return array Index: t3lib/cache/backend/class.t3lib_cache_backend_null.php =================================================================== --- t3lib/cache/backend/class.t3lib_cache_backend_null.php (Revision 4168) +++ t3lib/cache/backend/class.t3lib_cache_backend_null.php (Revision 4291) @@ -120,6 +120,16 @@ */ public function flushByTag($tag) { } + + /** + * Does nothing + * + * @param array ignored + * @return void + * @author Ingo Renner + */ + public function flushByTags(array $tags) { + } } Index: t3lib/class.t3lib_db.php =================================================================== --- t3lib/class.t3lib_db.php (Revision 4168) +++ t3lib/class.t3lib_db.php (Revision 4291) @@ -504,7 +504,8 @@ */ function listQuery($field, $value, $table) { $command = $this->quoteStr($value, $table); - $where = '('.$field.' LIKE \'%,'.$command.',%\' OR '.$field.' LIKE \''.$command.',%\' OR '.$field.' LIKE \'%,'.$command.'\' OR '.$field.'=\''.$command.'\')'; + $commandForLike = $this->escapeStrForLike($command, $table); + $where = '('.$field.' LIKE \'%,'.$commandForLike.',%\' OR '.$field.' LIKE \''.$commandForLike.',%\' OR '.$field.' LIKE \'%,'.$commandForLike.'\' OR '.$field.'=\''.$command.'\')'; return $where; } Index: t3lib/class.t3lib_tstemplate.php =================================================================== --- t3lib/class.t3lib_tstemplate.php (Revision 4168) +++ t3lib/class.t3lib_tstemplate.php (Revision 4291) @@ -239,21 +239,32 @@ * Fetches the "currentPageData" array from cache * * NOTE about currentPageData: - * It holds information about the TypoScript conditions along with the list of template uid's which is used on the page. - * In the getFromCache function in TSFE, currentPageData is used to evaluate if there is a template and if the matching conditions are alright. - * Unfortunately this does not take into account if the templates in the rowSum of currentPageData has changed composition, eg. due to hidden fields or start/end time. - * So if a template is hidden or times out, it'll not be discovered unless the page is regenerated - at least the this->start function must be called, because this will make a new portion of data in currentPageData string. + * It holds information about the TypoScript conditions along with the list + * of template uid's which is used on the page. In the getFromCache function + * in TSFE, currentPageData is used to evaluate if there is a template and + * if the matching conditions are alright. Unfortunately this does not take + * into account if the templates in the rowSum of currentPageData has + * changed composition, eg. due to hidden fields or start/end time. So if a + * template is hidden or times out, it'll not be discovered unless the page + * is regenerated - at least the this->start function must be called, + * because this will make a new portion of data in currentPageData string. * * @return array Returns the unmatched array $currentPageData if found cached in "cache_pagesection". Otherwise false is returned which means that the array must be generated and stored in the cache-table * @see start(), tslib_fe::getFromCache() */ - function getCurrentPageData() { - $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('content', 'cache_pagesection', 'page_id='.intval($GLOBALS['TSFE']->id).' AND mpvar_hash='.t3lib_div::md5int($GLOBALS['TSFE']->MP)); - if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) { - $currentPageData = unserialize($row['content']); - } else { - $currentPageData = false; + function getCurrentPageData() { + $currentPageData = false; + $pageSectionCache = $GLOBALS['cacheManager']->getCache('cache_pagesection'); + /* @var $pageSectionCache t3lib_cache_AbstractCache */ + + $cacheEntry = $pageSectionCache->load( + intval($GLOBALS['TSFE']->id) . '_' . t3lib_div::md5int($GLOBALS['TSFE']->MP) + ); + + if ($cacheEntry) { + $currentPageData = unserialize($cacheEntry); } + return $currentPageData; // 2008-02-03 / Stucki: Notice that $this->currentPageData is not used anymore! } @@ -292,7 +303,13 @@ if (is_array($theRootLine)) { $setupData = ''; $hash = ''; - $isCached = false; // Flag that indicates that the existing data in cache_pagesection could be used (this is the case if $TSFE->all is set, and the rowSum still matches). Based on this we decide if cache_pagesection needs to be updated... + + // Flag that indicates that the existing data in cache_pagesection + // could be used (this is the case if $TSFE->all is set, and the + // rowSum still matches). Based on this we decide if cache_pagesection + // needs to be updated... + $isCached = false; + $this->runThroughTemplates($theRootLine); if ($GLOBALS['TSFE']->all) { @@ -303,7 +320,7 @@ unset($cc); // If the two rowSums differ, we need to re-make the current page data and therefore clear the existing values. } else { // If $TSFE->all contains valid data, we don't need to update cache_pagesection (because this data was fetched from there already) - if (!strcmp(serialize($this->rootLine),serialize($cc['rootLine']))) { + if (!strcmp(serialize($this->rootLine), serialize($cc['rootLine']))) { $isCached = true; } // When the data is serialized below (ROWSUM hash), it must not contain the rootline by concept. So this must be removed (and added again later)... @@ -358,12 +375,12 @@ $hash = md5(serialize($cc)); // This stores the data. - t3lib_pageSelect::storeHash($hash, serialize($this->setup), 'TS TEMPLATE'); + t3lib_pageSelect::storeHash($hash, serialize($this->setup), 'TS_TEMPLATE'); if ($this->tt_track) $GLOBALS['TT']->setTSlogMessage('TS template size, serialized: '.strlen(serialize($this->setup)).' bytes'); $rowSumHash = md5('ROWSUM:'.serialize($this->rowSum)); - t3lib_pageSelect::storeHash($rowSumHash, serialize($cc['all']), 'TMPL CONDITIONS - ALL'); + t3lib_pageSelect::storeHash($rowSumHash, serialize($cc['all']), 'TMPL_CONDITIONS_ALL'); } // Add rootLine $cc['rootLine'] = $this->rootLine; @@ -376,17 +393,20 @@ unset($cc['match']); if (!$isCached && !$this->simulationHiddenOrTime && !$GLOBALS['TSFE']->no_cache) { // Only save the data if we're not simulating by hidden/starttime/endtime - $dbFields = array( - 'content' => serialize($cc), - 'tstamp' => $GLOBALS['EXEC_TIME'] + $pageSectionCache = $GLOBALS['cacheManager']->getCache('cache_pagesection'); + /* @var $pageSectionCache t3lib_cache_AbstractCache */ + + $mpvarHash = t3lib_div::md5int($GLOBALS['TSFE']->MP); + + $pageSectionCache->save( + intval($GLOBALS['TSFE']->id) . '_' . $mpvarHash, + serialize($cc), + array( + 'pageId_' . intval($GLOBALS['TSFE']->id), + 'mpvarHash_' . $mpvarHash + ) ); - $mpvar_hash = t3lib_div::md5int($GLOBALS['TSFE']->MP); - $GLOBALS['TYPO3_DB']->exec_UPDATEquery('cache_pagesection', 'page_id=' . intval($GLOBALS['TSFE']->id) . ' AND mpvar_hash=' . $mpvar_hash, $dbFields); - if ($GLOBALS['TYPO3_DB']->sql_affected_rows() == 0) { - $dbFields['page_id'] = intval($GLOBALS['TSFE']->id); - $dbFields['mpvar_hash'] = $mpvar_hash; - $GLOBALS['TYPO3_DB']->exec_INSERTquery('cache_pagesection', $dbFields); - } + } // If everything OK. if ($this->rootId && $this->rootLine && $this->setup) { Index: t3lib/class.t3lib_befunc.php =================================================================== --- t3lib/class.t3lib_befunc.php (Revision 4168) +++ t3lib/class.t3lib_befunc.php (Revision 4291) @@ -1195,28 +1195,27 @@ *******************************************/ /** - * Stores the string value $data in the 'cache_hash' table with the hash key, $hash, and visual/symbolic identification, $ident + * Stores the string value $data in the 'cache_hash' cache with the + * hash key, $hash, and visual/symbolic identification, $ident * IDENTICAL to the function by same name found in t3lib_page: * Usage: 2 * * @param string 32 bit hash string (eg. a md5 hash of a serialized array identifying the data being stored) * @param string The data string. If you want to store an array, then just serialize it first. - * @param string $ident is just a textual identification in order to inform about the content! May be 20 characters long. + * @param string $ident is just a textual identification in order to inform about the content! * @return void */ public static function storeHash($hash, $data, $ident) { - $insertFields = array( - 'hash' => $hash, - 'content' => $data, - 'ident' => $ident, - 'tstamp' => time() + $GLOBALS['cacheManager']->getCache('cache_hash')->save( + $hash, + $data, + array('ident_' . $ident), + 0 // unlimited lifetime ); - $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_hash', 'hash='.$GLOBALS['TYPO3_DB']->fullQuoteStr($hash, 'cache_hash')); - $GLOBALS['TYPO3_DB']->exec_INSERTquery('cache_hash', $insertFields); } /** - * Returns string value stored for the hash string in the table "cache_hash" + * Returns string value stored for the hash string in the cache "cache_hash" * Can be used to retrieved a cached value * IDENTICAL to the function by same name found in t3lib_page * Usage: 2 @@ -1226,16 +1225,16 @@ * @return string */ public static function getHash($hash, $expTime = 0) { - // if expTime is not set, the hash will never expire - $expTime = intval($expTime); - if ($expTime) { - $whereAdd = ' AND tstamp > '.(time()-$expTime); + $hashContent = null; + + $contentHashCache = $GLOBALS['cacheManager']->getCache('cache_hash'); + $cacheEntry = $contentHashCache->load($hash); + + if ($cacheEntry) { + $hashContent = $cacheEntry; } - $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('content', 'cache_hash', 'hash='.$GLOBALS['TYPO3_DB']->fullQuoteStr($hash, 'cache_hash').$whereAdd); - $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res); - $GLOBALS['TYPO3_DB']->sql_free_result($res); - return (is_array($row) ? $row['content'] : null); + return $hashContent; } Index: t3lib/class.t3lib_cache.php =================================================================== --- t3lib/class.t3lib_cache.php (Revision 0) +++ t3lib/class.t3lib_cache.php (Revision 4291) @@ -0,0 +1,98 @@ + +* All rights reserved +* +* This script is part of the TYPO3 project. The TYPO3 project is +* free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* The GNU General Public License can be found at +* http://www.gnu.org/copyleft/gpl.html. +* +* This script is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* This copyright notice MUST APPEAR in all copies of the script! +***************************************************************/ + + +/** + * A cache handling helper class + * + * @author Ingo Renner + * @package TYPO3 + * @subpackage t3lib + */ +class t3lib_cache { + + /** + * initializes the cache_pages cache + * + * @return void + * @author Ingo Renner + */ + public static function initPageCache() { + try { + $GLOBALS['TYPO3_CACHE']->create( + 'cache_pages', + 't3lib_cache_VariableCache', + $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheBackendAssignments']['cache_pages']['backend'], + $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheBackendAssignments']['cache_pages']['options'] + ); + } catch(t3lib_cache_exception_DuplicateIdentifier $e) { + // do nothing, a cache_pages cache already exists + } + } + + /** + * initializes the cache_pagesection cache + * + * @return void + * @author Ingo Renner + */ + public static function initPageSectionCache() { + try { + $GLOBALS['TYPO3_CACHE']->create( + 'cache_pagesection', + 't3lib_cache_VariableCache', + $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheBackendAssignments']['cache_pagesection']['backend'], + $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheBackendAssignments']['cache_pagesection']['options'] + ); + } catch(t3lib_cache_exception_DuplicateIdentifier $e) { + // do nothing, a cache_pagesection cache already exists + } + } + + /** + * initializes the cache_hash cache + * + * @return void + * @author Ingo Renner + */ + public static function initContentHashCache() { + try { + $GLOBALS['TYPO3_CACHE']->create( + 'cache_hash', + 't3lib_cache_VariableCache', + $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheBackendAssignments']['cache_hash']['backend'], + $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheBackendAssignments']['cache_hash']['options'] + ); + } catch(t3lib_cache_exception_DuplicateIdentifier $e) { + // do nothing, a cache_hash cache already exists + } + } +} + + +if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_cache.php']) { + include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_cache.php']); +} + +?> \ No newline at end of file Index: t3lib/class.t3lib_page.php =================================================================== --- t3lib/class.t3lib_page.php (Revision 4168) +++ t3lib/class.t3lib_page.php (Revision 4291) @@ -919,48 +919,47 @@ **********************************/ /** - * Returns string value stored for the hash string in the table "cache_hash" + * Returns string value stored for the hash string in the cache "cache_hash" * Can be used to retrieved a cached value * Can be used from your frontend plugins if you like. It is also used to store the parsed TypoScript template structures. You can call it directly like t3lib_pageSelect::getHash() * * @param string The hash-string which was used to store the data value * @param integer Allowed expiretime in seconds. Basically a record is selected only if it is not older than this value in seconds. If expTime is not set, the hashed value will never expire. - * @return string The "content" field of the "cache_hash" table row. + * @return string The "content" field of the "cache_hash" cache entry. * @see tslib_TStemplate::start(), storeHash() + * + * TODO check where $expTime is used, the new caching API can't handle it, so it can be removed */ - function getHash($hash,$expTime=0) { - // if expTime is not set, the hash will never expire - $expTime = intval($expTime); - if ($expTime) { - $whereAdd = ' AND tstamp > '.(time()-$expTime); + function getHash($hash, $expTime=0) { + $hashContent = null; + + $contentHashCache = $GLOBALS['cacheManager']->getCache('cache_hash'); + $cacheEntry = $contentHashCache->load($hash); + + if ($cacheEntry) { + $hashContent = $cacheEntry; } - $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('content', 'cache_hash', 'hash='.$GLOBALS['TYPO3_DB']->fullQuoteStr($hash, 'cache_hash').$whereAdd); - $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res); - $GLOBALS['TYPO3_DB']->sql_free_result($res); - if ($row) { - return $row['content']; - } + + return $hashContent; } /** - * Stores a string value in the cache_hash table identified by $hash. + * Stores a string value in the cache_hash cache identified by $hash. * Can be used from your frontend plugins if you like. You can call it directly like t3lib_pageSelect::storeHash() * * @param string 32 bit hash string (eg. a md5 hash of a serialized array identifying the data being stored) * @param string The data string. If you want to store an array, then just serialize it first. - * @param string $ident is just a textual identification in order to inform about the content! May be 20 characters long. + * @param string $ident is just a textual identification in order to inform about the content! * @return void * @see tslib_TStemplate::start(), getHash() */ - function storeHash($hash,$data,$ident) { - $insertFields = array( - 'hash' => $hash, - 'content' => $data, - 'ident' => $ident, - 'tstamp' => time() + function storeHash($hash, $data, $ident) { + $GLOBALS['cacheManager']->getCache('cache_hash')->save( + $hash, + $data, + array('ident_' . $ident), + 0 // unlimited lifetime ); - $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_hash', 'hash='.$GLOBALS['TYPO3_DB']->fullQuoteStr($hash, 'cache_hash')); - $GLOBALS['TYPO3_DB']->exec_INSERTquery('cache_hash', $insertFields); } /** Index: t3lib/class.t3lib_tsfebeuserauth.php =================================================================== --- t3lib/class.t3lib_tsfebeuserauth.php (Revision 4168) +++ t3lib/class.t3lib_tsfebeuserauth.php (Revision 4291) @@ -965,10 +965,11 @@ * @param integer The page id. * @return integer The number of pages for this page in the table "cache_pages" */ - function extGetNumberOfCachedPages($page_id) { - $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('count(*)', 'cache_pages', 'page_id='.intval($page_id)); - list($num) = $GLOBALS['TYPO3_DB']->sql_fetch_row($res); - return $num; + function extGetNumberOfCachedPages($pageId) { + $pageCache = $GLOBALS['cacheManager']->getCache('cache_pages'); + $pageCacheEntries = $pageCache->findEntriesByTag('pageId_' . (int) $pageId); + + return count($pageCacheEntries); } Index: t3lib/class.t3lib_tcemain.php =================================================================== --- t3lib/class.t3lib_tcemain.php (Revision 4168) +++ t3lib/class.t3lib_tcemain.php (Revision 4291) @@ -6951,8 +6951,19 @@ // Delete cache for selected pages: if (is_array($list_cache)) { - $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pages','page_id IN ('.implode(',',$GLOBALS['TYPO3_DB']->cleanIntArray($list_cache)).')'); - $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pagesection', 'page_id IN ('.implode(',',$GLOBALS['TYPO3_DB']->cleanIntArray($list_cache)).')'); + + $pageCache = $GLOBALS['cacheManager']->getCache( + 'cache_pages' + ); + $pageSectionCache = $GLOBALS['cacheManager']->getCache( + 'cache_pagesection' + ); + + $pageIds = $GLOBALS['TYPO3_DB']->cleanIntArray($list_cache); + foreach ($pageIds as $pageId) { + $pageCache->flushByTag('pageId_' . $pageId); + $pageSectionCache->flushByTag('pageId_' . $pageId); + } } } } @@ -7020,12 +7031,13 @@ break; case 'all': if ($this->admin || $this->BE_USER->getTSConfigVal('options.clearCache.all')) { + + // clear all caches that use the t3lib_cache framework + $GLOBALS['cacheManager']->flushCaches(); + if (t3lib_extMgm::isLoaded('cms')) { - $this->internal_clearPageCache(); - $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pagesection', ''); $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_treelist', ''); } - $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_hash',''); // Clearing additional cache tables: if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['clearAllCache_additionalTables'])) { @@ -7038,12 +7050,12 @@ } } } - if ($this->admin && $TYPO3_CONF_VARS['EXT']['extCache']) { + if ($this->admin && $TYPO3_CONF_VARS['EXT']['extCache']) { $this->removeCacheFiles(); } break; case 'temp_CACHED': - if ($this->admin && $TYPO3_CONF_VARS['EXT']['extCache']) { + if ($this->admin && $TYPO3_CONF_VARS['EXT']['extCache']) { $this->removeCacheFiles(); } break; @@ -7065,9 +7077,18 @@ } // Delete cache for selected pages: - if (is_array($list_cache)) { - $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pages','page_id IN ('.implode(',',$GLOBALS['TYPO3_DB']->cleanIntArray($list_cache)).')'); - $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pagesection', 'page_id IN ('.implode(',',$GLOBALS['TYPO3_DB']->cleanIntArray($list_cache)).')'); // Originally, cache_pagesection was not cleared with cache_pages! + if (is_array($list_cache)) { + $pageCache = $GLOBALS['cacheManager']->getCache( + 'cache_pages' + ); + $pageSectionCache = $GLOBALS['cacheManager']->getCache( + 'cache_pagesection' + ); + + foreach ($list_cache as $pageId) { + $pageCache->flushByTag('pageId_' . (int) $pageId); + $pageSectionCache->flushByTag('pageId_' . (int) $pageId); + } } } } @@ -7206,15 +7227,8 @@ * @return void */ function internal_clearPageCache() { - if (t3lib_extMgm::isLoaded('cms')) { - if ($GLOBALS['TYPO3_CONF_VARS']['FE']['pageCacheToExternalFiles']) { - $cacheDir = PATH_site.'typo3temp/cache_pages'; - $retVal = t3lib_div::rmdir($cacheDir,true); - if (!$retVal) { - t3lib_div::sysLog('Could not remove page cache files in "'.$cacheDir.'"','Core/t3lib_tcemain',2); - } - } - $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pages',''); + if (t3lib_extMgm::isLoaded('cms')) { + $GLOBALS['cacheManager']->getCache('cache_pages')->flush(); } } Index: typo3/view_help.php =================================================================== --- typo3/view_help.php (Revision 4168) +++ typo3/view_help.php (Revision 4291) @@ -766,7 +766,7 @@ /** * Creates glossary index in $this->glossaryWords - * Glossary is cached in cache_hash table and so will be updated only when cache is cleared. + * Glossary is cached in cache_hash cache and so will be updated only when cache is cleared. * * @return void */ Index: typo3/init.php =================================================================== --- typo3/init.php (Revision 4168) +++ typo3/init.php (Revision 4291) @@ -171,9 +171,36 @@ $CLIENT = t3lib_div::clientInfo(); // $CLIENT includes information about the browser/user-agent $PARSETIME_START = t3lib_div::milliseconds(); // Is set to the system time in milliseconds. This could be used to output script parsetime in the end of the script +// *********************************** +// Initializing the Caching System +// *********************************** + // TODO implement autoloading so that we only require stuff we really need +require_once(PATH_t3lib . 'class.t3lib_cache.php'); +require_once(PATH_t3lib . 'cache/class.t3lib_cache_abstractbackend.php'); +require_once(PATH_t3lib . 'cache/class.t3lib_cache_abstractcache.php'); +require_once(PATH_t3lib . 'cache/class.t3lib_cache_exception.php'); +require_once(PATH_t3lib . 'cache/class.t3lib_cache_factory.php'); +require_once(PATH_t3lib . 'cache/class.t3lib_cache_manager.php'); +require_once(PATH_t3lib . 'cache/class.t3lib_cache_variablecache.php'); +require_once(PATH_t3lib . 'cache/exception/class.t3lib_cache_exception_classalreadyloaded.php'); +require_once(PATH_t3lib . 'cache/exception/class.t3lib_cache_exception_duplicateidentifier.php'); +require_once(PATH_t3lib . 'cache/exception/class.t3lib_cache_exception_invalidbackend.php'); +require_once(PATH_t3lib . 'cache/exception/class.t3lib_cache_exception_invalidcache.php'); +require_once(PATH_t3lib . 'cache/exception/class.t3lib_cache_exception_invaliddata.php'); +require_once(PATH_t3lib . 'cache/exception/class.t3lib_cache_exception_nosuchcache.php'); + +$cacheManager = t3lib_div::makeInstance('t3lib_cache_Manager'); +$cacheFactoryClass = t3lib_div::makeInstanceClassName('t3lib_cache_Factory'); +$TYPO3_CACHE = new $cacheFactoryClass($cacheManager); + +t3lib_cache::initPageCache(); +t3lib_cache::initPageSectionCache(); +t3lib_cache::initContentHashCache(); +unset($cacheFactoryClass); + // ************************* // CLI dispatch processing // ************************* @@ -360,7 +387,7 @@ // ******************************* // $GLOBALS['LANG'] initialisation -// ******************************* +// ******************************* require_once(PATH_typo3.'sysext/lang/lang.php'); $GLOBALS['LANG'] = t3lib_div::makeInstance('language'); $GLOBALS['LANG']->init($BE_USER->uc['lang']); Index: typo3/sysext/cms/ext_tables.sql =================================================================== --- typo3/sysext/cms/ext_tables.sql (Revision 4168) +++ typo3/sysext/cms/ext_tables.sql (Revision 4291) @@ -8,17 +8,13 @@ # CREATE TABLE cache_pages ( id int(11) unsigned NOT NULL auto_increment, - hash varchar(32) DEFAULT '' NOT NULL, - page_id int(11) unsigned DEFAULT '0' NOT NULL, - reg1 int(11) unsigned DEFAULT '0' NOT NULL, - HTML mediumtext, - temp_content int(1) DEFAULT '0' NOT NULL, - tstamp int(11) unsigned DEFAULT '0' NOT NULL, - expires int(10) unsigned DEFAULT '0' NOT NULL, - cache_data mediumblob, - KEY page_id (page_id), - KEY sel (hash,page_id), - PRIMARY KEY (id) + identifier varchar(32) DEFAULT '' NOT NULL, + crdate int(11) unsigned DEFAULT '0' NOT NULL, + content mediumtext, + tags mediumtext, + lifetime int(11) unsigned DEFAULT '0' NOT NULL, + PRIMARY KEY (id), + KEY cache_id (identifier) ) ENGINE=InnoDB; @@ -26,11 +22,14 @@ # Table structure for table 'cache_pagesection' # CREATE TABLE cache_pagesection ( - page_id int(11) unsigned DEFAULT '0' NOT NULL, - mpvar_hash int(11) unsigned DEFAULT '0' NOT NULL, - content blob, - tstamp int(11) unsigned DEFAULT '0' NOT NULL, - PRIMARY KEY (page_id,mpvar_hash) + id int(11) unsigned NOT NULL auto_increment, + identifier varchar(32) DEFAULT '' NOT NULL, + crdate int(11) unsigned DEFAULT '0' NOT NULL, + content mediumtext, + tags mediumtext, + lifetime int(11) unsigned DEFAULT '0' NOT NULL, + PRIMARY KEY (id), + KEY cache_id (identifier) ) ENGINE=InnoDB; Index: typo3/sysext/cms/tslib/class.tslib_fe.php =================================================================== --- typo3/sysext/cms/tslib/class.tslib_fe.php (Revision 4168) +++ typo3/sysext/cms/tslib/class.tslib_fe.php (Revision 4291) @@ -111,7 +111,6 @@ * 2355: function setPageCacheContent($content,$data,$tstamp) * 2382: function clearPageCacheContent() * 2392: function clearPageCacheContent_pidList($pidList) - * 2403: function pageCachePostProcess(&$row,$type) * 2426: function setSysLastChanged() * * SECTION: Page generation; rendering and inclusion @@ -406,10 +405,16 @@ */ var $pages_lockObj; // Locking object for accessing "cache_pages" + /** + * the page cache object, use this to save pages to the cache and to + * retrieve them again + * + * @var t3lib_cache_AbstractBackend + */ + protected $pageCache; + protected $pageCacheTags = array(); - - /** * Class constructor * Takes a number of GET/POST input variable as arguments and stores them internally. @@ -573,6 +578,28 @@ /** + * Initializes the caching system. + * + * @return void + */ + public function initCaches() { + try { + $this->pageCache = $GLOBALS['cacheManager']->getCache( + 'cache_pages' + ); + } catch(t3lib_cache_exception_NoSuchCache $e) { + t3lib_cache::initPageCache(); + + $this->pageCache = $GLOBALS['cacheManager']->getCache( + 'cache_pages' + ); + } + + t3lib_cache::initPageSectionCache(); + t3lib_cache::initContentHashCache(); + } + + /** * Initializes the front-end login user. * * @return void @@ -1818,7 +1845,9 @@ if (!is_array($cc)) { $key = $this->id.'::'.$this->MP; $isLocked = $this->acquirePageGenerationLock($this->pagesection_lockObj, $key); // Returns true if the lock is active now - if (!$isLocked) { // Lock is no longer active, the data in "cache_pagesection" is now ready + + if (!$isLocked) { + // Lock is no longer active, the data in "cache_pagesection" is now ready $cc = $this->tmpl->getCurrentPageData(); if (is_array($cc)) { $this->releasePageGenerationLock($this->pagesection_lockObj); // Release the lock @@ -1853,7 +1882,9 @@ if (!is_array($row)) { $isLocked = $this->acquirePageGenerationLock($this->pages_lockObj, $lockHash); - if (!$isLocked) { // Lock is no longer active, the data in "cache_pages" is now ready + + if (!$isLocked) { + // Lock is no longer active, the data in "cache_pages" is now ready $row = $this->getFromCache_queryRow(); if (is_array($row)) { $this->releasePageGenerationLock($this->pages_lockObj); // Release the lock @@ -1891,27 +1922,12 @@ * * @return array Cached row, if any. Otherwise void. */ - function getFromCache_queryRow() { - - $GLOBALS['TT']->push('Cache Query',''); - $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery( - 'S.*', - 'cache_pages S,pages P', - 'S.hash='.$GLOBALS['TYPO3_DB']->fullQuoteStr($this->newHash, 'cache_pages').' - AND S.page_id=P.uid - AND S.expires > '.intval($GLOBALS['EXEC_TIME']).' - AND P.deleted=0 - AND P.hidden=0 - AND P.starttime<='.intval($GLOBALS['EXEC_TIME']).' - AND (P.endtime=0 OR P.endtime>'.intval($GLOBALS['EXEC_TIME']).')' - ); + function getFromCache_queryRow() { + $GLOBALS['TT']->push('Cache Query', ''); + $cachedPage = $this->pageCache->load($this->newHash); $GLOBALS['TT']->pull(); - if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) { - $this->pageCachePostProcess($row,'get'); - } - $GLOBALS['TYPO3_DB']->sql_free_result($res); - return $row; + return $cachedPage; } /** @@ -2156,7 +2172,7 @@ if ($this->TYPO3_CONF_VARS['EXT']['extCache'] != 0) { // Try to fetch if cache is enabled - list($TCA,$this->TCAcachedExtras) = unserialize($this->sys_page->getHash($tempHash, 0)); + list($TCA, $this->TCAcachedExtras) = unserialize($this->sys_page->getHash($tempHash, 0)); } // If no result, create it: @@ -2184,7 +2200,7 @@ $TCA = $newTc; // Store it in cache if cache is enabled if ($this->TYPO3_CONF_VARS['EXT']['extCache'] != 0) { - $this->sys_page->storeHash($tempHash, serialize(array($newTc,$this->TCAcachedExtras)), 'SHORT TC'); + $this->sys_page->storeHash($tempHash, serialize(array($newTc,$this->TCAcachedExtras)), 'SHORT_TC'); } } } @@ -2696,34 +2712,44 @@ } /** - * Sets cache content; Inserts the content string into the cache_pages table. + * Sets cache content; Inserts the content string into the cache_pages cache. * * @param string The content to store in the HTML field of the cache table * @param mixed The additional cache_data array, fx. $this->config - * @param integer Timestamp + * @param integer Expiration timestamp * @return void * @see realPageCacheContent(), tempPageCacheContent() */ - function setPageCacheContent($content,$data,$tstamp) { + function setPageCacheContent($content, $data, $expirationTstamp) { $this->clearPageCacheContent(); - $insertFields = array( - 'hash' => $this->newHash, - 'page_id' => $this->id, - 'HTML' => $content, + + $cacheData = array( + 'hash' => $this->newHash, + 'page_id' => $this->id, + 'HTML' => $content, 'temp_content' => $this->tempContent, - 'cache_data' => serialize($data), - 'expires' => $tstamp, - 'tstamp' => $GLOBALS['EXEC_TIME'] + 'cache_data' => serialize($data), + 'expires' => $expirationTstamp, + 'tstamp' => $GLOBALS['EXEC_TIME'] ); - $this->cacheExpires = $tstamp; + $this->cacheExpires = $expirationTstamp; - if ($this->page_cache_reg1) { - $insertFields['reg1'] = intval($this->page_cache_reg1); + $this->pageCacheTags[] = 'pageId_' . $cacheData['page_id']; + + if ($this->page_cache_reg1) { + $reg1 = intval($this->page_cache_reg1); + + $cacheData['reg1'] = $reg1; + $this->pageCacheTags[] = 'reg1_' . $reg1; } - $this->pageCachePostProcess($insertFields,'set'); - $GLOBALS['TYPO3_DB']->exec_INSERTquery('cache_pages', $insertFields); + $this->pageCache->save( + $cacheData['hash'], + $cacheData, + $this->pageCacheTags, + $cacheData['expires'] - $GLOBALS['EXEC_TIME'] + ); } /** @@ -2731,40 +2757,21 @@ * * @return void */ - function clearPageCacheContent() { - $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pages', 'hash='.$GLOBALS['TYPO3_DB']->fullQuoteStr($this->newHash, 'cache_pages')); + function clearPageCacheContent() { + $this->pageCache->remove($this->newHash); } /** * Clears cache content for a list of page ids * - * @param string A list of INTEGER numbers which points to page uids for which to clear entries in the cache_pages table (page content cache) + * @param string A list of INTEGER numbers which points to page uids for which to clear entries in the cache_pages cache (page content cache) * @return void */ - function clearPageCacheContent_pidList($pidList) { - $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pages', 'page_id IN ('.$GLOBALS['TYPO3_DB']->cleanIntList($pidList).')'); - } + function clearPageCacheContent_pidList($pidList) { + $pageIds = t3lib_div::trimExplode(',', $pidList); - /** - * Post processing page cache rows for both get and set. - * - * @param array Input "cache_pages" row, passed by reference! - * @param string Type of operation, either "get" or "set" - * @return void - */ - function pageCachePostProcess(&$row,$type) { - - if ($this->TYPO3_CONF_VARS['FE']['pageCacheToExternalFiles']) { - $cacheFileName = PATH_site.'typo3temp/cache_pages/'.$row['hash']{0}.$row['hash']{1}.'/'.$row['hash'].'.html'; - switch((string)$type) { - case 'get': - $row['HTML'] = @is_file($cacheFileName) ? t3lib_div::getUrl($cacheFileName) : ''; - break; - case 'set': - t3lib_div::writeFileToTypo3tempDir($cacheFileName,$row['HTML']); - $row['HTML'] = ''; - break; - } + foreach ($pageIds as $pageId) { + $this->pageCache->flushByTag('pageId_' . (int) $pageId); } } @@ -2840,6 +2847,16 @@ return $success; } + /** + * adds tags to this page's cache entry, you can then f.e. remove cache + * entries by tag + * + * @param array an array of tag + * @return void + */ + public function addCacheTags(array $tags) { + $this->pageCacheTags = array_merge($this->pageCacheTags, $tags); + } @@ -2859,6 +2876,7 @@ + /******************************************** * * Page generation; rendering and inclusion Index: typo3/sysext/cms/tslib/index_ts.php =================================================================== --- typo3/sysext/cms/tslib/index_ts.php (Revision 4168) +++ typo3/sysext/cms/tslib/index_ts.php (Revision 4291) @@ -156,6 +156,8 @@ $TT->push('Initializing the Caching System',''); // TODO implement autoloading so that we only require stuff we really need + require_once(PATH_t3lib . 'class.t3lib_cache.php'); + require_once(PATH_t3lib . 'cache/class.t3lib_cache_abstractbackend.php'); require_once(PATH_t3lib . 'cache/class.t3lib_cache_abstractcache.php'); require_once(PATH_t3lib . 'cache/class.t3lib_cache_exception.php'); @@ -173,6 +175,7 @@ $cacheManager = t3lib_div::makeInstance('t3lib_cache_Manager'); $cacheFactoryClass = t3lib_div::makeInstanceClassName('t3lib_cache_Factory'); $TYPO3_CACHE = new $cacheFactoryClass($cacheManager); + unset($cacheFactoryClass); $TT->pull(); @@ -182,15 +185,16 @@ // *********************************** $temp_TSFEclassName = t3lib_div::makeInstanceClassName('tslib_fe'); $TSFE = new $temp_TSFEclassName( - $TYPO3_CONF_VARS, - t3lib_div::_GP('id'), - t3lib_div::_GP('type'), - t3lib_div::_GP('no_cache'), - t3lib_div::_GP('cHash'), - t3lib_div::_GP('jumpurl'), - t3lib_div::_GP('MP'), - t3lib_div::_GP('RDCT') - ); + $TYPO3_CONF_VARS, + t3lib_div::_GP('id'), + t3lib_div::_GP('type'), + t3lib_div::_GP('no_cache'), + t3lib_div::_GP('cHash'), + t3lib_div::_GP('jumpurl'), + t3lib_div::_GP('MP'), + t3lib_div::_GP('RDCT') +); +$TSFE->initCaches(); if($TYPO3_CONF_VARS['FE']['pageUnavailable_force'] && !t3lib_div::cmpIP(t3lib_div::getIndpEnv('REMOTE_ADDR'), $TYPO3_CONF_VARS['SYS']['devIPmask'])) { @@ -212,6 +216,7 @@ t3lib_div::_GP('MP'), t3lib_div::_GP('RDCT') ); + $TSFE->initCaches(); $TSFE->ADMCMD_preview_postInit($temp_previewConfig); } Index: typo3/sysext/cms/tslib/class.tslib_fetce.php =================================================================== --- typo3/sysext/cms/tslib/class.tslib_fetce.php (Revision 4168) +++ typo3/sysext/cms/tslib/class.tslib_fetce.php (Revision 4291) @@ -258,9 +258,15 @@ */ function clear_cacheCmd($cacheCmd) { $cacheCmd = intval($cacheCmd); + if ($cacheCmd) { - $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pages', 'page_id='.intval($cacheCmd)); - if ($cacheCmd == intval($GLOBALS['TSFE']->id)) { // Setting no_cache true if the cleared-cache page is the current page! + + $GLOBALS['cacheManager']->getCache('cache_pages')->flushByTag( + 'pageId_' . $cacheCmd + ); + + if ($cacheCmd == intval($GLOBALS['TSFE']->id)) { + // Setting no_cache true if the cleared-cache page is the current page! $GLOBALS['TSFE']->set_no_cache(); } } Index: typo3/sysext/tstemplate/ts/index.php =================================================================== --- typo3/sysext/tstemplate/ts/index.php (Revision 4168) +++ typo3/sysext/tstemplate/ts/index.php (Revision 4291) @@ -142,9 +142,9 @@ TABLE#ts-analyzer tr.c-headLineTable {background-color: #A2AAB8;} TABLE#ts-analyzer tr td {padding: 0 2px;} TABLE#ts-analyzer tr.c-headLineTable td {padding: 2px 4px; font-weight:bold; color: #fff;} - .tst-analyzer-options { margin:5px 0; } - .tst-analyzer-options label {padding-left:5px; vertical-align:text-top; } - .bgColor0 {background-color:#fff;} + .tst-analyzer-options { margin:5px 0; } + .tst-analyzer-options label {padding-left:5px; vertical-align:text-top; } + .bgColor0 {background-color:#fff;} '; @@ -262,22 +262,22 @@ } if($this->extClassConf['name'] == 'tx_tstemplateinfo') { - // NEW button + // NEW button $buttons['new'] = ''; - + if(!empty($this->e) && !t3lib_div::_POST('abort') && !t3lib_div::_POST('saveclose')) { // no NEW-button while edit $buttons['new'] = ''; - + // SAVE button $buttons['save'] = ''; - // SAVE AND CLOSE button + // SAVE AND CLOSE button $buttons['save_close'] = ''; // CLOSE button $buttons['close'] = ''; - + } } elseif($this->extClassConf['name'] == 'tx_tstemplateceditor' && count($this->MOD_MENU['constant_editor_cat'])) { // SAVE button @@ -319,13 +319,25 @@ function getCountCacheTables($humanReadable) { $out = array(); - $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('count(*)', 'cache_pages', ''); + $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery( + 'count(id)', + 'cache_pages', + '' + ); list($out['cache_pages']) = $GLOBALS['TYPO3_DB']->sql_fetch_row($res); - $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('count(*)', 'cache_pagesection', ''); + $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery( + 'count(id)', + 'cache_pagesection', + '' + ); list($out['cache_pagesection']) = $GLOBALS['TYPO3_DB']->sql_fetch_row($res); - $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('count(*)', 'cache_hash', ''); + $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery( + 'count(id)', + 'cache_hash', + '' + ); list($out['cache_hash']) = $GLOBALS['TYPO3_DB']->sql_fetch_row($res); if ($humanReadable) { @@ -428,7 +440,7 @@ 'pid' => $actTemplateId ? -1 * $actTemplateId : $id, 'title' => "+ext", ); - + $tce->start($recData, array()); $tce->process_datamap(); return $tce->substNEWwithIDs['NEW']; Index: typo3/sysext/indexed_search/modfunc1/class.tx_indexedsearch_modfunc1.php =================================================================== --- typo3/sysext/indexed_search/modfunc1/class.tx_indexedsearch_modfunc1.php (Revision 4168) +++ typo3/sysext/indexed_search/modfunc1/class.tx_indexedsearch_modfunc1.php (Revision 4291) @@ -1296,7 +1296,12 @@ while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) { $idList[] = $row['page_id']; } - $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_pages', 'page_id IN ('.implode(',',$GLOBALS['TYPO3_DB']->cleanIntArray($idList)).')'); + + $pageCache = $GLOBALS['cacheManager']->getCache('cache_pages'); + + foreach ($idList as $pageId) { + $pageCache->flushByTag('pageId_' . (int) $pageId); + } } }