CLOVER🍀

That was when it all began.

Infinispan 9.2のEviction Strategyを試す

Infinispan 9.2では、Evictionの戦略として「ExceptionベースのEviction」をサポートしたということが、リリースについて
書かれたブログエントリに記載があります。

Infinispan: Infinispan 9.2.0.Final

Exception based evictionA new "eviction" that instead of removing old entries prevents new entries being inserted (supported by all memory storage and eviction types)

http://blog.infinispan.org/2018/02/infinispan-920final.html

ただこのEviction Strategyという設定自体、Infinispan 9.2で新しく設定できるようになった項目(新規の設定項目)
となります。

Eviction strategy

全部で次の4つのStrategyがあり、

  • NONE
  • MANUAL
  • REMOVE
  • EXCEPTION

Infinispan 9.1までの挙動で考えると、MANUALとREMOVEが相当するという感じでしょうか。

せっかくなので、見ていってみましょう。

環境

Java

$ java -version
openjdk version "1.8.0_151"
OpenJDK Runtime Environment (build 1.8.0_151-8u151-b12-0ubuntu0.16.04.2-b12)
OpenJDK 64-Bit Server VM (build 25.151-b12, mixed mode)

Infinispanは、9.2.1を使用します。

準備

依存関係は、こちら。

libraryDependencies ++= Seq(
  "org.infinispan" % "infinispan-core" % "9.2.1.Final" % Compile,
  "net.jcip" % "jcip-annotations" % "1.0" % Compile,
  "org.scalatest" %% "scalatest" % "3.0.5" % Test
)

Eviction Strategyは、「infinispan-core」があれば十分確認できます。

お題

Eviction Strategyの各戦略に対して、Node数が3のDistributed Cacheについて動きを確認してみたいと思います。Evictionの閾値を設ける場合は、
オブジェクト数(count)を10とします。

テストコードと設定ファイルの雛形

テストコードの雛形は、このように用意します。
src/test/scala/org/littlewings/infinispan/evictionstrategy/EvictionStrategySuite.scala

package org.littlewings.infinispan.evictionstrategy

import org.infinispan.Cache
import org.infinispan.commons.CacheException
import org.infinispan.configuration.cache.StorageType
import org.infinispan.eviction.EvictionStrategy
import org.infinispan.interceptors.impl.ContainerFullException
import org.infinispan.manager.DefaultCacheManager
import org.infinispan.remoting.RemoteException
import org.scalatest.{FunSuite, Matchers}

class EvictionStrategySuite extends FunSuite with Matchers {
  // ここに、テストを書く!!

  protected def withCache[K, V](cacheName: String, numInstances: Int = 3)(fun: Cache[K, V] => Unit): Unit = {
    val managers = (1 to numInstances).map(_ => new DefaultCacheManager("infinispan.xml"))

    managers.foreach(_.startCache(cacheName))

    try {
      val cache = managers(0).getCache[K, V](cacheName)
      fun(cache)
      cache.stop()
    } finally {
      managers.foreach(_.stop())
    }
  }
}

簡単にクラスタを構成できる、ヘルパーメソッド付きです。

続いて、設定ファイルの雛形。
src/test/resources/infinispan.xml

<?xml version="1.0" encoding="UTF-8"?>
<infinispan
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="urn:infinispan:config:9.2 http://www.infinispan.org/schemas/infinispan-config-9.2.xsd"
        xmlns="urn:infinispan:config:9.2">
    <jgroups>
        <stack-file name="udp" path="default-configs/default-jgroups-udp.xml"/>
    </jgroups>

    <cache-container>
        <transport cluster="test-cluster" stack="udp"/>

        <!-- 後で -->

    </cache-container>
</infinispan>

この中に、Cacheの定義を埋めていきます。

デフォルト?

最初は、Eviction Strategyをなにも設定しない状態で動かしてみましょう。

        <distributed-cache name="defaultEvictionStrategyCache" owners="1"/>

ほぼデフォルトのDistributed Cacheで、ownersのみ1にしてあります。ownersを1にしている理由については、Eviction有効時に触れることとしましょう。

テストコードは、こちら。

  test("default eviction strategy") {
    withCache[String, String]("defaultEvictionStrategyCache", 3) { cache =>
      val configuration = cache.getCacheConfiguration
      configuration.memory.evictionStrategy should be(EvictionStrategy.NONE)
      configuration.memory.storageType should be(StorageType.OBJECT)

      (1 to 50).foreach(i => cache.put(s"key${i}", s"value${i}"))

      cache.size should be(50L)

      println("size = " + cache.size)

      cache.forEach((key, _) => cache.evict(key))
      cache.forEach((key, _) => println(key))

      println("size = " + cache.size)

      cache.size should (be >= 33 or be <= 34)
    }
  }

クラスタ内のNodeは、3つです。

Cacheの定義で確認すると、デフォルトのEviction StrategyはNONEのようです。

      val configuration = cache.getCacheConfiguration
      configuration.memory.evictionStrategy should be(EvictionStrategy.NONE)
      configuration.memory.storageType should be(StorageType.OBJECT)

NONEとは、Evictionが有効になっていない状態で、直接Cache#evictは呼び出されない想定となっているようです。Passivationが有効だと、警告されるそうな。
https://github.com/infinispan/infinispan/blob/9.2.1.Final/core/src/main/java/org/infinispan/configuration/cache/EvictionConfigurationBuilder.java#L116-L118
https://github.com/infinispan/infinispan/blob/9.2.1.Final/core/src/main/java/org/infinispan/configuration/cache/MemoryConfigurationBuilder.java#L179-L182

データを50個放り込んで全部をCache#evictすると、33〜34個くらいのエントリが残ります。
*例が悪いのですが、Eviction StratetyとCache#evictには関係はあるものの同時に使って説明するべきではなかったなぁと思います

      (1 to 50).foreach(i => cache.put(s"key${i}", s"value${i}"))

      cache.size should be(50L)

      println("size = " + cache.size)

      cache.forEach((key, _) => cache.evict(key))
      cache.forEach((key, _) => println(key))

      println("size = " + cache.size)

      cache.size should (be >= 33 or be <= 34)

ちょっと、ん?って感じですね。ですが、ここは流しておきます。

なお、この状態でCache#evictを呼び出すと、実は警告されていたりします。

3 31, 2018 12:59:36 午前 org.infinispan.cache.impl.CacheImpl evict
WARN: ISPN000419: Eviction of an entry invoked without an explicit eviction strategy for cache defaultEvictionStrategyCache

Evictionが有効でないのにCache#evictを呼び出しているよ、と言われるようですね。
https://github.com/infinispan/infinispan/blob/9.2.1.Final/core/src/main/java/org/infinispan/cache/impl/CacheImpl.java#L873-L875

ここで言う「Evictionが有効でない」というのは、MemoryConfiguration#isEvictionEnabledがtrueを返すことであり
https://github.com/infinispan/infinispan/blob/9.2.1.Final/core/src/main/java/org/infinispan/configuration/cache/MemoryConfiguration.java#L87

EvictionStrategy#isRemovableBasedがtrueを返す時です。
https://github.com/infinispan/infinispan/blob/9.2.1.Final/core/src/main/java/org/infinispan/eviction/EvictionStrategy.java#L66-L68

つまりREMOVEの時だけですね、警告されないの…。

ここで、Eviction StrategyはNONEのままで、閾値をオブジェクト数10にしてみましょう。

        <distributed-cache name="noneEvictionStrategyCache" owners="1">
            <memory>
                <object strategy="NONE" size="10"/>
            </memory>
        </distributed-cache>

テストコードは、こちら。

test("none eviction strategy, but select remove strategy") {
    withCache[String, String]("noneEvictionStrategyCache", 3) { cache =>
      // REMOVE!!
      cache.getCacheConfiguration.memory.evictionStrategy should be(EvictionStrategy.REMOVE)
      cache.getCacheConfiguration.memory.size should be(10L)

      (1 to 50).foreach(i => cache.put(s"key${i}", s"value${i}"))

      cache.size should be(30L)

      println("size = " + cache.size)

      cache.forEach((key, _) => cache.evict(key))
      cache.forEach((key, _) => println(key))

      println("size = " + cache.size)

      cache.size should be(20L)
    }
  }

なんと、敷居値を設定すると、設定ファイル上はNONEを指定しているにも関わらず、REMOVEにされてしまいました。

      // REMOVE!!
      cache.getCacheConfiguration.memory.evictionStrategy should be(EvictionStrategy.REMOVE)
      cache.getCacheConfiguration.memory.size should be(10L)

先ほどと同様に50個のエントリを放り込むと、Evictionを有効にしているので30個しか残りません。

      (1 to 50).foreach(i => cache.put(s"key${i}", s"value${i}"))

      cache.size should be(30L)

      println("size = " + cache.size)

      cache.forEach((key, _) => cache.evict(key))
      cache.forEach((key, _) => println(key))

      println("size = " + cache.size)

      cache.size should be(20L)

Cache#evict後は、20個です。

ここで、InfinispanのEvictionにおける閾値の考え方は、「Node単位の閾値」でした。
Infinispan 9で変わったData ContainerとEviction - CLOVER

つまり、ownersを1にしているがために、Node数が3なので50個のエントリを放り込んでもCacheに残るのは10×3とわかりやすい結果になっているわけですね。
デフォルトのownersは2(バックアップがひとつで、これもEvictionの対象数に含まれる)なので、そのままだとCacheに残るエントリ数がもっと揺れる
結果となります。

で、Cache#evictすると残るのは20個なのですが…どうもデータの操作したCacheのエントリにしか影響していなさそうな…。この点は、また後で。

MANUAL

続いて、MANUAL。

MANUALの意味は、Cache#evictを利用してよいこと以外は、NONEと同じです。こちらを使う場合は、Passivationを有効にしても警告は出ないようです。
https://github.com/infinispan/infinispan/blob/9.2.1.Final/core/src/main/java/org/infinispan/configuration/cache/EvictionConfigurationBuilder.java#L116-L118
https://github.com/infinispan/infinispan/blob/9.2.1.Final/core/src/main/java/org/infinispan/configuration/cache/MemoryConfigurationBuilder.java#L179-L182

Cacheの定義はこちら。

        <distributed-cache name="manualEvictionStrategyCache" owners="1">
            <memory>
                <object strategy="MANUAL" size="10"/>
            </memory>
        </distributed-cache>

Eviction Strategyを「MANUAL」にしている以外、先ほどのNONEと同じです。

結果も、実は一緒だったりします。Eviction StrategyがREMOVEとなってしまうところまで、同じです。

  test("manual eviction strategy, but select remove strategy") {
    withCache[String, String]("manualEvictionStrategyCache", 3) { cache =>
      // REMOVE!!
      cache.getCacheConfiguration.memory.evictionStrategy should be(EvictionStrategy.REMOVE)
      cache.getCacheConfiguration.memory.size should be(10L)

      (1 to 50).foreach(i => cache.put(s"key${i}", s"value${i}"))

      cache.size should be(30L)

      println("size = " + cache.size)

      cache.forEach((key, _) => cache.evict(key))
      cache.forEach((key, _) => println(key))

      println("size = " + cache.size)

      cache.size should be(20L)
    }
  }

Passivationの警告を除いてMANUALとNONEが同じというのは、EvictionStrategyのソースコードを見るとわかります。
https://github.com/infinispan/infinispan/blob/9.2.1.Final/core/src/main/java/org/infinispan/eviction/EvictionStrategy.java#L20-L27

Enumのコンストラクタとしてbooleanの引数exceptionおよびremoveを取るのですが(Exceptionベースなのか、Removeなのかを示す値)、NONEもMANUALも
両方falseで、定義上ほぼ違いがありません。

また、EvictionStrategy#isEnabledでNONEとMANUALが同じように扱われているところからも、そこは伺えることでしょう。
https://github.com/infinispan/infinispan/blob/9.2.1.Final/core/src/main/java/org/infinispan/eviction/EvictionStrategy.java#L50-L52

ちなみにですね、Eviction StrategyをMANUALにしてサイズ制限などをしない場合、MANUALのままにはなるのですが、Cache#evictを
直接使用するとやっぱり警告されたりします…。
https://github.com/infinispan/infinispan/blob/9.2.1.Final/core/src/main/java/org/infinispan/cache/impl/CacheImpl.java#L873-L875

だって、この判定条件ってRemovableBasedなStrategyかどうかで見てますからねぇ。

REMOVE

続いて、REMOVE。とはいっても、先ほどsize指定時にNONEが強制的にREMOVEに変更された結果を見ているので、結果はすでにわかっていることになります。

Cacheの定義。

        <distributed-cache name="removeEvictionStrategyCache" owners="1">
            <memory>
                <object strategy="REMOVE" size="10"/>
            </memory>
        </distributed-cache>

テストコード。

  test("remove eviction strategy") {
    withCache[String, String]("removeEvictionStrategyCache", 3) { cache =>
      cache.getCacheConfiguration.memory.evictionStrategy should be(EvictionStrategy.REMOVE)
      cache.getCacheConfiguration.memory.size should be(10L)

      (1 to 50).foreach(i => cache.put(s"key${i}", s"value${i}"))

      cache.size should be(30L)

      println("size = " + cache.size)

      cache.forEach((key, _) => cache.evict(key))
      cache.forEach((key, _) => println(key))

      println("size = " + cache.size)

      cache.size should be(20L)
    }
  }

ここでは、NONEなどがなぜREMOVEに強制変更されるかを見てみましょう。

解は、こちらにあります。
https://github.com/infinispan/infinispan/blob/9.2.1.Final/core/src/main/java/org/infinispan/configuration/cache/MemoryConfigurationBuilder.java#L175-L177

Evictionが無効な時に、sizeが0より大きい値で指定されていると、強制的にREMOVEが設定されるようになっています。ここで、Evictionが無効な時というのは
EvictionStrategy#isEnabledがfalseを返す時。

つまり、NONEとMANUAL以外の時です。
https://github.com/infinispan/infinispan/blob/9.2.1.Final/core/src/main/java/org/infinispan/eviction/EvictionStrategy.java#L51

EXCEPTION

最後は、EXCEPTION。こちらは、他と少し毛色が変わります。

まずは、Cacheの定義から。

        <distributed-cache name="exceptionEvictionStrategyCache" owners="1">
            <memory>
                <object strategy="EXCEPTION" size="10"/>
            </memory>
            <!-- NON_DURABLE_XA または FULL_XA である必要がある -->
            <transaction mode="NON_DURABLE_XA"/>
        </distributed-cache>

コメントにも書いていますが、トランザクショナルなCacheである必要があり、かつXAが有効であることを要求します。「XAが有効」とは、トランザクション
モードが「NON_DURABLE_XA」(リカバリを無効にしたXA)か、「FULL_XA」のどちらかであることを指します。

これを守らない場合、もれなく例外が飛んできてエラーになります。
https://github.com/infinispan/infinispan/blob/9.2.1.Final/core/src/main/java/org/infinispan/configuration/cache/MemoryConfigurationBuilder.java#L187-L195

今回はAuto Commitなノリで使いましょう。

テストコード。

  test("exception eviction strategy") {
    withCache[String, String]("exceptionEvictionStrategyCache", 3) { cache =>
      cache.getCacheConfiguration.memory.evictionStrategy should be(EvictionStrategy.EXCEPTION)
      cache.getCacheConfiguration.memory.size should be(10L)

      val thrown = the[CacheException] thrownBy (1 to 50).foreach(i => cache.put(s"key${i}", s"value${i}"))
      thrown.getMessage should be("Could not commit implicit transaction")

      thrown.getCause.getCause.getCause match {
        case cause: RemoteException =>
          cause.getMessage should include("ISPN000217: Received exception from")

          val remoteCause = cause.getCause
          remoteCause should be(a[ContainerFullException])
          remoteCause.getMessage should be("ISPN000514: Container eviction limit 10 reached, write operation(s) is blocked")
        case cause: ContainerFullException =>
          cause.getMessage should be("ISPN000514: Container eviction limit 10 reached, write operation(s) is blocked")
        case _ =>
          fail(s"unknown Exception[${thrown.getCause}]")
      }

      cache.size should (be >=24 or be <= 30)

      println("size = " + cache.size)

      cache.forEach((key, _) => cache.evict(key))
      cache.forEach((key, _) => println(cache.get(key)))

      println("size = " + cache.size)

      cache.size should (be >= 14 or be <= 20)
    }
  }

他の例に習って50個のエントリを追加していますが、途中で失敗しています。

      val thrown = the[CacheException] thrownBy (1 to 50).foreach(i => cache.put(s"key${i}", s"value${i}"))
      thrown.getMessage should be("Could not commit implicit transaction")

例外の原因はLocal Node発生したかRemote Nodeで発生したかで見え方が変わりますが、もとをたどると「Containerがいっぱいになった」という例外が
投げられていることがわかります。

      thrown.getCause.getCause.getCause match {
        case cause: RemoteException =>
          cause.getMessage should include("ISPN000217: Received exception from")

          val remoteCause = cause.getCause
          remoteCause should be(a[ContainerFullException])
          remoteCause.getMessage should be("ISPN000514: Container eviction limit 10 reached, write operation(s) is blocked")
        case cause: ContainerFullException =>
          cause.getMessage should be("ISPN000514: Container eviction limit 10 reached, write operation(s) is blocked")
        case _ =>
          fail(s"unknown Exception[${thrown.getCause}]")
      }

もう少し、EXEPTIONなStrategyを追ってみましょう。

Eviction StrategyをEXCEPTIONとすると、InfinispanのInterceptorを構築する際にTransactionalExceptionEvictionInterceptorが追加されます。
https://github.com/infinispan/infinispan/blob/9.2.1.Final/core/src/main/java/org/infinispan/factories/InterceptorChainFactory.java#L241-L246

このTransactionalExceptionEvictionInterceptorで、Evictionで指定した上限を越えていないか確認し、上限に達すると例外をスローするわけです。
https://github.com/infinispan/infinispan/blob/9.2.1.Final/core/src/main/java/org/infinispan/interceptors/impl/TransactionalExceptionEvictionInterceptor.java#L112-L127
https://github.com/infinispan/infinispan/blob/9.2.1.Final/core/src/main/java/org/infinispan/interceptors/impl/TransactionalExceptionEvictionInterceptor.java#L193-L195

各種Strategyの雰囲気は、だいたいわかったのではないでしょうか?

もう少し中身を

それでは、もう少し中身に踏み込んでみましょう。

EvictionStrategyというのは、RemovalBaseかExceptionBaseかのフラグを設定したEnumにすぎないことがわかります。
https://github.com/infinispan/infinispan/blob/9.2.1.Final/core/src/main/java/org/infinispan/eviction/EvictionStrategy.java#L20-L36

   NONE(false, false),
   MANUAL(false, false),
   REMOVE(false, true),
   EXCEPTION(true, false),

EvictionStrategyとして、Evictionが有効かどうかはNONEかMANUAL以外だということは、前に書きました。
https://github.com/infinispan/infinispan/blob/9.2.1.Final/core/src/main/java/org/infinispan/eviction/EvictionStrategy.java#L50-L52

とはいうものの、MemoryConfigurationとして扱った時に、Evictionが有効になっているかどうかというのは、RemovableBasedとなっているかどうかという
判定となるので、この点には注意です。
https://github.com/infinispan/infinispan/blob/9.2.1.Final/core/src/main/java/org/infinispan/configuration/cache/MemoryConfiguration.java#L86-L88

また、Deprecatedとなっていますが、既存のEviction StrategyであるUNORDERERDやFIFO、LRU、LIRSについても宣言としては残っていますが、REMOVEと同じ意味に
なっていますね。
https://github.com/infinispan/infinispan/blob/9.2.1.Final/core/src/main/java/org/infinispan/eviction/EvictionStrategy.java#L11-L18

   @Deprecated
   UNORDERED(false, true),
   @Deprecated
   FIFO(false, true),
   @Deprecated
   LRU(false, true),
   @Deprecated
   LIRS(false, true),

そして、これらのEviction StrategyがDataContainer構築時に利用されます。
https://github.com/infinispan/infinispan/blob/9.2.1.Final/core/src/main/java/org/infinispan/factories/DataContainerFactory.java#L34-L56

Heapを使うデフォルトのDataContainerであれば、Caffeineの設定に反映されるという感じになります。
*Remove Strategyでsizeやcountでの閾値指定の場合
https://github.com/infinispan/infinispan/blob/9.2.1.Final/core/src/main/java/org/infinispan/container/DefaultDataContainer.java#L101-L112

Off-Heapの場合は、自前でした。
https://github.com/infinispan/infinispan/blob/9.2.1.Final/core/src/main/java/org/infinispan/container/offheap/BoundedOffHeapDataContainer.java#L44-L53

Exception Strategyの場合は、Interceptorが例外をスローする、でしたね。
https://github.com/infinispan/infinispan/blob/9.2.1.Final/core/src/main/java/org/infinispan/interceptors/impl/TransactionalExceptionEvictionInterceptor.java#L193-L195

まとめると、こんなところでしょうか。

Cache#evictされるのが、Local Nodeのエントリだけなのはどうして?

Eviction Strategyとは直接関係ありませんが、Cache#evictした時の挙動の話です。

これまで言っていた、Eviction StrategyはあくまでデータをCache#putした時に裏で動くEvictionの仕組みであって、明示的にCache#evictを呼び出した時は
また別の話となります。

これは、最初に全エントリをCache#evictしたのに、けっこうな数のエントリが残ってしまったことが最初どうしてかわからず、途中でPrimary Ownerのデータ以外は
evictしても消えていないという事実になんとなく気付きました。

こういうやつですね。

      (1 to 50).foreach(i => cache.put(s"key${i}", s"value${i}"))

      cache.size should be(30L)

      println("size = " + cache.size)

      cache.forEach((key, _) => cache.evict(key))
      cache.forEach((key, _) => println(key))

      println("size = " + cache.size)

      cache.size should be(20L)

ownersが1のDistributed Cacheに50エントリ放り込み、残るエントリ数が30、これで全キーに対してCache#evictしても、消えているのは1 Node分。
なお、このCache#evictをCache#removeにすると、全エントリがキレイになくなります。

内部的にはCache#removeとCache#evictは、似たような関係にあります。

なにが似てるかって、Cache#removeとCache#evictの内部表現であるRemoveCommandとEvictCommandは継承関係にあるからです。
https://github.com/infinispan/infinispan/blob/9.2.1.Final/core/src/main/java/org/infinispan/commands/write/RemoveCommand.java
https://github.com/infinispan/infinispan/blob/9.2.1.Final/core/src/main/java/org/infinispan/commands/write/EvictCommand.java#L19

では、この差はなにかというとトランザクション系のInterceptorにあります。

関連するのは、このあたりのInterceptor構築のところですね。
https://github.com/infinispan/infinispan/blob/9.2.1.Final/core/src/main/java/org/infinispan/factories/InterceptorChainFactory.java#L288-L329

ここで登場する各種Interceptor…TriangleDistributionInterceptor、VersionedDistributionInterceptor、TxDistributionInterceptorなどいろいろありますが、
これらのInterceptorでRemoveCommandとEvictCommandでは扱いに差があります。

ベースとなるInterceptorの実装に対して、RemoveCommandについてはオーバーライドされており
https://github.com/infinispan/infinispan/blob/9.2.1.Final/core/src/main/java/org/infinispan/interceptors/distribution/TriangleDistributionInterceptor.java#L117-L120
https://github.com/infinispan/infinispan/blob/9.2.1.Final/core/src/main/java/org/infinispan/interceptors/distribution/TxDistributionInterceptor.java#L134-L137

Remote Nodeに対しても処理を行うように実装されています。
https://github.com/infinispan/infinispan/blob/9.2.1.Final/core/src/main/java/org/infinispan/interceptors/distribution/TriangleDistributionInterceptor.java#L380-L404
https://github.com/infinispan/infinispan/blob/9.2.1.Final/core/src/main/java/org/infinispan/interceptors/distribution/TxDistributionInterceptor.java#L389-L416

これに対して、EvictCommandについてはデフォルト実装となっており、Commandを直接実行する流れになります。
https://github.com/infinispan/infinispan/blob/9.2.1.Final/core/src/main/java/org/infinispan/interceptors/DDAsyncInterceptor.java#L93-L96
https://github.com/infinispan/infinispan/blob/9.2.1.Final/core/src/main/java/org/infinispan/interceptors/BaseAsyncInterceptor.java#L51-L61

Cache#evict効果が、Local Nodeでしか反映されなかったのはこのためでしょう。

なお蛇足ですが、SyncなDistributed Cache、Replicated Cacheの場合にバージョン管理が必要だったら…という分岐があり、そうでなかったらAsyncな
Distributed Cache、Replicated Cacheにフォールスルーする記述があるのですが
https://github.com/infinispan/infinispan/blob/9.2.1.Final/core/src/main/java/org/infinispan/factories/InterceptorChainFactory.java#L293-L303

ここでいう「バージョン管理が必要だったら」というのは、トランザクションが有効なことを指しています。
https://github.com/infinispan/infinispan/blob/9.2.1.Final/core/src/main/java/org/infinispan/factories/InterceptorChainFactory.java#L112-L113

なんか、Evictionについていろいろ深堀りすることになりました…。

まとめ

Infinispan 9.2で整理された、Eviction Strategyについて試しつつ、実装を追ってみました。

これまであんまり気にしていなかった、Cache#evictの処理の裏側も見れてちょっと勉強になりました。

今回作成したソースコードは、こちらに置いています。
https://github.com/kazuhira-r/infinispan-getting-started/tree/master/embedded-eviction-strategy