ちょっと前に、InfinispanのCache Loaderの使ったサンプルを書きましたが、この時にEvictionとPassivationの関係がよくわかってなくて、すごくアホなエントリになってしまいました…。
ちゃんと、英単語として読めばよかった…。
まあ、その反省も踏まえて、ここで復習したいと思います。
Eviction
https://docs.jboss.org/author/display/ISPN/Eviction
Cache Passivation
https://docs.jboss.org/author/display/ISPN/Cache+Loaders+and+Stores#CacheLoadersandStores-CachePassivation
What does the passivation flag do?
https://docs.jboss.org/author/pages/viewpage.action?pageId=5832809
Eviction(追い出し)に関する設定は、Infinispanのメモリ内に保持するエントリに関するものです。ここでは、
- メモリに保持する最大数
- Evictionのアルゴリズム
- Evictionを行うスレッドの動作ポリシー
の設定が可能です。
で、ここにCache Loaderの設定を加えます。
なんですが、ここでPassivationを有効にするかどうかで、Cache Loaderに保存される内容が変わります。
Passivation | メモリ上のエントリ | Cache Loader上のエントリ |
---|---|---|
無効 | EvictionのmaxEntriesで設定した数(*) | メモリ上のエントリ+Evictされたエントリ |
有効 | EvictionのmaxEntriesで設定した数(*) | Evictされたエントリ |
*maxEntriesで設定した数であることを、厳密に保証するわけではないようです
つまり、Passivationを無効(デフォルト)にした場合は、Cache Loaderが保持するエントリは、メモリ上のエントリを含んだすべてのエントリになります。特に書き込みを同期モードにした場合は、Write-Throughキャッシュとして振る舞うことになります。
反対に、Passivationを有効にした場合は、EvictされたエントリがCache Loaderに置かれるということになるため、メモリ上のエントリとCache Loader上のエントリを合わせてはじめて全体が揃うといったことになります。また、いったんEvictされCache Loaderに移されたエントリが、再度アクティブになるとメモリ上に戻り、今度はCache Loaderからは削除されます。
ここを前はちゃんと理解できていませんでした…。
というわけで、懲りずにまたサンプルを作成。
src/main/scala/InfinispanEvictPassive.scala
import org.infinispan.Cache import org.infinispan.configuration.cache.ConfigurationBuilder import org.infinispan.container.entries.CacheEntry import org.infinispan.eviction.{EvictionStrategy, EvictionThreadPolicy} import org.infinispan.manager.{DefaultCacheManager, EmbeddedCacheManager} object InfinispanEvictPassive { def main(args: Array[String]): Unit = { val manager = new DefaultCacheManager val range = (1 to 10) val (keys, values) = range.map(i => (s"key$i", s"value$i")).unzip println("---------------------------- Passivation -------------------------------------") val cachePassivation = defineCacheEnablePassivation(manager, "cacheEnablePassivation") val advancedCachePassivation = cachePassivation.getAdvancedCache keys.foreach { k => printCacheEntryDetail("Cache Passivation Preloaded", advancedCachePassivation.getCacheEntry(k, null, null)) } keys.zip(values).foreach { case (k, v) => cachePassivation.put(k, v) } println("------------------------------------------------------------------------------") keys.foreach { k => printCacheEntryDetail("Cache Passivation Writed", advancedCachePassivation.getCacheEntry(k, null, null)) } println("---------------------------- Passivation -------------------------------------") println("---------------------------- Write-Through -------------------------------------") val cacheWriteThrough = defineCacheWriteThrough(manager, "cacheWritThrough") val advancedCacheWriteThrough = cacheWriteThrough.getAdvancedCache keys.foreach { k => printCacheEntryDetail("Cache Write-Through Preloaded", advancedCacheWriteThrough.getCacheEntry(k, null, null)) } keys.zip(values).foreach { case (k, v) => cacheWriteThrough.put(k, v) } println("------------------------------------------------------------------------------") keys.foreach { k => printCacheEntryDetail("Cache Write-Through Writed", advancedCacheWriteThrough.getCacheEntry(k, null, null)) } println("---------------------------- Write-Through -------------------------------------") } def defineCacheEnablePassivation(manager: EmbeddedCacheManager, name: String): Cache[String, String] = { manager.defineConfiguration( name, new ConfigurationBuilder() .eviction .strategy(EvictionStrategy.LIRS) .threadPolicy(EvictionThreadPolicy.PIGGYBACK) .maxEntries(4) .loaders .passivation(true) .addFileCacheStore .ignoreModifications(false) .fetchPersistentState(false) .location("cache-store-passivation") .build) manager.getCache(name) } def defineCacheWriteThrough(manager: EmbeddedCacheManager, name: String): Cache[String, String] = { manager.defineConfiguration( name, new ConfigurationBuilder() .eviction .strategy(EvictionStrategy.LIRS) .threadPolicy(EvictionThreadPolicy.PIGGYBACK) .maxEntries(4) .loaders .passivation(false) .addFileCacheStore .ignoreModifications(false) .fetchPersistentState(false) .location("cache-store-write-through") .build) manager.getCache(name) } def printCacheEntryDetail(preMsg: String, cacheEntry: CacheEntry): Unit = cacheEntry match { case null => case _ => val msg = s"""$preMsg => | Key[${cacheEntry.getKey}], | Value[${cacheEntry.getValue}]""".stripMargin println(msg) } }
キャッシュの設定は、Passivationを有効にしたもの
def defineCacheEnablePassivation(manager: EmbeddedCacheManager, name: String): Cache[String, String] = { manager.defineConfiguration( name, new ConfigurationBuilder() .eviction .strategy(EvictionStrategy.LIRS) .threadPolicy(EvictionThreadPolicy.PIGGYBACK) .maxEntries(4) .loaders .passivation(true) .addFileCacheStore .ignoreModifications(false) .fetchPersistentState(false) .location("cache-store-passivation") .build) manager.getCache(name) }
無効にしたものの2つを用意しています。
def defineCacheWriteThrough(manager: EmbeddedCacheManager, name: String): Cache[String, String] = { manager.defineConfiguration( name, new ConfigurationBuilder() .eviction .strategy(EvictionStrategy.LIRS) .threadPolicy(EvictionThreadPolicy.PIGGYBACK) .maxEntries(4) .loaders .passivation(false) .addFileCacheStore .ignoreModifications(false) .fetchPersistentState(false) .location("cache-store-write-through") .build) manager.getCache(name) }
ともに、EvictionのアルゴリズムはLIRSで、最大保持数は4です。
Cache Loaderの設定は、ファイル保存で、Passivationを有効にした方は「cache-store-passivation」ディレクトリ、無効にした方は「cache-store-write-through」ディレクトリに保存することにしています。
キャッシュに保存するキーと値は、簡単に作成して
val range = (1 to 10) val (keys, values) = range.map(i => (s"key$i", s"value$i")).unzip
起動時にとりあえず読んでみて、改めてキャッシュに保存して読み出します。
println("---------------------------- Passivation -------------------------------------") val cachePassivation = defineCacheEnablePassivation(manager, "cacheEnablePassivation") val advancedCachePassivation = cachePassivation.getAdvancedCache keys.foreach { k => printCacheEntryDetail("Cache Passivation Preloaded", advancedCachePassivation.getCacheEntry(k, null, null)) } keys.zip(values).foreach { case (k, v) => cachePassivation.put(k, v) } println("------------------------------------------------------------------------------") keys.foreach { k => printCacheEntryDetail("Cache Passivation Writed", advancedCachePassivation.getCacheEntry(k, null, null)) } println("---------------------------- Passivation -------------------------------------")
これはPassivationを有効にした方のものですが、無効にした方もだいだい同じです。
起動時と終了時の読み出しは、AdvancedCacheからCacheEntryを取得して、nullでなければキーと値を出力するようにしています。nullの場合は、何も出ません。
def printCacheEntryDetail(preMsg: String, cacheEntry: CacheEntry): Unit = cacheEntry match { case null => case _ => val msg = s"""$preMsg => | Key[${cacheEntry.getKey}], | Value[${cacheEntry.getValue}]""".stripMargin println(msg) }
では、実行してみます。
> run [info] Running InfinispanEvictPassive [info] ---------------------------- Passivation ------------------------------------- [error] 4 29, 2013 12:28:40 午前 org.infinispan.factories.GlobalComponentRegistry start [error] INFO: ISPN000128: Infinispan version: Infinispan 'Delirium' 5.2.1.Final [error] 4 29, 2013 12:28:41 午前 org.infinispan.jmx.CacheJmxRegistration start [error] INFO: ISPN000031: MBeans were successfully registered to the platform MBean server. [info] ------------------------------------------------------------------------------ [info] Cache Passivation Writed => [info] Key[key1], [info] Value[value1] [info] Cache Passivation Writed => [info] Key[key2], [info] Value[value2] [info] Cache Passivation Writed => [info] Key[key3], [info] Value[value3] [info] Cache Passivation Writed => [info] Key[key4], [info] Value[value4] [info] Cache Passivation Writed => [info] Key[key5], [info] Value[value5] [info] Cache Passivation Writed => [info] Key[key6], [info] Value[value6] [info] Cache Passivation Writed => [info] Key[key7], [info] Value[value7] [info] Cache Passivation Writed => [info] Key[key8], [info] Value[value8] [info] Cache Passivation Writed => [info] Key[key9], [info] Value[value9] [info] Cache Passivation Writed => [info] Key[key10], [info] Value[value10] [info] ---------------------------- Passivation ------------------------------------- [info] ---------------------------- Write-Through ------------------------------------- [error] 4 29, 2013 12:28:41 午前 org.infinispan.jmx.CacheJmxRegistration start [error] INFO: ISPN000031: MBeans were successfully registered to the platform MBean server. [info] ------------------------------------------------------------------------------ [info] Cache Write-Through Writed => [info] Key[key1], [info] Value[value1] [info] Cache Write-Through Writed => [info] Key[key2], [info] Value[value2] [info] Cache Write-Through Writed => [info] Key[key3], [info] Value[value3] [info] Cache Write-Through Writed => [info] Key[key4], [info] Value[value4] [info] Cache Write-Through Writed => [info] Key[key5], [info] Value[value5] [info] Cache Write-Through Writed => [info] Key[key6], [info] Value[value6] [info] Cache Write-Through Writed => [info] Key[key7], [info] Value[value7] [info] Cache Write-Through Writed => [info] Key[key8], [info] Value[value8] [info] Cache Write-Through Writed => [info] Key[key9], [info] Value[value9] [info] Cache Write-Through Writed => [info] Key[key10], [info] Value[value10] [info] ---------------------------- Write-Through ------------------------------------- [success] Total time: 3 s, completed 2013/04/29 0:28:41
共に、同じ結果です。
ここで、Cache Loaderに出力されたファイルの内容を見てみます。
まずはPassivationを有効にした方から。
$ cat cache-store-passivation/cacheEnablePassivation/3288064 ^C^A�^C*^F^C >^Dkey4>^Fvalue4^C >^Dkey6>^Fvalue6^C >^Dkey2>^Fvalue2^C >^Dkey1>^Fvalue1^C >^Dkey8>^Fvalue8^C >^Dkey9>^Fvalue9
6つのエントリが確認できます。maxEntriesは、4ですからね。
続いて、Passivationを無効にした方です。
$ cat cache-store-write-through/cacheWritThrough/3288064 ^C^A�^C* ^C >^Dkey4>^Fvalue4^C >^Dkey3>^Fvalue3^C >^Dkey6>^Fvalue6^C >^Dkey5>^Fvalue5^C >^Dkey2>^Fvalue2^C >^Dkey1>^Fvalue1^C >^Dkey8>^Fvalue8^C >^Dkey7>^Fvalue7^C >^Dkey9>^Fvalue9
…9つしかない?と言いたいところですが、実際には表示できない文字があるので、そこにあるんでしょうなぁ。
では、もう1度プログラムを起動してみます。
> run [info] Running InfinispanEvictPassive [info] ---------------------------- Passivation ------------------------------------- [error] 4 29, 2013 12:32:39 午前 org.infinispan.factories.GlobalComponentRegistry start [error] INFO: ISPN000128: Infinispan version: Infinispan 'Delirium' 5.2.1.Final [error] 4 29, 2013 12:32:39 午前 org.infinispan.jmx.CacheJmxRegistration start [error] INFO: ISPN000031: MBeans were successfully registered to the platform MBean server. [info] Cache Passivation Preloaded => [info] Key[key1], [info] Value[value1] [info] Cache Passivation Preloaded => [info] Key[key2], [info] Value[value2] [info] Cache Passivation Preloaded => [info] Key[key4], [info] Value[value4] [info] Cache Passivation Preloaded => [info] Key[key6], [info] Value[value6] [info] Cache Passivation Preloaded => [info] Key[key8], [info] Value[value8] [info] Cache Passivation Preloaded => [info] Key[key9], [info] Value[value9] [info] ------------------------------------------------------------------------------ [info] Cache Passivation Writed => [info] Key[key1], [info] Value[value1] [info] Cache Passivation Writed => [info] Key[key2], [info] Value[value2] [info] Cache Passivation Writed => [info] Key[key3], [info] Value[value3] [info] Cache Passivation Writed => [info] Key[key4], [info] Value[value4] [info] Cache Passivation Writed => [info] Key[key5], [info] Value[value5] [info] Cache Passivation Writed => [info] Key[key6], [info] Value[value6] [info] Cache Passivation Writed => [info] Key[key7], [info] Value[value7] [info] Cache Passivation Writed => [info] Key[key8], [info] Value[value8] [info] Cache Passivation Writed => [info] Key[key9], [info] Value[value9] [info] Cache Passivation Writed => [info] Key[key10], [info] Value[value10] [info] ---------------------------- Passivation ------------------------------------- [info] ---------------------------- Write-Through ------------------------------------- [error] 4 29, 2013 12:32:40 午前 org.infinispan.jmx.CacheJmxRegistration start [error] INFO: ISPN000031: MBeans were successfully registered to the platform MBean server. [info] Cache Write-Through Preloaded => [info] Key[key1], [info] Value[value1] [info] Cache Write-Through Preloaded => [info] Key[key2], [info] Value[value2] [info] Cache Write-Through Preloaded => [info] Key[key3], [info] Value[value3] [info] Cache Write-Through Preloaded => [info] Key[key4], [info] Value[value4] [info] Cache Write-Through Preloaded => [info] Key[key5], [info] Value[value5] [info] Cache Write-Through Preloaded => [info] Key[key6], [info] Value[value6] [info] Cache Write-Through Preloaded => [info] Key[key7], [info] Value[value7] [info] Cache Write-Through Preloaded => [info] Key[key8], [info] Value[value8] [info] Cache Write-Through Preloaded => [info] Key[key9], [info] Value[value9] [info] Cache Write-Through Preloaded => [info] Key[key10], [info] Value[value10] [info] ------------------------------------------------------------------------------ [info] Cache Write-Through Writed => [info] Key[key1], [info] Value[value1] [info] Cache Write-Through Writed => [info] Key[key2], [info] Value[value2] [info] Cache Write-Through Writed => [info] Key[key3], [info] Value[value3] [info] Cache Write-Through Writed => [info] Key[key4], [info] Value[value4] [info] Cache Write-Through Writed => [info] Key[key5], [info] Value[value5] [info] Cache Write-Through Writed => [info] Key[key6], [info] Value[value6] [info] Cache Write-Through Writed => [info] Key[key7], [info] Value[value7] [info] Cache Write-Through Writed => [info] Key[key8], [info] Value[value8] [info] Cache Write-Through Writed => [info] Key[key9], [info] Value[value9] [info] Cache Write-Through Writed => [info] Key[key10], [info] Value[value10] [info] ---------------------------- Write-Through ------------------------------------- [success] Total time: 2 s, completed 2013/04/29 0:32:40
Passivationを無効にした方は、前回保存した全てのエントリが読み込めています。対して、Passivationを有効にした方はEvictされたと思われるものしか読み込めていないことになります。
ここを、前に動かした時は変な理解のままエントリを書いたと…。
この前回Evictされた内容を読み出してしまうのが嫌だとかいうことであれば、purgeOnStartupで調整するんでしょうね。
5/6 追記)
EvictionとPassivationをテーマにしていたのですが、せっかくなのでCacheLoaderを外した場合の挙動も書いておきますね。
Cacheの設定としては、以下のようにしてみます。
def defineCacheNoStore(manager: EmbeddedCacheManager, name: String): Cache[String, String] = { manager.defineConfiguration( name, new ConfigurationBuilder() .eviction .strategy(EvictionStrategy.LIRS) .maxEntries(4) .build) manager.getCache(name) }
キャッシュを使用するコードとしては、他のサンプルと同じように。
println("---------------------------- No-Store -------------------------------------") val cacheNoStore = defineCacheNoStore(manager, "cacheNoStore") val advancedCacheNoStore = cacheNoStore.getAdvancedCache keys.foreach { k => printCacheEntryDetail("Cache No-Store Preloaded", advancedCacheNoStore.getCacheEntry(k, null, null)) } keys.zip(values).foreach { case (k, v) => cacheNoStore.put(k, v) } println("------------------------------------------------------------------------------") keys.foreach { k => printCacheEntryDetail("Cache No-Store Writed", advancedCacheNoStore.getCacheEntry(k, null, null)) } println("---------------------------- No-Store -------------------------------------")
実行すると
[info] ---------------------------- No-Store ------------------------------------- [error] 5 06, 2013 7:32:21 午後 org.infinispan.jmx.CacheJmxRegistration start [error] INFO: ISPN000031: MBeans were successfully registered to the platform MBean server. [info] ------------------------------------------------------------------------------ [info] Cache No-Store Writed => [info] Key[key3], [info] Value[value3] [info] Cache No-Store Writed => [info] Key[key5], [info] Value[value5] [info] Cache No-Store Writed => [info] Key[key7], [info] Value[value7] [info] Cache No-Store Writed => [info] Key[key10], [info] Value[value10] [info] ---------------------------- No-Store -------------------------------------
という結果になり、キャッシュへの保存数が制限されるような挙動になります。
が、maxEntriesに設定した数を保証してくれるわけでもないみたいなので、目安ですね。
実際、10個のエントリを保存するためにmaxEntriesは32まで上げないとダメでした…。