at posts/single.html

PStore ファイルの内容を確認する方法

tDiary のプラグインを作っているときに、キャッシュデータを PStore ファイルに保存することがある。 PStore ファイルの中身はバイナリ (Marshal.dumpの結果) なので、保存されているデータの中身をエディタで見ることができない。 デバッグ時などでファイルの中身が見たい場合に、どうすればいいか考えてみた。 他にいい方法があれば、教えてください。

PStore の代わりに YAML::Store を使う

YAML::Store を使うとデータを YAML 形式で保存できるので、エディタでキャッシュの内容を確認できるようになる。 YAML をパースする分だけ PStore より速度が落ちるので、開発時だけ YAML::Store を使うというのもあり。 以下のように Store を切り替えられるようにしておくと便利かも。

      case db_type
      when :pstore
        require 'pstore'
        @db = PStore.new("cache.pstore")
      when :yaml
        require 'yaml/store'
        @db = YAML::Store.new("cache.yaml")
      else
        raise ArgumentError.new("unsupported database type: #{db_type}")
      end

Marshal.dump はできるけど YAML ではダンプできないようなオブジェクトを格納する場合には、この方法は使えない。

PStore ファイルをダンプするスクリプトを書く

PStore の中身を開いてダンプするような、ちょっとしたスクリプト (pstoredump.rb) を書いておくと便利。

#!/usr/bin/env ruby
require 'pstore'
require 'pp'
 
file = ARGV[0]
db = PStore.new(file)
db.transaction(true) do
  pp db
end

このスクリプトを動かして PStore の内容をダンプする。

pstoredump.rb cache.pstore > cache.txt

irb を使って対話的に PStore データを読み書きする

irb から操作するときは、以下のようにしている。

$ irb
> require 'pstore'
> db = PStore.new("cache.pstore")
> table = nil
> db.transaction(true) { table = db.instance_variable_get("@table") }
> table.keys

普通、 PStore の中身は transaction ブロックの中でしか読めない。 ブロックの中だとデータを対話的に表示できない(ブロックが閉じた時点でまとめて実行される)ので、 対話的に中身を読むにはちょっと不便。

そこで、 instance_variable_get を使ってデータの中身をローカル変数 (table) に取り出している。 こうすれば、 table 変数を使って PStore データを表示できる。

もちろん、 transaction ブロックの外なので、データの更新はできない。 データを更新したい場合は、もう一度 transaction を開いて、ローカル変数の値をセットする。

> db.transaction { db.instance_variable_set("@table", table) }

なお、読み込みと更新で transaction が2回に分かれているので、同時に他の環境から同じ PStore ファイルへアクセスされる場合にはこの方法は使えない。

参考

PStore, YAML::Store, さらに独自の Store を使う方法まで。分かりやすい。

そういえば、 PStore ではファイルサイズの上限の目安ってどれくらいなんだろう。 内部的にはファイルの中身をそのまま @table ハッシュに load しているだけなので、 DB のように値をどんどん追加していくと一気に処理が重くなる。 環境にもよるけど、 CGI で動かすなら最大でも 1MB くらいまでに収まるように設計した方がいいのかな。

関連する日記