[exo-jcr-commits] exo-jcr SVN: r4587 - kernel/trunk/exo.kernel.component.cache/src/main/java/org/exoplatform/services/cache and 3 other directories.
do-not-reply at jboss.org
do-not-reply at jboss.org
Mon Jul 4 08:56:27 EDT 2011
Author: nfilotto
Date: 2011-07-04 08:56:27 -0400 (Mon, 04 Jul 2011)
New Revision: 4587
Added:
kernel/trunk/exo.kernel.component.cache/src/main/java/org/exoplatform/services/cache/impl/InvalidationExoCache.java
Modified:
jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/kernel/cache.xml
kernel/trunk/exo.kernel.component.cache/src/main/java/org/exoplatform/services/cache/ExoCacheConfig.java
kernel/trunk/exo.kernel.component.cache/src/main/java/org/exoplatform/services/cache/impl/CacheServiceImpl.java
kernel/trunk/exo.kernel.component.ext.cache.impl.infinispan.v4/src/main/java/org/exoplatform/services/cache/impl/infinispan/AbstractExoCache.java
kernel/trunk/exo.kernel.component.ext.cache.impl.jboss.v3/src/test/java/org/exoplatform/services/cache/impl/jboss/TestAbstractExoCache.java
Log:
EXOJCR-1418: Support non-serializable values in distributed eXo caches
The attribute "avoidValueReplication" has been added into ExoCacheConfig to allow to enable the invalidation mode by configuration if needed
Modified: jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/kernel/cache.xml
===================================================================
--- jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/kernel/cache.xml 2011-07-01 14:27:05 UTC (rev 4586)
+++ jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/kernel/cache.xml 2011-07-04 12:56:27 UTC (rev 4587)
@@ -20,7 +20,7 @@
create new <envar>ExoCache</envar> instances. See the below example of
<envar>org.exoplatform.services.cache.CacheService</envar>
definition:</para>
-
+
<programlisting language="xml"> <component>
<key>org.exoplatform.services.cache.CacheService</key>
<jmx-name>cache:type=CacheService</jmx-name>
@@ -40,16 +40,17 @@
</init-params>
</component></programlisting>
- <note>
- <para>The <envar>ExoCacheConfig</envar> which name is
- <envar>default</envar>, will be the default configuration of all the
- <envar>ExoCache</envar> instances that don't have dedicated
- configuration.</para>
- </note>
- <para> See the below example about how to define a new
+ <note>
+ <para>The <envar>ExoCacheConfig</envar> which name is
+ <envar>default</envar>, will be the default configuration of all the
+ <envar>ExoCache</envar> instances that don't have dedicated
+ configuration.</para>
+ </note>
+
+ <para>See the below example about how to define a new
<envar>ExoCacheConfig</envar> thanks to a
<emphasis>external-component-plugin</emphasis>:</para>
-
+
<programlisting language="xml"> <external-component-plugins>
<target-component>org.exoplatform.services.cache.CacheService</target-component>
<component-plugin>
@@ -125,14 +126,14 @@
<entry>distributed</entry>
<entry>Indicates if the cache is distributed. This field is
- optional. This field is used for backward compatibility.</entry>
+ optional. This field is deprecated.</entry>
</row>
<row>
<entry>replicated</entry>
<entry>Indicates if the cache is replicated. This field is
- optional. This field is deprecated.</entry>
+ optional. </entry>
</row>
<row>
@@ -141,11 +142,95 @@
<entry>Indicates if the log is enabled. This field is optional.
This field is used for backward compatibility.</entry>
</row>
+
+ <row>
+ <entry>avoidValueReplication</entry>
+
+ <entry>Indicates whether the values of the cache should be
+ replicated or not in case of a replicated cache. This field is
+ optional. By default it is disabled. Find more details about this
+ field in the next section.</entry>
+ </row>
</tbody>
</tgroup>
</table>
+ </section>
- <para></para>
+ <section>
+ <title>Advanced concepts</title>
+
+ <section>
+ <title>Invalidation</title>
+
+ <para>In case, you have big values or non serializable values and you
+ need a replicated cache to at list invalidate the data when it is
+ needed, you can use the invalidation mode that will work on top of any
+ replicated cache implementations. This is possible thanks to the class
+ <emphasis>InvalidationExoCache</emphasis> which is actually a decorator
+ whose idea is to replicate the the hash code of the value in order to
+ know if it is needed or not to invalidate the local data, if the new
+ hash code of the value is the same as the old value, we assume that it
+ is the same value so we don't invalidate the old value. This is required
+ to avoid the following infinite loop that we will face with invalidation
+ mode proposed out of the box by JBoss Cache for example:</para>
+
+ <orderedlist>
+ <listitem>
+ <para>Cluster node #1 puts (key1, value1) into the cache</para>
+ </listitem>
+
+ <listitem>
+ <para>On cluster node #2 key1 is invalidated by put call in node
+ #1</para>
+ </listitem>
+
+ <listitem>
+ <para>Node #2 re-loads key1 and puts (key1, value1) into the
+ cache</para>
+ </listitem>
+
+ <listitem>
+ <para>On cluster node #1 key1 is invalidated, so we get back to step
+ #1</para>
+ </listitem>
+ </orderedlist>
+
+ <para>In the use case above, thanks to the
+ <emphasis>InvalidationExoCache</emphasis> since the value loaded at step
+ #3 has the same hash code as the value loaded as step #1, the step #4
+ won't invalidate the data on the cluster node #1.</para>
+
+ <para>It exists 2 ways to use the invalidation mode which are the
+ following:</para>
+
+ <orderedlist>
+ <listitem>
+ <para>By configuration: For this you simply need to set the
+ parameter <emphasis>avoidValueReplication</emphasis> to
+ <emphasis>true</emphasis> in your eXo cache configuration, this will
+ indicate the CacheService to wrap your eXo cache instance into an
+ <emphasis>InvalidationExoCache</emphasis>.</para>
+ </listitem>
+
+ <listitem>
+ <para>Programmatically; You can wrap your eXo cache instance into an
+ <emphasis>org.exoplatform.services.cache.impl.InvalidationExoCache</emphasis>
+ yourself using the public constructors that are available. Please
+ note that if you use <emphasis>CacheListeners</emphasis> add them to
+ the InvalidationExoCache instance instead of the nested eXo Cache
+ because the nested eXo Cache will contain only hash codes so the
+ related listeners will get hash codes instead of the real
+ values.</para>
+ </listitem>
+ </orderedlist>
+
+ <note>
+ <para>The invalidation will be efficient if and only if the hash code
+ method is properly implemented, in other words 2 value objects
+ representing the same data will return the same hash code otherwise
+ the infinite loop described above will still be effective.</para>
+ </note>
+ </section>
</section>
<section>
@@ -158,7 +243,7 @@
<para>You just need to implement your own <envar>ExoCacheFactory</envar>
and register it in an eXo container, as described below:</para>
-
+
<programlisting language="java">package org.exoplatform.services.cache;
...
public interface ExoCacheFactory {
@@ -178,7 +263,7 @@
can simply register your factory by adding a file
<emphasis>conf/portal/configuration.xml</emphasis> with a content of the
following type:</para>
-
+
<programlisting language="xml"><configuration>
<component>
<key>org.exoplatform.services.cache.ExoCacheFactory</key>
@@ -188,14 +273,14 @@
</configuration>
</programlisting>
-<note>
- <para>Since kernel 2.3.0-CR1, if the configuration is not a sub class
- of <envar>ExoCacheConfig</envar> and the implementation given in the
- configuration is the full qualified name of an existing implementation
- of eXo Cache, we will assume that the user expects to have an instance
- of this eXo Cache type so we won't use the configured cache
- factory.</para>
- </note>
+ <note>
+ <para>Since kernel 2.3.0-CR1, if the configuration is not a sub class of
+ <envar>ExoCacheConfig</envar> and the implementation given in the
+ configuration is the full qualified name of an existing implementation
+ of eXo Cache, we will assume that the user expects to have an instance
+ of this eXo Cache type so we won't use the configured cache
+ factory.</para>
+ </note>
</section>
<section>
@@ -210,7 +295,7 @@
wish as you can do with any components.</para>
<para>The default configuration of the factory is:</para>
-
+
<programlisting language="xml"><configuration>
<component>
<key>org.exoplatform.services.cache.ExoCacheFactory</key>
@@ -278,7 +363,7 @@
<para>If for a given reason, you need to use a specific configuration
for a cache, you can register one thanks to an "<emphasis>external
plugin</emphasis>", see an example below:</para>
-
+
<programlisting language="xml"><configuration>
...
<external-component-plugins>
@@ -323,9 +408,8 @@
<title>Understanding a cache creator</title>
<para>The factory for jboss cache, delegates the cache creation to
- <envar>ExoCacheCreator</envar> that is defined as
- below:</para>
-
+ <envar>ExoCacheCreator</envar> that is defined as below:</para>
+
<programlisting language="java">package org.exoplatform.services.cache.impl.jboss;
...
public interface ExoCacheCreator {
@@ -387,9 +471,8 @@
<title>Registering a cache creator</title>
<para>You can register any cache creator that you want thanks to an
- <emphasis>"external plugin"</emphasis>, see an example
- below:</para>
-
+ <emphasis>"external plugin"</emphasis>, see an example below:</para>
+
<programlisting language="xml"> <external-component-plugins>
<target-component>org.exoplatform.services.cache.ExoCacheFactory</target-component>
<component-plugin>
@@ -483,7 +566,6 @@
<object type="org.exoplatform.services.cache.impl.jboss.fifo.FIFOExoCacheCreator"></object>
</object-param>
...</programlisting>
-
</section>
<section>
@@ -496,7 +578,6 @@
<object type="org.exoplatform.services.cache.impl.jboss.mru.MRUExoCacheCreator"></object>
</object-param>
...</programlisting>
-
</section>
<section>
@@ -707,56 +788,54 @@
</object-param>
...</programlisting>
-<table>
- <title>Fields description</title>
+ <table>
+ <title>Fields description</title>
- <tgroup cols="2">
- <tbody>
- <row>
- <entry>maxNodes</entry>
+ <tgroup cols="2">
+ <tbody>
+ <row>
+ <entry>maxNodes</entry>
- <entry>This is the maximum number of nodes allowed in
- this region. 0 denotes immediate expiry, -1 denotes no
- limit.</entry>
- </row>
+ <entry>This is the maximum number of nodes allowed in this
+ region. 0 denotes immediate expiry, -1 denotes no
+ limit.</entry>
+ </row>
- <row>
- <entry>minTimeToLive</entry>
+ <row>
+ <entry>minTimeToLive</entry>
- <entry>The minimum amount of time (in milliseconds) that
- a node must be allowed to live after being accessed
- before it is allowed to be considered for eviction. 0
- denotes that this feature is disabled, which is the
- default value.</entry>
- </row>
+ <entry>The minimum amount of time (in milliseconds) that a
+ node must be allowed to live after being accessed before it is
+ allowed to be considered for eviction. 0 denotes that this
+ feature is disabled, which is the default value.</entry>
+ </row>
- <row>
- <entry>maxAge</entry>
+ <row>
+ <entry>maxAge</entry>
- <entry>Lifespan of a node (in milliseconds) regardless
- of idle time before the node is swept away. 0 denotes
- immediate expiry, -1 denotes no limit.</entry>
- </row>
+ <entry>Lifespan of a node (in milliseconds) regardless of idle
+ time before the node is swept away. 0 denotes immediate
+ expiry, -1 denotes no limit.</entry>
+ </row>
- <row>
- <entry>timeToLive</entry>
+ <row>
+ <entry>timeToLive</entry>
- <entry>The amount of time that a node is not written to
- or read (in milliseconds) before the node is swept away.
- 0 denotes immediate expiry, -1 denotes no limit.</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- <itemizedlist>
+ <entry>The amount of time that a node is not written to or
+ read (in milliseconds) before the node is swept away. 0
+ denotes immediate expiry, -1 denotes no limit.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ <itemizedlist>
<listitem>
<para>Old configuration</para>
</listitem>
- </itemizedlist>
+ </itemizedlist>
- <programlisting language="xml">...
+ <programlisting language="xml">...
<object-param>
<name>lru-with-old-config</name>
<description>The lru cache configuration</description>
@@ -769,38 +848,36 @@
</object-param>
...</programlisting>
- <table>
- <title>Fields description</title>
+ <table>
+ <title>Fields description</title>
- <tgroup cols="2">
- <tbody>
- <row>
- <entry>maxSize</entry>
+ <tgroup cols="2">
+ <tbody>
+ <row>
+ <entry>maxSize</entry>
- <entry>This is the maximum number of nodes allowed in this
- region. 0 denotes immediate expiry, -1 denotes no
- limit.</entry>
- </row>
+ <entry>This is the maximum number of nodes allowed in this
+ region. 0 denotes immediate expiry, -1 denotes no
+ limit.</entry>
+ </row>
- <row>
- <entry>liveTime</entry>
+ <row>
+ <entry>liveTime</entry>
- <entry>The minimum amount of time (in seconds) that a node
- must be allowed to live after being accessed before it is
- allowed to be considered for eviction. 0 denotes that this
- feature is disabled, which is the default value.</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
+ <entry>The minimum amount of time (in seconds) that a node
+ must be allowed to live after being accessed before it is
+ allowed to be considered for eviction. 0 denotes that this
+ feature is disabled, which is the default value.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
- <note>
- <para>For the fields <emphasis>maxAge</emphasis> and
- <emphasis>timeToLive</emphasis> needed by JBoss cache, we will
- use the default values provided by the creator.</para>
- </note>
-
-
+ <note>
+ <para>For the fields <emphasis>maxAge</emphasis> and
+ <emphasis>timeToLive</emphasis> needed by JBoss cache, we will use
+ the default values provided by the creator.</para>
+ </note>
</section>
<section>
@@ -811,8 +888,8 @@
<para>New configuration</para>
</listitem>
</itemizedlist>
-
- <programlisting language="xml">...
+
+ <programlisting language="xml">...
<object-param>
<name>fifo</name>
<description>The fifo cache configuration</description>
@@ -824,38 +901,38 @@
</object-param>
...</programlisting>
- <table>
- <title>Fields description</title>
+ <table>
+ <title>Fields description</title>
- <tgroup cols="2">
- <tbody>
- <row>
- <entry>maxNodes</entry>
+ <tgroup cols="2">
+ <tbody>
+ <row>
+ <entry>maxNodes</entry>
- <entry>This is the maximum number of nodes allowed in this
- region. 0 denotes immediate expiry, -1 denotes no
- limit.</entry>
- </row>
+ <entry>This is the maximum number of nodes allowed in this
+ region. 0 denotes immediate expiry, -1 denotes no
+ limit.</entry>
+ </row>
- <row>
- <entry>minTimeToLive</entry>
+ <row>
+ <entry>minTimeToLive</entry>
- <entry>The minimum amount of time (in milliseconds) that a
- node must be allowed to live after being accessed before
- it is allowed to be considered for eviction. 0 denotes
- that this feature is disabled, which is the default
- value.</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- <itemizedlist>
- <listitem>
- <para>Old configuration</para>
- </listitem>
- </itemizedlist>
-
- <programlisting language="xml">...
+ <entry>The minimum amount of time (in milliseconds) that a
+ node must be allowed to live after being accessed before it is
+ allowed to be considered for eviction. 0 denotes that this
+ feature is disabled, which is the default value.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <itemizedlist>
+ <listitem>
+ <para>Old configuration</para>
+ </listitem>
+ </itemizedlist>
+
+ <programlisting language="xml">...
<object-param>
<name>fifo-with-old-config</name>
<description>The fifo cache configuration</description>
@@ -868,30 +945,30 @@
</object-param>
...</programlisting>
- <table>
- <title>Fields description</title>
+ <table>
+ <title>Fields description</title>
- <tgroup cols="2">
- <tbody>
- <row>
- <entry>maxSize</entry>
+ <tgroup cols="2">
+ <tbody>
+ <row>
+ <entry>maxSize</entry>
- <entry>This is the maximum number of nodes allowed in this
- region. 0 denotes immediate expiry, -1 denotes no
- limit.</entry>
- </row>
+ <entry>This is the maximum number of nodes allowed in this
+ region. 0 denotes immediate expiry, -1 denotes no
+ limit.</entry>
+ </row>
- <row>
- <entry>liveTime</entry>
+ <row>
+ <entry>liveTime</entry>
- <entry>The minimum amount of time (in seconds) that a node
- must be allowed to live after being accessed before it is
- allowed to be considered for eviction. 0 denotes that this
- feature is disabled, which is the default value.</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
+ <entry>The minimum amount of time (in seconds) that a node
+ must be allowed to live after being accessed before it is
+ allowed to be considered for eviction. 0 denotes that this
+ feature is disabled, which is the default value.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
</section>
<section>
@@ -902,8 +979,8 @@
<para>New configuration</para>
</listitem>
</itemizedlist>
-
- <programlisting language="xml">...
+
+ <programlisting language="xml">...
<object-param>
<name>mru</name>
<description>The mru cache configuration</description>
@@ -915,39 +992,38 @@
</object-param>
...</programlisting>
- <table>
- <title>Fields description</title>
+ <table>
+ <title>Fields description</title>
- <tgroup cols="2">
- <tbody>
- <row>
- <entry>maxNodes</entry>
+ <tgroup cols="2">
+ <tbody>
+ <row>
+ <entry>maxNodes</entry>
- <entry>This is the maximum number of nodes allowed in this
- region. 0 denotes immediate expiry, -1 denotes no
- limit.</entry>
- </row>
+ <entry>This is the maximum number of nodes allowed in this
+ region. 0 denotes immediate expiry, -1 denotes no
+ limit.</entry>
+ </row>
- <row>
- <entry>minTimeToLive</entry>
+ <row>
+ <entry>minTimeToLive</entry>
- <entry>The minimum amount of time (in milliseconds) that a
- node must be allowed to live after being accessed before
- it is allowed to be considered for eviction. 0 denotes
- that this feature is disabled, which is the default
- value.</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
+ <entry>The minimum amount of time (in milliseconds) that a
+ node must be allowed to live after being accessed before it is
+ allowed to be considered for eviction. 0 denotes that this
+ feature is disabled, which is the default value.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
<itemizedlist>
<listitem>
<para>Old configuration</para>
</listitem>
</itemizedlist>
-
- <programlisting language="xml">...
+
+ <programlisting language="xml">...
<object-param>
<name>mru-with-old-config</name>
<description>The mru cache configuration</description>
@@ -960,30 +1036,30 @@
</object-param>
...</programlisting>
- <table>
- <title>Fields description</title>
+ <table>
+ <title>Fields description</title>
- <tgroup cols="2">
- <tbody>
- <row>
- <entry>maxSize</entry>
+ <tgroup cols="2">
+ <tbody>
+ <row>
+ <entry>maxSize</entry>
- <entry>This is the maximum number of nodes allowed in this
- region. 0 denotes immediate expiry, -1 denotes no
- limit.</entry>
- </row>
+ <entry>This is the maximum number of nodes allowed in this
+ region. 0 denotes immediate expiry, -1 denotes no
+ limit.</entry>
+ </row>
- <row>
- <entry>liveTime</entry>
+ <row>
+ <entry>liveTime</entry>
- <entry>The minimum amount of time (in seconds) that a node
- must be allowed to live after being accessed before it is
- allowed to be considered for eviction. 0 denotes that this
- feature is disabled, which is the default value.</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
+ <entry>The minimum amount of time (in seconds) that a node
+ must be allowed to live after being accessed before it is
+ allowed to be considered for eviction. 0 denotes that this
+ feature is disabled, which is the default value.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
</section>
<section>
@@ -994,8 +1070,8 @@
<para>New configuration</para>
</listitem>
</itemizedlist>
-
- <programlisting language="xml">...
+
+ <programlisting language="xml">...
<object-param>
<name>lfu</name>
<description>The lfu cache configuration</description>
@@ -1008,49 +1084,49 @@
</object-param>
...</programlisting>
- <table>
- <title>Fields description</title>
+ <table>
+ <title>Fields description</title>
- <tgroup cols="2">
- <tbody>
- <row>
- <entry>maxNodes</entry>
+ <tgroup cols="2">
+ <tbody>
+ <row>
+ <entry>maxNodes</entry>
- <entry>This is the maximum number of nodes allowed in this
- region. 0 denotes immediate expiry, -1 denotes no
- limit.</entry>
- </row>
+ <entry>This is the maximum number of nodes allowed in this
+ region. 0 denotes immediate expiry, -1 denotes no
+ limit.</entry>
+ </row>
- <row>
- <entry>minNodes</entry>
+ <row>
+ <entry>minNodes</entry>
- <entry>This is the minimum number of nodes allowed in this
- region. This value determines what the eviction queue
- should prune down to per pass. e.g. If minNodes is 10 and
- the cache grows to 100 nodes, the cache is pruned down to
- the 10 most frequently used nodes when the eviction timer
- makes a pass through the eviction algorithm.</entry>
- </row>
+ <entry>This is the minimum number of nodes allowed in this
+ region. This value determines what the eviction queue should
+ prune down to per pass. e.g. If minNodes is 10 and the cache
+ grows to 100 nodes, the cache is pruned down to the 10 most
+ frequently used nodes when the eviction timer makes a pass
+ through the eviction algorithm.</entry>
+ </row>
- <row>
- <entry>minTimeToLive</entry>
+ <row>
+ <entry>minTimeToLive</entry>
- <entry>The minimum amount of time (in milliseconds) that a
- node must be allowed to live after being accessed before
- it is allowed to be considered for eviction. 0 denotes
- that this feature is disabled, which is the default
- value.</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- <itemizedlist>
- <listitem>
- <para>Old configuration</para>
- </listitem>
- </itemizedlist>
-
- <programlisting language="xml">...
+ <entry>The minimum amount of time (in milliseconds) that a
+ node must be allowed to live after being accessed before it is
+ allowed to be considered for eviction. 0 denotes that this
+ feature is disabled, which is the default value.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <itemizedlist>
+ <listitem>
+ <para>Old configuration</para>
+ </listitem>
+ </itemizedlist>
+
+ <programlisting language="xml">...
<object-param>
<name>lfu-with-old-config</name>
<description>The lfu cache configuration</description>
@@ -1063,37 +1139,36 @@
</object-param>
...</programlisting>
- <table>
- <title>Fields description</title>
+ <table>
+ <title>Fields description</title>
- <tgroup cols="2">
- <tbody>
- <row>
- <entry>maxSize</entry>
+ <tgroup cols="2">
+ <tbody>
+ <row>
+ <entry>maxSize</entry>
- <entry>This is the maximum number of nodes allowed in this
- region. 0 denotes immediate expiry, -1 denotes no
- limit.</entry>
- </row>
+ <entry>This is the maximum number of nodes allowed in this
+ region. 0 denotes immediate expiry, -1 denotes no
+ limit.</entry>
+ </row>
- <row>
- <entry>liveTime</entry>
+ <row>
+ <entry>liveTime</entry>
- <entry>The minimum amount of time (in milliseconds) that a
- node must be allowed to live after being accessed before
- it is allowed to be considered for eviction. 0 denotes
- that this feature is disabled, which is the default
- value.</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
+ <entry>The minimum amount of time (in milliseconds) that a
+ node must be allowed to live after being accessed before it is
+ allowed to be considered for eviction. 0 denotes that this
+ feature is disabled, which is the default value.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
- <para><note>
- <para>For the fields <emphasis>minNodes</emphasis> and
- <emphasis>timeToLive</emphasis> needed by JBoss cache, we will
- use the default values provided by the creator.</para>
- </note></para>
+ <para><note>
+ <para>For the fields <emphasis>minNodes</emphasis> and
+ <emphasis>timeToLive</emphasis> needed by JBoss cache, we will use
+ the default values provided by the creator.</para>
+ </note></para>
</section>
<section>
@@ -1104,8 +1179,8 @@
<para>New configuration</para>
</listitem>
</itemizedlist>
-
- <programlisting language="xml">...
+
+ <programlisting language="xml">...
<object-param>
<name>ea</name>
<description>The ea cache configuration</description>
@@ -1118,46 +1193,45 @@
</object-param>
...</programlisting>
- <table>
- <title>Fields description</title>
+ <table>
+ <title>Fields description</title>
- <tgroup cols="2">
- <tbody>
- <row>
- <entry>maxNodes</entry>
+ <tgroup cols="2">
+ <tbody>
+ <row>
+ <entry>maxNodes</entry>
- <entry>This is the maximum number of nodes allowed in this
- region. 0 denotes immediate expiry, -1 denotes no
- limit.</entry>
- </row>
+ <entry>This is the maximum number of nodes allowed in this
+ region. 0 denotes immediate expiry, -1 denotes no
+ limit.</entry>
+ </row>
- <row>
- <entry>minTimeToLive</entry>
+ <row>
+ <entry>minTimeToLive</entry>
- <entry>The minimum amount of time (in milliseconds) that a
- node must be allowed to live after being accessed before
- it is allowed to be considered for eviction. 0 denotes
- that this feature is disabled, which is the default
- value.</entry>
- </row>
+ <entry>The minimum amount of time (in milliseconds) that a
+ node must be allowed to live after being accessed before it is
+ allowed to be considered for eviction. 0 denotes that this
+ feature is disabled, which is the default value.</entry>
+ </row>
- <row>
- <entry>expirationTimeout</entry>
+ <row>
+ <entry>expirationTimeout</entry>
- <entry>This is the timeout after which the cache entry
- must be evicted.</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
+ <entry>This is the timeout after which the cache entry must be
+ evicted.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
<itemizedlist>
<listitem>
<para>Old configuration</para>
</listitem>
</itemizedlist>
-
- <programlisting language="xml">...
+
+ <programlisting language="xml">...
<object-param>
<name>ea-with-old-config</name>
<description>The ea cache configuration</description>
@@ -1170,38 +1244,36 @@
</object-param>
...</programlisting>
- <table>
- <title>Fields description</title>
+ <table>
+ <title>Fields description</title>
- <tgroup cols="2">
- <tbody>
- <row>
- <entry>maxSize</entry>
+ <tgroup cols="2">
+ <tbody>
+ <row>
+ <entry>maxSize</entry>
- <entry>This is the maximum number of nodes allowed in this
- region. 0 denotes immediate expiry, -1 denotes no
- limit.</entry>
- </row>
+ <entry>This is the maximum number of nodes allowed in this
+ region. 0 denotes immediate expiry, -1 denotes no
+ limit.</entry>
+ </row>
- <row>
- <entry>liveTime</entry>
+ <row>
+ <entry>liveTime</entry>
- <entry>The minimum amount of time (in milliseconds) that a
- node must be allowed to live after being accessed before
- it is allowed to be considered for eviction. 0 denotes
- that this feature is disabled, which is the default
- value.</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
+ <entry>The minimum amount of time (in milliseconds) that a
+ node must be allowed to live after being accessed before it is
+ allowed to be considered for eviction. 0 denotes that this
+ feature is disabled, which is the default value.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
- <para><note>
- <para>For the fields <emphasis>expirationTimeout</emphasis>
- needed by JBoss cache, we will use the default values provided
- by the creator.</para>
- </note></para>
-
+ <para><note>
+ <para>For the fields <emphasis>expirationTimeout</emphasis> needed
+ by JBoss cache, we will use the default values provided by the
+ creator.</para>
+ </note></para>
</section>
</section>
</section>
@@ -1218,7 +1290,7 @@
if you wish as you can do with any components.</para>
<para>The default configuration of the factory is:</para>
-
+
<programlisting language="xml"><configuration>
<component>
<key>org.exoplatform.services.cache.ExoCacheFactory</key>
@@ -1241,12 +1313,13 @@
<para>The default configuration template aims to be the skeleton from
which we will create any type of infinispan cache instance, thus it must
- be very generic.</para>
+ be very generic.</para>
+
<note>
- <para>All the cache instances that will rely on this cache
- configuration will share the same
- <envar>EmbeddedCacheManager.</envar></para>
- </note>
+ <para>All the cache instances that will rely on this cache
+ configuration will share the same
+ <envar>EmbeddedCacheManager.</envar></para>
+ </note>
</section>
<section>
@@ -1255,7 +1328,7 @@
<para>If for a given reason, you need to use a specific configuration
for a cache, you can register one thanks to an "<emphasis>external
plugin</emphasis>", see an example below:</para>
-
+
<programlisting language="xml"><configuration>
...
<external-component-plugins>
@@ -1306,9 +1379,8 @@
<title>Understanding a cache creator</title>
<para>The factory for infinispan, delegates the cache creation to
- <envar>ExoCacheCreator</envar> that is defined as
- below:</para>
-
+ <envar>ExoCacheCreator</envar> that is defined as below:</para>
+
<programlisting language="java">package org.exoplatform.services.cache.impl.infinispan;
...
public interface ExoCacheCreator {
@@ -1374,9 +1446,8 @@
<title>Register a cache creator</title>
<para>You can register any cache creator you want thanks to an
- <emphasis>"external plugin"</emphasis>, see an example
- below:</para>
-
+ <emphasis>"external plugin"</emphasis>, see an example below:</para>
+
<programlisting language="xml"> <external-component-plugins>
<target-component>org.exoplatform.services.cache.ExoCacheFactory</target-component>
<component-plugin>
@@ -1535,8 +1606,8 @@
<para>New configuration</para>
</listitem>
</itemizedlist>
-
- <programlisting language="xml">...
+
+ <programlisting language="xml">...
<object-param>
<name>myCache</name>
<description>My cache configuration</description>
@@ -1550,67 +1621,65 @@
</object>
</object-param>
...</programlisting>
- <table>
- <title>Fields description</title>
- <tgroup cols="2">
- <tbody>
- <row>
- <entry>strategy</entry>
+ <table>
+ <title>Fields description</title>
- <entry>The name of the strategy to use such as
- 'UNORDERED', 'FIFO', 'LRU', 'LIRS' and 'NONE' (to
- disable eviction).</entry>
- </row>
+ <tgroup cols="2">
+ <tbody>
+ <row>
+ <entry>strategy</entry>
- <row>
- <entry>maxEntries</entry>
+ <entry>The name of the strategy to use such as 'UNORDERED',
+ 'FIFO', 'LRU', 'LIRS' and 'NONE' (to disable
+ eviction).</entry>
+ </row>
- <entry>Maximum number of entries in a cache instance. If
- selected value is not a power of two the actual value
- will default to the least power of two larger than
- selected value. -1 means no limit which is also the
- default value.</entry>
- </row>
+ <row>
+ <entry>maxEntries</entry>
- <row>
- <entry>lifespan</entry>
+ <entry>Maximum number of entries in a cache instance. If
+ selected value is not a power of two the actual value will
+ default to the least power of two larger than selected value.
+ -1 means no limit which is also the default value.</entry>
+ </row>
- <entry>Maximum lifespan of a cache entry, after which
- the entry is expired cluster-wide, in milliseconds. -1
- means the entries never expire which is also the default
- value.</entry>
- </row>
+ <row>
+ <entry>lifespan</entry>
- <row>
- <entry>maxIdle</entry>
+ <entry>Maximum lifespan of a cache entry, after which the
+ entry is expired cluster-wide, in milliseconds. -1 means the
+ entries never expire which is also the default value.</entry>
+ </row>
- <entry>Maximum idle time a cache entry will be
- maintained in the cache, in milliseconds. If the idle
- time is exceeded, the entry will be expired
- cluster-wide. -1 means the entries never expire which is
- also the default value.</entry>
- </row>
+ <row>
+ <entry>maxIdle</entry>
- <row>
- <entry>wakeUpInterval</entry>
+ <entry>Maximum idle time a cache entry will be maintained in
+ the cache, in milliseconds. If the idle time is exceeded, the
+ entry will be expired cluster-wide. -1 means the entries never
+ expire which is also the default value.</entry>
+ </row>
- <entry>Interval between subsequent eviction runs, in
- milliseconds. If you wish to disable the periodic
- eviction process altogether, set wakeupInterval to -1.
- The default value is 5000.</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
+ <row>
+ <entry>wakeUpInterval</entry>
+
+ <entry>Interval between subsequent eviction runs, in
+ milliseconds. If you wish to disable the periodic eviction
+ process altogether, set wakeupInterval to -1. The default
+ value is 5000.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
<itemizedlist>
<listitem>
<para>Old configuration</para>
</listitem>
</itemizedlist>
- <programlisting language="xml">...
+ <programlisting language="xml">...
<object-param>
<name>myCache</name>
<description>My cache configuration</description>
@@ -1622,48 +1691,45 @@
</object-param>
...</programlisting>
- <table>
- <title>Fields description</title>
+ <table>
+ <title>Fields description</title>
- <tgroup cols="2">
- <tbody>
- <row>
- <entry>maxSize</entry>
+ <tgroup cols="2">
+ <tbody>
+ <row>
+ <entry>maxSize</entry>
- <entry>Maximum number of entries in a cache instance. If
- selected value is not a power of two the actual value will
- default to the least power of two larger than selected
- value. -1 means no limit which is also the default
- value.</entry>
- </row>
+ <entry>Maximum number of entries in a cache instance. If
+ selected value is not a power of two the actual value will
+ default to the least power of two larger than selected value.
+ -1 means no limit which is also the default value.</entry>
+ </row>
- <row>
- <entry>liveTime</entry>
+ <row>
+ <entry>liveTime</entry>
- <entry>Maximum lifespan of a cache entry, after which the
- entry is expired cluster-wide, in milliseconds. -1 means
- the entries never expire which is also the default
- value.</entry>
- </row>
+ <entry>Maximum lifespan of a cache entry, after which the
+ entry is expired cluster-wide, in milliseconds. -1 means the
+ entries never expire which is also the default value.</entry>
+ </row>
- <row>
- <entry>implementation</entry>
+ <row>
+ <entry>implementation</entry>
- <entry>The name of the implementation to use the expected
- value is one of the eviction strategies defined in the
- field <emphasis>implementations</emphasis> of the generic
- cache creator.</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
+ <entry>The name of the implementation to use the expected
+ value is one of the eviction strategies defined in the field
+ <emphasis>implementations</emphasis> of the generic cache
+ creator.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
- <para><note>
- <para>For the fields <emphasis>maxIdle</emphasis> and
- <emphasis>wakeUpInterval</emphasis> needed by infinispan, we
- will use the default values provided by the creator.</para>
- </note></para>
-
+ <para><note>
+ <para>For the fields <emphasis>maxIdle</emphasis> and
+ <emphasis>wakeUpInterval</emphasis> needed by infinispan, we will
+ use the default values provided by the creator.</para>
+ </note></para>
</section>
</section>
</section>
Modified: kernel/trunk/exo.kernel.component.cache/src/main/java/org/exoplatform/services/cache/ExoCacheConfig.java
===================================================================
--- kernel/trunk/exo.kernel.component.cache/src/main/java/org/exoplatform/services/cache/ExoCacheConfig.java 2011-07-01 14:27:05 UTC (rev 4586)
+++ kernel/trunk/exo.kernel.component.cache/src/main/java/org/exoplatform/services/cache/ExoCacheConfig.java 2011-07-04 12:56:27 UTC (rev 4587)
@@ -68,6 +68,11 @@
*/
private boolean logEnabled;
+ /**
+ * Indicates whether or not the replication of the values should be avoided
+ */
+ public boolean avoidValueReplication;
+
public String getName()
{
return name;
@@ -147,8 +152,24 @@
{
this.logEnabled = enableLogging;
}
+
+ /**
+ * @return the avoidValueReplication
+ */
+ public boolean avoidValueReplication()
+ {
+ return avoidValueReplication;
+ }
/**
+ * @param avoidValueReplication the avoidValueReplication to set
+ */
+ public void setAvoidValueReplication(boolean avoidValueReplication)
+ {
+ this.avoidValueReplication = avoidValueReplication;
+ }
+
+ /**
* @see java.lang.Object#clone()
*/
@Override
Modified: kernel/trunk/exo.kernel.component.cache/src/main/java/org/exoplatform/services/cache/impl/CacheServiceImpl.java
===================================================================
--- kernel/trunk/exo.kernel.component.cache/src/main/java/org/exoplatform/services/cache/impl/CacheServiceImpl.java 2011-07-01 14:27:05 UTC (rev 4586)
+++ kernel/trunk/exo.kernel.component.cache/src/main/java/org/exoplatform/services/cache/impl/CacheServiceImpl.java 2011-07-04 12:56:27 UTC (rev 4587)
@@ -154,6 +154,7 @@
return null;
}
+ @SuppressWarnings({"rawtypes", "unchecked"})
private ExoCache<? extends Serializable, ?> createCacheInstance(String region) throws Exception
{
ExoCacheConfig config = configs_.get(region);
@@ -198,7 +199,9 @@
{
managed.registerCache(simple);
}
- return simple;
+ // If the flag avoid value replication is enabled we wrap the eXo cache instance
+ // into an InvalidationExoCache to enable the invalidation
+ return safeConfig.avoidValueReplication() ? new InvalidationExoCache(simple) : simple;
}
public Collection<ExoCache<? extends Serializable, ?>> getAllCacheInstances()
Added: kernel/trunk/exo.kernel.component.cache/src/main/java/org/exoplatform/services/cache/impl/InvalidationExoCache.java
===================================================================
--- kernel/trunk/exo.kernel.component.cache/src/main/java/org/exoplatform/services/cache/impl/InvalidationExoCache.java (rev 0)
+++ kernel/trunk/exo.kernel.component.cache/src/main/java/org/exoplatform/services/cache/impl/InvalidationExoCache.java 2011-07-04 12:56:27 UTC (rev 4587)
@@ -0,0 +1,560 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.cache.impl;
+
+import org.exoplatform.services.cache.CacheListener;
+import org.exoplatform.services.cache.CacheListenerContext;
+import org.exoplatform.services.cache.CachedObjectSelector;
+import org.exoplatform.services.cache.ExoCache;
+import org.exoplatform.services.cache.ObjectCacheInfo;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * This eXo cache type is a decorator allowing ExoCache instances that have
+ * big values or non serializable values to be replicated thanks to an invalidation
+ * mechanism. To prevent infinite loop described below, we replicate the hash code of
+ * the value such that if the hash code is the same, we don't invalidate the value locally
+ * <ul>
+ * <li>Cluster node #1 puts (key1, value1) into the cache</li>
+ * <li>On cluster node #2 key1 is invalidated by the put call in node #1</li>
+ * <li>Node #2 re-loads key1 and puts (key1, value1) into the cache</li>
+ * <li>On cluster node #1 key1 is invalidated, so we get back to step #1</li>
+ * </ul>
+ *
+ * @author <a href="mailto:nfilotto at exoplatform.com">Nicolas Filotto</a>
+ * @version $Id$
+ *
+ */
+public class InvalidationExoCache<K extends Serializable, V> implements ExoCache<K, V>, CacheListener<K, InvalidationExoCache.HashCode<V>>
+{
+ /**
+ * Logger.
+ */
+ private static final Log LOG = ExoLogger.getLogger("exo.kernel.component.cache.InvalidationExoCache");
+
+ /**
+ * The eXo cache instance that we would like to replicate using the invalidation
+ * mechanism
+ */
+ private final ExoCache<K, HashCode<V>> delegate;
+
+ /**
+ * The listeners of the cache
+ */
+ private final CopyOnWriteArrayList<CacheListener<? super K, ? super V>> listeners;
+
+ /**
+ * The local cache that contains the real values
+ */
+ private final ConcurrentMap<K, V> localCache;
+
+ /**
+ * @param delegate the underneath eXo cache instance, we assume that the eXo cache
+ * implementation behind is fully functional.
+ */
+ public InvalidationExoCache(ExoCache<K, V> delegate)
+ {
+ this(delegate, 16);
+ }
+
+ /**
+ * @param delegate the underneath eXo cache instance, we assume that the eXo cache
+ * implementation behind is fully functional.
+ * @concurrencyLevel the estimated number of concurrently
+ * updating threads. The implementation performs internal sizing
+ * to try to accommodate this many threads.
+ */
+ @SuppressWarnings("unchecked")
+ public InvalidationExoCache(ExoCache<K, V> delegate, int concurrencyLevel)
+ {
+ this.delegate = (ExoCache<K, HashCode<V>>)delegate;
+ // We listen to the cache in order to get a callbacks in case of internal puts for example
+ this.delegate.addCacheListener(this);
+ this.listeners = new CopyOnWriteArrayList<CacheListener<? super K, ? super V>>();
+ this.localCache = new ConcurrentHashMap<K, V>(concurrencyLevel, 0.75f, concurrencyLevel);
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#getName()
+ */
+ public String getName()
+ {
+ return delegate.getName();
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#setName(java.lang.String)
+ */
+ public void setName(String name)
+ {
+ delegate.setName(name);
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#getLabel()
+ */
+ public String getLabel()
+ {
+ return delegate.getLabel();
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#setLabel(java.lang.String)
+ */
+ public void setLabel(String s)
+ {
+ delegate.setLabel(s);
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#get(java.io.Serializable)
+ */
+ public V get(Serializable name)
+ {
+ HashCode<V> result = delegate.get(name);
+ return result == null ? null : localCache.get(name);
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#remove(java.io.Serializable)
+ */
+ public V remove(Serializable key) throws NullPointerException
+ {
+ V value = localCache.get(key);
+ delegate.remove(key);
+ return value;
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#put(java.io.Serializable, java.lang.Object)
+ */
+ public void put(K key, V value) throws NullPointerException
+ {
+ delegate.put(key, new HashCode<V>(value));
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#putMap(java.util.Map)
+ */
+ public void putMap(Map<? extends K, ? extends V> objs) throws NullPointerException, IllegalArgumentException
+ {
+ if (objs == null)
+ {
+ throw new NullPointerException("No null map accepted");
+ }
+ Map<K, HashCode<V>> map = new LinkedHashMap<K, HashCode<V>>();
+ for (Entry<? extends K, ? extends V> entry : objs.entrySet())
+ {
+ if (entry.getKey() == null)
+ {
+ throw new IllegalArgumentException("No null cache key accepted");
+ }
+ else if (entry.getValue() == null)
+ {
+ throw new IllegalArgumentException("No null cache value accepted");
+ }
+ map.put(entry.getKey(), new HashCode<V>(entry.getValue()));
+ }
+ delegate.putMap(map);
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#clearCache()
+ */
+ public void clearCache()
+ {
+ delegate.clearCache();
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#select(org.exoplatform.services.cache.CachedObjectSelector)
+ */
+ public void select(CachedObjectSelector<? super K, ? super V> selector) throws Exception
+ {
+ if (selector == null)
+ {
+ throw new IllegalArgumentException("No null selector");
+ }
+ for (Entry<K, V> entry : localCache.entrySet())
+ {
+ final K key = entry.getKey();
+ final V value = entry.getValue();
+ ObjectCacheInfo<V> info = new ObjectCacheInfo<V>()
+ {
+ public V get()
+ {
+ return value;
+ }
+
+ public long getExpireTime()
+ {
+ // Cannot know: The expire time is managed by JBoss Cache itself
+ return -1;
+ }
+ };
+ if (selector.select(key, info))
+ {
+ selector.onSelect(this, key, info);
+ }
+ }
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#getCacheSize()
+ */
+ public int getCacheSize()
+ {
+ return localCache.size();
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#getMaxSize()
+ */
+ public int getMaxSize()
+ {
+ return delegate.getMaxSize();
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#setMaxSize(int)
+ */
+ public void setMaxSize(int max)
+ {
+ delegate.setMaxSize(max);
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#getLiveTime()
+ */
+ public long getLiveTime()
+ {
+ return delegate.getLiveTime();
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#setLiveTime(long)
+ */
+ public void setLiveTime(long period)
+ {
+ delegate.setLiveTime(period);
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#getCacheHit()
+ */
+ public int getCacheHit()
+ {
+ return delegate.getCacheHit();
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#getCacheMiss()
+ */
+ public int getCacheMiss()
+ {
+ return delegate.getCacheMiss();
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#getCachedObjects()
+ */
+ public List<? extends V> getCachedObjects()
+ {
+ return new ArrayList<V>(localCache.values());
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#removeCachedObjects()
+ */
+ public List<? extends V> removeCachedObjects()
+ {
+ final List<? extends V> list = getCachedObjects();
+ clearCache();
+ return list;
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#addCacheListener(org.exoplatform.services.cache.CacheListener)
+ */
+ public void addCacheListener(CacheListener<? super K, ? super V> listener) throws NullPointerException
+ {
+ if (listener == null)
+ {
+ throw new NullPointerException();
+ }
+ listeners.add(listener);
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#isLogEnabled()
+ */
+ public boolean isLogEnabled()
+ {
+ return delegate.isLogEnabled();
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.ExoCache#setLogEnabled(boolean)
+ */
+ public void setLogEnabled(boolean b)
+ {
+ delegate.setLogEnabled(b);
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.CacheListener#onExpire(org.exoplatform.services.cache.CacheListenerContext, java.io.Serializable, java.lang.Object)
+ */
+ public void onExpire(CacheListenerContext context, K key, HashCode<V> obj) throws Exception
+ {
+ V value = localCache.remove(key);
+ if (listeners.isEmpty())
+ {
+ return;
+ }
+ for (CacheListener<? super K, ? super V> listener : listeners)
+ {
+ try
+ {
+ listener.onExpire(context, key, value);
+ }
+ catch (Exception e)
+ {
+ if (LOG.isWarnEnabled())
+ LOG.warn("Cannot execute the CacheListener properly", e);
+ }
+ }
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.CacheListener#onRemove(org.exoplatform.services.cache.CacheListenerContext, java.io.Serializable, java.lang.Object)
+ */
+ public void onRemove(CacheListenerContext context, K key, HashCode<V> obj) throws Exception
+ {
+ V value = localCache.remove(key);
+ if (listeners.isEmpty())
+ {
+ return;
+ }
+ for (CacheListener<? super K, ? super V> listener : listeners)
+ {
+ try
+ {
+ listener.onRemove(context, key, value);
+ }
+ catch (Exception e)
+ {
+ if (LOG.isWarnEnabled())
+ LOG.warn("Cannot execute the CacheListener properly", e);
+ }
+ }
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.CacheListener#onPut(org.exoplatform.services.cache.CacheListenerContext, java.io.Serializable, java.lang.Object)
+ */
+ public void onPut(CacheListenerContext context, K key, HashCode<V> obj) throws Exception
+ {
+ V value = obj.getValue();
+ if (value != null)
+ {
+ // we assume that it is a local put since the value is inside the HashCode object
+ localCache.put(key, value);
+ }
+ else
+ {
+ // we assume that it is a remote put since the value is not inside the HashCode object
+ V currentValue = localCache.get(key);
+ if (currentValue != null && obj != null && currentValue.hashCode() == obj.hashCode())
+ {
+ // We assume that it is the same value so we don't change the value in the cache
+ value = currentValue;
+ }
+ else
+ {
+ // A new value has been added to the cache so we invalidate the local one
+ value = null;
+ localCache.remove(key);
+ }
+ }
+ if (listeners.isEmpty())
+ {
+ return;
+ }
+ for (CacheListener<? super K, ? super V> listener : listeners)
+ try
+ {
+ listener.onPut(context, key, value);
+ }
+ catch (Exception e)
+ {
+ if (LOG.isWarnEnabled())
+ LOG.warn("Cannot execute the CacheListener properly", e);
+ }
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.CacheListener#onGet(org.exoplatform.services.cache.CacheListenerContext, java.io.Serializable, java.lang.Object)
+ */
+ public void onGet(CacheListenerContext context, K key, HashCode<V> obj) throws Exception
+ {
+ if (listeners.isEmpty())
+ {
+ return;
+ }
+ V value = obj == null ? null : localCache.get(key);
+ for (CacheListener<? super K, ? super V> listener : listeners)
+ try
+ {
+ listener.onGet(context, key, value);
+ }
+ catch (Exception e)
+ {
+ if (LOG.isWarnEnabled())
+ LOG.warn("Cannot execute the CacheListener properly", e);
+ }
+ }
+
+ /**
+ * @see org.exoplatform.services.cache.CacheListener#onClearCache(org.exoplatform.services.cache.CacheListenerContext)
+ */
+ public void onClearCache(CacheListenerContext context) throws Exception
+ {
+ localCache.clear();
+ if (listeners.isEmpty())
+ {
+ return;
+ }
+ for (CacheListener<? super K, ? super V> listener : listeners)
+ {
+ try
+ {
+ listener.onClearCache(context);
+ }
+ catch (Exception e)
+ {
+ if (LOG.isWarnEnabled())
+ LOG.warn("Cannot execute the CacheListener properly", e);
+ }
+ }
+ }
+
+ /**
+ * We use this class to propagate the hash code of the value efficiently over the network
+ */
+ public static class HashCode<V> implements Externalizable
+ {
+ /**
+ * The hash code of the value
+ */
+ private int hashCode;
+
+ /**
+ * The corresponding value
+ */
+ private V value;
+
+ public HashCode() {}
+
+ public HashCode(V value)
+ {
+ this.hashCode = value.hashCode();
+ this.value = value;
+ }
+
+ /**
+ * @return the value
+ */
+ public V getValue()
+ {
+ return value;
+ }
+
+ /**
+ * @see java.io.Externalizable#writeExternal(java.io.ObjectOutput)
+ */
+ public void writeExternal(ObjectOutput out) throws IOException
+ {
+ out.writeInt(hashCode);
+ }
+
+ /**
+ * @see java.io.Externalizable#readExternal(java.io.ObjectInput)
+ */
+ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
+ {
+ this.hashCode = in.readInt();
+ }
+
+ /**
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode()
+ {
+ return hashCode;
+ }
+
+ /**
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ @SuppressWarnings("rawtypes")
+ HashCode other = (HashCode)obj;
+ if (hashCode != other.hashCode)
+ return false;
+ if (value != null && other.value != null)
+ {
+ return value.equals(other.value);
+ }
+ return true;
+ }
+
+ /**
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString()
+ {
+ return "HashCode [hashCode=" + hashCode + ", value=" + value + "]";
+ }
+ }
+}
Modified: kernel/trunk/exo.kernel.component.ext.cache.impl.infinispan.v4/src/main/java/org/exoplatform/services/cache/impl/infinispan/AbstractExoCache.java
===================================================================
--- kernel/trunk/exo.kernel.component.ext.cache.impl.infinispan.v4/src/main/java/org/exoplatform/services/cache/impl/infinispan/AbstractExoCache.java 2011-07-01 14:27:05 UTC (rev 4586)
+++ kernel/trunk/exo.kernel.component.ext.cache.impl.infinispan.v4/src/main/java/org/exoplatform/services/cache/impl/infinispan/AbstractExoCache.java 2011-07-04 12:56:27 UTC (rev 4587)
@@ -31,8 +31,10 @@
import org.infinispan.Cache;
import org.infinispan.context.Flag;
import org.infinispan.notifications.Listener;
+import org.infinispan.notifications.cachelistener.annotation.CacheEntryEvicted;
import org.infinispan.notifications.cachelistener.annotation.CacheEntryModified;
import org.infinispan.notifications.cachelistener.annotation.CacheEntryRemoved;
+import org.infinispan.notifications.cachelistener.event.CacheEntryEvictedEvent;
import org.infinispan.notifications.cachelistener.event.CacheEntryModifiedEvent;
import org.infinispan.notifications.cachelistener.event.CacheEntryRemovedEvent;
@@ -472,18 +474,21 @@
@Listener
public class CacheEventListener
{
-// Infinispan triggers a CacheEntryEvictedEvent only at explicit eviction which is
-// not what we want here. So it will be considered as non supported
-// @CacheEntryEvicted
-// public void cacheEntryEvicted(CacheEntryEvictedEvent evt)
-// {
-// if (evt.isPre())
-// {
-// final K key = (K)evt.getKey();
-// final V value = cache.withFlags(Flag.SKIP_LOCKING).get(key);
-// onExpire(key, value);
-// }
-// }
+ /**
+ * Warning Infinispan triggers a <code>CacheEntryEvictedEvent</code> only at explicit eviction
+ * that is done lazily which is not exactly what we expect, we still use it to be
+ * able to use it with <code>avoidValueReplication</code> set to <code>true</code>.
+ */
+ @CacheEntryEvicted
+ public void cacheEntryEvicted(CacheEntryEvictedEvent evt)
+ {
+ if (evt.isPre())
+ {
+ final K key = (K)evt.getKey();
+ final V value = cache.withFlags(Flag.SKIP_LOCKING).get(key);
+ onExpire(key, value);
+ }
+ }
@CacheEntryRemoved
public void cacheEntryRemoved(CacheEntryRemovedEvent evt)
Modified: kernel/trunk/exo.kernel.component.ext.cache.impl.jboss.v3/src/test/java/org/exoplatform/services/cache/impl/jboss/TestAbstractExoCache.java
===================================================================
--- kernel/trunk/exo.kernel.component.ext.cache.impl.jboss.v3/src/test/java/org/exoplatform/services/cache/impl/jboss/TestAbstractExoCache.java 2011-07-01 14:27:05 UTC (rev 4586)
+++ kernel/trunk/exo.kernel.component.ext.cache.impl.jboss.v3/src/test/java/org/exoplatform/services/cache/impl/jboss/TestAbstractExoCache.java 2011-07-04 12:56:27 UTC (rev 4587)
@@ -31,6 +31,7 @@
import org.exoplatform.services.cache.ExoCacheFactory;
import org.exoplatform.services.cache.ExoCacheInitException;
import org.exoplatform.services.cache.ObjectCacheInfo;
+import org.exoplatform.services.cache.impl.InvalidationExoCache;
import org.exoplatform.services.cache.impl.jboss.lru.LRUExoCacheCreator;
import org.exoplatform.test.BasicTestCase;
@@ -41,8 +42,8 @@
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
-import java.util.Map.Entry;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
@@ -270,17 +271,17 @@
config2.setLiveTime(1);
config2.setImplementation("LRU");
config2.setDistributed(true);
- AbstractExoCache<Serializable, Object> cache1 =
- (AbstractExoCache<Serializable, Object>)getExoCacheFactoryInstance().createCache(config);
- MyCacheListener listener1 = new MyCacheListener();
+ AbstractExoCache<Serializable, String> cache1 =
+ (AbstractExoCache<Serializable, String>)getExoCacheFactoryInstance().createCache(config);
+ MyCacheListener<String> listener1 = new MyCacheListener<String>();
cache1.addCacheListener(listener1);
- AbstractExoCache<Serializable, Object> cache2 =
- (AbstractExoCache<Serializable, Object>)getExoCacheFactoryInstance().createCache(config);
- MyCacheListener listener2 = new MyCacheListener();
+ AbstractExoCache<Serializable, String> cache2 =
+ (AbstractExoCache<Serializable, String>)getExoCacheFactoryInstance().createCache(config);
+ MyCacheListener<String> listener2 = new MyCacheListener<String>();
cache2.addCacheListener(listener2);
- AbstractExoCache<Serializable, Object> cache3 =
- (AbstractExoCache<Serializable, Object>)getExoCacheFactoryInstance().createCache(config2);
- MyCacheListener listener3 = new MyCacheListener();
+ AbstractExoCache<Serializable, String> cache3 =
+ (AbstractExoCache<Serializable, String>)getExoCacheFactoryInstance().createCache(config2);
+ MyCacheListener<String> listener3 = new MyCacheListener<String>();
cache3.addCacheListener(listener3);
try
{
@@ -358,7 +359,7 @@
assertEquals(1, listener1.clearCache);
assertEquals(0, listener2.clearCache);
assertEquals(0, listener3.clearCache);
- Map<Serializable, Object> values = new HashMap<Serializable, Object>();
+ Map<Serializable, String> values = new HashMap<Serializable, String>();
values.put(new MyKey("a"), "a");
values.put(new MyKey("b"), "b");
cache1.putMap(values);
@@ -379,22 +380,22 @@
assertEquals(1, listener1.clearCache);
assertEquals(0, listener2.clearCache);
assertEquals(0, listener3.clearCache);
- values = new HashMap<Serializable, Object>()
+ values = new HashMap<Serializable, String>()
{
private static final long serialVersionUID = 1L;
- public Set<Entry<Serializable, Object>> entrySet()
+ public Set<Entry<Serializable, String>> entrySet()
{
- Set<Entry<Serializable, Object>> set = new LinkedHashSet<Entry<Serializable, Object>>(super.entrySet());
- set.add(new Entry<Serializable, Object>()
+ Set<Entry<Serializable, String>> set = new LinkedHashSet<Entry<Serializable, String>>(super.entrySet());
+ set.add(new Entry<Serializable, String>()
{
- public Object setValue(Object paramV)
+ public String setValue(String paramV)
{
return null;
}
- public Object getValue()
+ public String getValue()
{
throw new RuntimeException("An exception");
}
@@ -456,6 +457,247 @@
}
}
+ @SuppressWarnings("unchecked")
+ public void testDistributedCacheWithNSValues() throws Exception
+ {
+ System.out
+ .println("WARNING: For Linux distributions the following JVM parameter must be set to true, java.net.preferIPv4Stack = "
+ + System.getProperty("java.net.preferIPv4Stack"));
+ ExoCacheConfig config = new ExoCacheConfig();
+ config.setName("MyCacheDistributedWithNSValues");
+ config.setMaxSize(5);
+ config.setLiveTime(1);
+ config.setImplementation("LRU");
+ config.setDistributed(true);
+ config.setAvoidValueReplication(true);
+ ExoCacheConfig config2 = new ExoCacheConfig();
+ config2.setName("MyCacheDistributedWithNSValues2");
+ config2.setMaxSize(5);
+ config2.setLiveTime(1);
+ config2.setImplementation("LRU");
+ config2.setDistributed(true);
+ config2.setAvoidValueReplication(true);
+ AbstractExoCache<Serializable, MyNonSerializableValue> acache1 =
+ (AbstractExoCache<Serializable, MyNonSerializableValue>)getExoCacheFactoryInstance().createCache(config);
+ MyCacheListener<MyNonSerializableValue> listener1 = new MyCacheListener<MyNonSerializableValue>();
+ ExoCache<Serializable, MyNonSerializableValue> cache1 = new InvalidationExoCache<Serializable, MyNonSerializableValue>(acache1);
+ cache1.addCacheListener(listener1);
+ AbstractExoCache<Serializable, MyNonSerializableValue> acache2 =
+ (AbstractExoCache<Serializable, MyNonSerializableValue>)getExoCacheFactoryInstance().createCache(config);
+ MyCacheListener<MyNonSerializableValue> listener2 = new MyCacheListener<MyNonSerializableValue>();
+ ExoCache<Serializable, MyNonSerializableValue> cache2 = new InvalidationExoCache<Serializable, MyNonSerializableValue>(acache2);
+ cache2.addCacheListener(listener2);
+ AbstractExoCache<Serializable, MyNonSerializableValue> acache3 =
+ (AbstractExoCache<Serializable, MyNonSerializableValue>)getExoCacheFactoryInstance().createCache(config2);
+ MyCacheListener<MyNonSerializableValue> listener3 = new MyCacheListener<MyNonSerializableValue>();
+ ExoCache<Serializable, MyNonSerializableValue> cache3 = new InvalidationExoCache<Serializable, MyNonSerializableValue>(acache3);
+ cache3.addCacheListener(listener3);
+ try
+ {
+ cache1.put(new MyKey("a"), new MyNonSerializableValue("b"));
+ assertEquals(1, cache1.getCacheSize());
+ assertNull(cache2.get(new MyKey("a")));
+ assertEquals(0, cache2.getCacheSize());
+ assertEquals(0, cache3.getCacheSize());
+ assertEquals(1, listener1.put);
+ assertEquals(1, listener2.put);
+ assertEquals(0, listener3.put);
+ assertEquals(0, listener1.get);
+ assertEquals(1, listener2.get);
+ assertEquals(0, listener3.get);
+ cache2.put(new MyKey("b"), new MyNonSerializableValue("c"));
+ assertEquals(1, cache1.getCacheSize());
+ assertEquals(1, cache2.getCacheSize());
+ assertNull(cache1.get(new MyKey("b")));
+ assertEquals(0, cache3.getCacheSize());
+ assertEquals(2, listener1.put);
+ assertEquals(2, listener2.put);
+ assertEquals(0, listener3.put);
+ assertEquals(1, listener1.get);
+ assertEquals(1, listener2.get);
+ assertEquals(0, listener3.get);
+ cache3.put(new MyKey("c"), new MyNonSerializableValue("d"));
+ assertEquals(1, cache1.getCacheSize());
+ assertEquals(1, cache2.getCacheSize());
+ assertEquals(1, cache3.getCacheSize());
+ assertEquals(new MyNonSerializableValue("d"), cache3.get(new MyKey("c")));
+ assertEquals(2, listener1.put);
+ assertEquals(2, listener2.put);
+ assertEquals(1, listener3.put);
+ assertEquals(1, listener1.get);
+ assertEquals(1, listener2.get);
+ assertEquals(1, listener3.get);
+ cache2.put(new MyKey("a"), new MyNonSerializableValue("a"));
+ assertEquals(0, cache1.getCacheSize());
+ assertEquals(2, cache2.getCacheSize());
+ assertNull(cache1.get(new MyKey("a")));
+ assertEquals(3, listener1.put);
+ assertEquals(3, listener2.put);
+ assertEquals(1, listener3.put);
+ assertEquals(2, listener1.get);
+ assertEquals(1, listener2.get);
+ assertEquals(1, listener3.get);
+ cache2.remove(new MyKey("a"));
+ assertEquals(0, cache1.getCacheSize());
+ assertEquals(1, cache2.getCacheSize());
+ assertEquals(3, listener1.put);
+ assertEquals(3, listener2.put);
+ assertEquals(1, listener3.put);
+ assertEquals(2, listener1.get);
+ assertEquals(1, listener2.get);
+ assertEquals(1, listener3.get);
+ assertEquals(1, listener1.remove);
+ assertEquals(1, listener2.remove);
+ assertEquals(0, listener3.remove);
+ cache1.put(new MyKey("c"), new MyNonSerializableValue("c"));
+ cache1.clearCache();
+ assertEquals(0, cache1.getCacheSize());
+ assertNull(cache1.get(new MyKey("b")));
+ assertEquals(new MyNonSerializableValue("c"), cache2.get(new MyKey("b")));
+ assertNull(cache2.get(new MyKey("c")));
+ assertEquals(1, cache2.getCacheSize());
+ assertEquals(4, listener1.put);
+ assertEquals(4, listener2.put);
+ assertEquals(1, listener3.put);
+ assertEquals(3, listener1.get);
+ assertEquals(3, listener2.get);
+ assertEquals(1, listener3.get);
+ assertEquals(1, listener1.remove);
+ assertEquals(1, listener2.remove);
+ assertEquals(0, listener3.remove);
+ assertEquals(1, listener1.clearCache);
+ assertEquals(0, listener2.clearCache);
+ assertEquals(0, listener3.clearCache);
+ Map<Serializable, MyNonSerializableValue> values = new HashMap<Serializable, MyNonSerializableValue>();
+ values.put(new MyKey("a"), new MyNonSerializableValue("a"));
+ values.put(new MyKey("b"), new MyNonSerializableValue("b"));
+ cache1.putMap(values);
+ assertEquals(2, cache1.getCacheSize());
+ Thread.sleep(40);
+ assertNull(cache2.get(new MyKey("a")));
+ assertNull(cache2.get(new MyKey("b")));
+ assertEquals(0, cache2.getCacheSize());
+ assertEquals(6, listener1.put);
+ assertEquals(6, listener2.put);
+ assertEquals(1, listener3.put);
+ assertEquals(3, listener1.get);
+ assertEquals(5, listener2.get);
+ assertEquals(1, listener3.get);
+ assertEquals(1, listener1.remove);
+ assertEquals(1, listener2.remove);
+ assertEquals(0, listener3.remove);
+ assertEquals(1, listener1.clearCache);
+ assertEquals(0, listener2.clearCache);
+ assertEquals(0, listener3.clearCache);
+ values = new HashMap<Serializable, MyNonSerializableValue>()
+ {
+ private static final long serialVersionUID = 1L;
+
+ public Set<Entry<Serializable, MyNonSerializableValue>> entrySet()
+ {
+ Set<Entry<Serializable, MyNonSerializableValue>> set = new LinkedHashSet<Entry<Serializable, MyNonSerializableValue>>(super.entrySet());
+ set.add(new Entry<Serializable, MyNonSerializableValue>()
+ {
+
+ public MyNonSerializableValue setValue(MyNonSerializableValue paramV)
+ {
+ return null;
+ }
+
+ public MyNonSerializableValue getValue()
+ {
+ throw new RuntimeException("An exception");
+ }
+
+ public Serializable getKey()
+ {
+ return "c";
+ }
+ });
+ return set;
+ }
+ };
+ values.put(new MyKey("e"), new MyNonSerializableValue("e"));
+ values.put(new MyKey("d"), new MyNonSerializableValue("d"));
+ try
+ {
+ cache1.putMap(values);
+ }
+ catch (Exception e)
+ {
+ // ignore me
+ }
+ assertEquals(2, cache1.getCacheSize());
+ assertEquals(0, cache2.getCacheSize());
+ assertEquals(1, cache3.getCacheSize());
+ assertEquals(6, listener1.put);
+ assertEquals(6, listener2.put);
+ assertEquals(1, listener3.put);
+ assertEquals(3, listener1.get);
+ assertEquals(5, listener2.get);
+ assertEquals(1, listener3.get);
+ assertEquals(1, listener1.remove);
+ assertEquals(1, listener2.remove);
+ assertEquals(0, listener3.remove);
+ assertEquals(1, listener1.clearCache);
+ assertEquals(0, listener2.clearCache);
+ assertEquals(0, listener3.clearCache);
+ assertEquals(0, listener1.expire);
+ assertEquals(0, listener2.expire);
+ assertEquals(0, listener3.expire);
+ Thread.sleep(1600);
+ assertEquals(0, cache1.getCacheSize());
+ assertEquals(0, cache2.getCacheSize());
+ assertEquals(0, cache3.getCacheSize());
+ assertEquals(6, listener1.put);
+ assertEquals(6, listener2.put);
+ assertEquals(1, listener3.put);
+ assertEquals(3, listener1.get);
+ assertEquals(5, listener2.get);
+ assertEquals(1, listener3.get);
+ assertEquals(1, listener1.remove);
+ assertEquals(1, listener2.remove);
+ assertEquals(0, listener3.remove);
+ assertEquals(1, listener1.clearCache);
+ assertEquals(0, listener2.clearCache);
+ assertEquals(0, listener3.clearCache);
+ assertEquals(2, listener1.expire);
+ assertEquals(3, listener2.expire);
+ assertEquals(1, listener3.expire);
+ cache1.put(new MyKey("a"), new MyNonSerializableValue("b"));
+ assertNotNull(cache1.get(new MyKey("a")));
+ assertNull(cache2.get(new MyKey("a")));
+ cache2.put(new MyKey("a"), new MyNonSerializableValue("c"));
+ assertNotNull(cache2.get(new MyKey("a")));
+ assertNull(cache1.get(new MyKey("a")));
+ cache1.put(new MyKey("a"), new MyNonSerializableValue("c"));
+ assertEquals(new MyNonSerializableValue("c"), cache2.get(new MyKey("a")));
+ assertEquals(new MyNonSerializableValue("c"), cache1.get(new MyKey("a")));
+ assertEquals(9, listener1.put);
+ assertEquals(9, listener2.put);
+ assertEquals(1, listener3.put);
+ assertEquals(6, listener1.get);
+ assertEquals(8, listener2.get);
+ assertEquals(1, listener3.get);
+ assertEquals(1, listener1.remove);
+ assertEquals(1, listener2.remove);
+ assertEquals(0, listener3.remove);
+ assertEquals(1, listener1.clearCache);
+ assertEquals(0, listener2.clearCache);
+ assertEquals(0, listener3.clearCache);
+ assertEquals(2, listener1.expire);
+ assertEquals(3, listener2.expire);
+ assertEquals(1, listener3.expire);
+
+ }
+ finally
+ {
+ acache1.cache.stop();
+ acache2.cache.stop();
+ acache3.cache.stop();
+ }
+ }
+
public void testMultiThreading() throws Exception
{
long time = System.currentTimeMillis();
@@ -645,7 +887,7 @@
System.out.println("Total Time = " + (System.currentTimeMillis() - time));
}
- public static class MyCacheListener implements CacheListener<Serializable, Object>
+ public static class MyCacheListener<T> implements CacheListener<Serializable, T>
{
public int clearCache;
@@ -658,64 +900,67 @@
public int remove;
- public void onClearCache(ExoCache<Serializable, Object> cache) throws Exception
+ public void onClearCache(CacheListenerContext context) throws Exception
{
clearCache++;
}
- public void onExpire(ExoCache<Serializable, Object> cache, Serializable key, Object obj) throws Exception
+ public void onExpire(CacheListenerContext context, Serializable key, T obj) throws Exception
{
expire++;
}
- public void onGet(ExoCache<Serializable, Object> cache, Serializable key, Object obj) throws Exception
+ public void onGet(CacheListenerContext context, Serializable key, T obj) throws Exception
{
get++;
}
- public void onPut(ExoCache<Serializable, Object> cache, Serializable key, Object obj) throws Exception
+ public void onPut(CacheListenerContext context, Serializable key, T obj) throws Exception
{
put++;
}
- public void onRemove(ExoCache<Serializable, Object> cache, Serializable key, Object obj) throws Exception
+ public void onRemove(CacheListenerContext context, Serializable key, T obj) throws Exception
{
remove++;
}
+ }
- public void onClearCache(CacheListenerContext context) throws Exception
- {
- clearCache++;
- }
+ public static class MyKey implements Serializable
+ {
+ private static final long serialVersionUID = 1L;
- public void onExpire(CacheListenerContext context, Serializable key, Object obj) throws Exception
+ public String value;
+
+ public MyKey(String value)
{
- expire++;
+ this.value = value;
}
- public void onGet(CacheListenerContext context, Serializable key, Object obj) throws Exception
+ @Override
+ public boolean equals(Object paramObject)
{
- get++;
+ return paramObject instanceof MyKey && ((MyKey)paramObject).value.endsWith(value);
}
- public void onPut(CacheListenerContext context, Serializable key, Object obj) throws Exception
+ @Override
+ public int hashCode()
{
- put++;
+ return value.hashCode();
}
- public void onRemove(CacheListenerContext context, Serializable key, Object obj) throws Exception
+ @Override
+ public String toString()
{
- remove++;
+ return value;
}
}
-
- public static class MyKey implements Serializable
+
+ public static class MyNonSerializableValue
{
- private static final long serialVersionUID = 1L;
-
public String value;
- public MyKey(String value)
+ public MyNonSerializableValue(String value)
{
this.value = value;
}
@@ -723,7 +968,7 @@
@Override
public boolean equals(Object paramObject)
{
- return paramObject instanceof MyKey && ((MyKey)paramObject).value.endsWith(value);
+ return paramObject instanceof MyNonSerializableValue && ((MyNonSerializableValue)paramObject).value.endsWith(value);
}
@Override
More information about the exo-jcr-commits
mailing list