ぐらめぬ・ぜぷつぇんのはてダ(2007 to 2011)

2007年~2011年ごろまで はてなダイアリー に書いてた記事を引っ越してきました。

Singletonはすごい取り扱い要注意なデザパタとつくづく実感した。

YakiBikiのHTMLプラグインでHTMLエスケープが抜けてそうだったので一通り見直し掛けてる内に、みょうな現象が発生した。

  • "sys"ロールユーザーでログイン中に、
  • 1. を実行し、
  • 2. を実行するようなHTMLドキュメントを表示してみる。

具体的にはこんなHTMLテキストを表示させてみる。

<yb_ls 適当なページ名 />
...
<yb_recent 適当な件数 />

すると、sysロールなので には全データの最新XX件が表示される筈なのだが・・・何故か、の取得結果と同じデータが表示されてしまう。しかし"sys"ロールでないユーザでログインしている場合はこの現象は発生しない。

結論から言うと、日時順インデックスを操作するDatetimeクラスのインスタンスがgrain_Factory::index()内でSingletonになっていて、した時のフィルタ設定がリセットされずにでも呼ばれた為、でその前のと同じ結果が返されてしまっていたという罠。
また、何で"sys"ロールでログインしている場合のみ発生するかというと、"sys"ロール「でない」場合はちゃんと毎度ACLを評価した結果をフィルタに設定しているから。つまり"sys"ロールでログインしている場合のみ、DatetimeのSingletonインスタンスに対するfilter設定が、直前に呼ばれたまま残ってしまっているから。

・・・Singleton(とその亜種)って、本当に、頭痛の種だな。
もともとYakiBikiはファイル読み込みが頻発するため、一度インデックスファイルを読み込んだらずっとメモリ上に残しておくことを目的にして、インデックス系のインスタンスはSingletonっぽくしてあるのだが。
なんか、それが無用なトラブルの元になっているように思えてならない。

あと自分、実はDatetimeクラスにちゃんとreset()メソッドを用意していて、これ呼ぶとfilter設定をリセットしてくれる。・・・が、肝心のgrain_Factory::index()で呼んでいなかったΣ(゚Д゚;。

というわけで、対処としてはreset()を grain_Factory::index()でdatetimeが指定された時、Singletonキャッシュから参照を取得後に呼ぶようにした。

なんというか、パフォーマンスを気にしてSingletonにするとろくな事にならないような気がする。*1

*1:でも例えばStrutsのActionクラスは一度インスタンスが生成されたらキャッシュされる、Singleton亜種なんだよな・・・。先日読んだStruts本にも、この点に注意してActionクラスメンバに迂闊にリクエスト絡みの変数をセットしてしまうとヤバイとか書いてあったな。