今までは Cache::FileCache によるファイルシステムキャッシュにしていたけど、いくつか問題があって SQLite にかえた
ファイルシステムキャッシュで困っていたこと
- なんか遅い
- キャッシュ無効化の処理のためにキャッシュを生成元とキャッシュのキーをキャッシュ内に格納したいが、アトミックにやるうまい方法がなかった
SQLite 選択
Redis とかを立てるのが機能的には便利そうだけど、リソース的にあんまりサーバプロセスを増やしたくはないので、SQLite とした。
CREATE TABLE cache (
`cache_key` TEXT NOT NULL PRIMARY KEY,
`content` BLOB NOT NULL
);
CREATE TABLE cache_relation (
`id` INTEGER PRIMARY KEY,
`cache_key` TEXT NOT NULL,
`source_id` TEXT NOT NULL
);
CREATE INDEX cache_relation_index_cache_key ON cache_relation (`cache_key`);
CREATE INDEX cache_relation_index_source_id ON cache_relation (`source_id`);
CREATE TRIGGER on_cache_deleted AFTER DELETE ON cache BEGIN
DELETE FROM cache_relation WHERE cache_key = old.cache_key;
END;
CREATE TRIGGER on_cache_related_deleted AFTER DELETE ON cache_relation BEGIN
DELETE FROM cache WHERE cache_key = old.cache_key;
END;
こんな感じでキャッシュ本体 (cacheテーブル)と、そのキャッシュを生成するのに使ったもののid(文字列)のリスト(cache_relationテーブル)を持って、お互いにトリガーで消しあうようにしておく。
こうしておくと、通常のキャッシュキーによる追加・削除だけではなくて、生成元が更新された時に関連するキャッシュをまとめて消せる。
なお、キャッシュ用のDBファイルは元データと分けた。というのも、元データのDBは毎日バックアップとしてGmailに送りつけているので、キャッシュを含めたくなかったから。