OSCache#getElementCountInMemory が -1 を返す理由を考えてみた
com.opensymphony.oscache.hibernate.OSCache#getElementCountInMemory が -1 を返す理由と、自分が実装するとしたらどうするかを考えてみました。
第一印象
おいらが最初に OSCache を使った時には、getElementCountInMemory が -1 を返すなんてダメダメだと思いました。EhCache はきちんと値を返していたので好感が持てました。
java.util.Map#size() の戻り値は int 型
しかし、ソースを追って気づいたのですが、getElementCountInMemory の戻り値は long であり、java.lang.Map#size() の戻り値は int なんですね。ということは、内部で使用している Map 実装の Map#size() メソッドの値を直接返すことはできません。
EhCache の getElementCountInMemory() 実装
では、EhCacheはどうやって実装しているのだろうと疑問に思い、ソース見てみました。Map#size() をそのまま使って値を返していました orz
理論上は
実装上 long でエントリ数を返すことが難しいことと、hiberante の Cache#getElementCountInMemory の仕様としては、サポートしないなら -1 を返せばよいことになているので、OSCache の実装は全く問題なしです。逆にEhCacheのほうは、Integer.MAX_VALUE を超えるとバグということになりますね。
実際問題
Integer.MAX_VALUE は 2,147,483,647 です。ここで、Integer.MAX_VALUE の数だけエントリ数を持たせることを考えてみます。
32bitOS環境でのオンメモリキャッシュを仮定
java 実装の参照のメモリサイズを 4 バイトであると仮定すると、エントリ、キー、値の参照のサイズの合計だけで 25,769,803,764 バイトになります。32ビット環境では1プロセスが扱えるメモリの上限はせいぜい 2GB や 4GB 程度であるため、エントリ数が int の上限を超えることは考えられません。
64bitOS環境でのオンメモリキャッシュを仮定
java 実装の参照のメモリサイズを 8 バイトであると仮定すると、エントリ、キー、値の参照のサイズの合計だけで 51,539,607,528 バイトになります。64ビット環境では1プロセスが扱えるメモリの上限が 100GB 超であるため、エントリ数が int の上限を超えることは考えられないこともないです。しかし、エントリ、キー、値の実際の情報まで含めて考えると現実的ではありません。(現状のOSCacheやEhCacheのエントリが含むメタ情報から考えると、ありえないと言えます)
ディスクキャッシュを仮定
ディスクキャッシュの場合、値はディスク上に保存するとしても、エントリ用のメタ情報とキー情報はインデックスとしてメモリ上に配置しておく必要があります。となると、上記のオンメモリキャッシュの場合と同様、ディスクキャッシュでもエントリ数が int の上限を超えることは現実的ではありません。