タグを使用したKohana 3のプライマリキャッシュ

この例は、Kohana 3.1フレームワークでのコンテンツ管理システムの開発中に発生した1つの問題を解決した結果であり、1つの管理者アカウントと多くの未登録の読者が想定されています。



データベースにアクセスするモデルメソッドの結果をキャッシュするのに長い時間がかかりました。 実際、DBMSの負荷を軽減するために、データベースからデータセットのコピーを作成する必要がありました。 新しいデータを追加するとき、または古いデータを更新するときにキャッシュをすぐに更新するには、タグでキャッシュをクリアする必要がありました。



これらすべてを考慮し、使用するホスティングの制限により、要件は次のとおりでした。



標準のCache_File



クラスCache_File



タグをサポートCache_File



ん。このため、独自のクラスを記述する必要があり、 JetCache



という名前が付けられました。



クラスは「loner」テンプレートに従って設計されています。 ファイルバンクのモデルで動作するクラスの例を考えてみましょう。 モデルが初期化されると、インスタンスが作成されます:



 $this->cache = JetCache::instance();
      
      







特定のカテゴリのファイルのリストを抽出する関数の例を使用して、データキャッシュの作成を検討します(ここでは、読みやすくするためにいくつかの引数とコードを削除しています)。



  //    /** * * @param int $rubricId Id    * @return array */ public function getFiles($rubricId) { //!!!  ,      , //   $key = 'filebank_get_files'.$rubricId; $arResult = $this->cache->get($key); if (is_array($arResult)) { return $arResult; } $arResult = array(); $arParams = array(); $arParams[':rubricId'] = $rubricId; $query = " SELECT * FROM `filebank_files` WHERE `rubric_id`=:rubricId ORDER BY `time` DESC, `name` ASC "; $arResult['files'] = DB::query(Database::SELECT, $query) ->parameters($arParams) ->execute() ->as_array(); //!!!      $this->cache->set($key, $arResult, array('filebank_rubrics', 'filebank_files')); return $arResult; }
      
      







したがって、キャッシュエントリはキー$key = 'filebank_get_files'.$rubricId



とタグ“ filebank_rubrics”および“ filebank_files”、つまり、カテゴリとファイルに関する情報を直接更新する場合、このエントリをクリアする必要があります。



タグによってキャッシュをクリアする例については、カテゴリを削除する機能を検討してください。 cacheRegExp



プロパティには、検証のためにタグを抽出するファイル(キー)の名前の正規表現が含まれています。 つまり、チェックは二重です。最初に正規表現でファイル名をチェックし、次にタグをチェックします。



  protected $cacheRegExp = '/^filebank/'; //  public function delRubric($rubricId) { $query = ' SELECT `name` FROM `filebank_files` WHERE `rubric_id`=:rubricId '; $arFiles = DB::query(Database::SELECT, $query) ->param(':rubricId', $rubricId) ->execute() ->as_array(); $arFiles = Arr::path($arFiles, '*.name'); $this->delFiles($arFiles); $query = ' DELETE FROM `filebank_rubrics` WHERE `rubric_id`=:rubricId '; DB::query(Database::DELETE, $query) ->param(':rubricId', $rubricId) ->execute(); //!!!     $tags = array('filebank_rubrics', 'filebank_files'); $this->cache->delete_by_tags($tags, $this->cacheRegExp); }
      
      





つまり、ルーブリックを削除すると、ルーブリックおよびルーブリック内の位置に関連付けられたデータのキャッシュがクリアされます。



したがって、プライマリの長期データキャッシュの可能性が追加されました。 コントローラレベルでは、ファイルドライバで標準の「キャッシュ」モジュールを使用して短期キャッシングを使用することもできます。



キャッシュを消去したり、ユーザーが情報を追加したりする高速が必要な大規模プロジェクトの場合は、もちろん、特別なソリューションを使用することをお勧めします。 たとえば、ドライバ「Memcached-tag」または「Xcache」モジュール「Cache」。 ただし、1人または少数のグループが管理する小規模なサイトの場合、特別なキャッシュツールを提供せずにホスティングを使用すると、このソリューションはうまく機能します。



キャッシュが保存されるファイルは1つのディレクトリに含まれ、次の構造を持ちます。

, (unix timestamp)\n

\n

\n









最後に、完全なクラスコードを示します。

 <?php defined('SYSPATH') or die('No direct access allowed.'); class JetCache { protected static $instance = NULL; protected static $config; protected static $cache_dir; protected static $cache_time; public static function instance() { if (is_null(self::$instance)) { self::$instance = new self(); } return self::$instance; } protected function __construct() { self::$config = Kohana::config('jethelix')->default; self::$cache_dir = self::$config['jet_cache_dir']; if (!is_dir(self::$cache_dir)) { $oldUmask = umask(0000); if (!mkdir(self::$cache_dir, 0777, TRUE)) { $message = '    JetCache'; throw new Exception($message); } umask($oldUmask); } self::$cache_time = self::$config['jet_cache']; } protected function __clone() { } public function set($id, $data, array $tags=array(), $lifetime=NULL) { if (!$lifetime) { $lifetime = self::$cache_time; } $filename = self::$cache_dir . '/' . $id . '.txt'; $expires = time() + (int)$lifetime; $tagString = implode(',', $tags); $serData = serialize($data); $content = $expires . "\n" . $tagString . "\n" . $serData; try { file_put_contents($filename, $content); } catch (Exception $e) { return FALSE; } return TRUE; } public function get($id) { $filename = self::$cache_dir . '/' . $id . '.txt'; if (!is_file($filename)) { return NULL; } try { $content = file_get_contents($filename); } catch (Exception $e) { return NULL; } $arContent = explode("\n", $content); unset ($content); try { if ($arContent[0] < time()) { return NULL; } $data = unserialize($arContent[2]); return $data; } catch (Exception $e) { return NULL; } } public function delete($id) { $filename = self::$cache_dir . '/' . $id . '.txt'; try { unlink($filename); } catch (Exception $e) { return FALSE; } return TRUE; } public function garbage_collect() { $dir = opendir(self::$cache_dir); while ($file = readdir($dir)) { $fullName = self::$cache_dir . '/'. $file; if (!is_file($fullName)) { continue; } try { $this->_deleteIfExpires($fullName); } catch (Exception $e) { return FALSE; } } return TRUE; } protected function _deleteIfExpires($filename) { $fhandle = fopen($filename, 'r'); $expires = (int)fgets($fhandle); fclose($fhandle); if ($expires < time()) { unlink($filename); } } public function delete_by_tags(array $tags, $filenameRegExp=NULL) { $this->garbage_collect(); try { $arFiles = $this->_getTaggedFiles($tags, $filenameRegExp); $this->_deleteFiles($arFiles); } catch (Exception $e) { return FALSE; } return TRUE; } protected function _getTaggedFiles(array $needTags, $filenameRegExp) { $taggedFiles = array(); $dir = opendir(self::$cache_dir); while ($file = readdir($dir)) { $fullName = self::$cache_dir . '/' . $file; if (!is_file($fullName)) { continue; } if ($filenameRegExp && !preg_match($filenameRegExp, $file)) { continue; } $hasTags = $this->_getTagsFromFile($fullName); $isValid = $this->_tagsValidate($needTags, $hasTags); if ($isValid) { $taggedFiles[] = $fullName; } } return $taggedFiles; } protected function _getTagsFromFile($filename) { $fhandler = fopen($filename, 'r'); fgets($fhandler); $tagString = fgets($fhandler); fclose($fhandler); $tagString = trim($tagString); $arTags = explode(',', $tagString); return $arTags; } protected function _tagsValidate(array $needTags, array $hasTags) { foreach ($needTags as $tag) { if (in_array($tag, $hasTags)) { return TRUE; } } return FALSE; } protected function _deleteFiles(array $files) { foreach ($files as $filename) { unlink($filename); } } }
      
      






All Articles