How to modify/evolve a distributed Infinispan cache "hot" without losing entries?

Asked

Viewed 155 times

5

Context

I have a cluster with some nodes of the Jboss EAP 6.4. Applications in this node cluster share a cache embedded mode infinispan with UDP synchronous distribution (Jgroups):

<cache-container name="meu-container"
        default-cache="meu-cache"
        jndi-name="java:jboss/infinispan/cache/meu-container">
   <transport stack="udp"/>
   <distributed-cache name="meu-cache" 
         owners="2"  
         mode="SYNC" />
   <!-- Outros caches -->       
</cache-container>  

This cache uses a String as a key and a POJO as a value:

@Resource(lookup="java:jboss/infinispan/cache/meu-container/meu-cache")
private Cache<String, MeuPojo> meuCache;

MeuPojo is a simple object Serializable:

public class MeuPojo implements java.io.Serializable {

    private static final long serialVersionUID = 4L;  
    
    private String campoUm;
    private Integer campoDois;

    // Outros campos, getters, setters, etc

} 

The cache distributed works perfectly and all instances of meuCache "see" all entries. Changes in any instance of MeuPojo are seen in all nodes, new entries or deletions of entries in any node are "reflected" in the other nodes.

During a upgrade of the application without updates in MeuPojo the knots of cluster go up and down one by one without prejudice to the cache. Once a node goes up it gains access to his copy of the entries of cache.

The problem

The problem happens when I modify MeuPojo. In this case Infinispan does not behave very well due to differences in serialization. If I add a new field (e. g., private String campoTres;) updated nodes cannot see the entries with updated versions of MeuPojo in the meuCache and vice versa (not updated nodes do not see versions of MeuPojo up-to-date).

Nothing significant happens in logs regardless of the value of serialVersionUID. Which leads me to believe that the Infinispan is swallowing exceptions like InvalidClassException.

Currently every time we want to add a new field in MeuPojo is a fight. The workaround is to use two caches (meu-cache and meu-cache-v2) and two different classes MeuPojo and MeuPojoV2. We manually copy the entries into the application and exchange which cache is "valid" for applications in each upgrade.

I think there must be a less "dumb" way to evolve MeuPojo without losing cache entries, but I couldn’t find a solution. The ideal would be for updated nodes to see entries in updated versions of MeuPojo (as if they had campo3 = null) and vice versa.

Someone has been through it and knows a solution or at least one work-Around less laborious?

1 answer

2

I see at least two possible alternatives, but there must be more. The first of these is the simplest, but also more fragile, and consists of freezing the set of fields of the existing classes (as well as freezing the serialVersionUID) and force new fields to be added with the modifier transient. Any violation of this rule will cause the problem you describe.

The other alternative is to take control of serialization yourself by implementing the following methods:

private void writeObject(java.io.ObjectOutputStream out) throws IOException;
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException;
private void readObjectNoData() throws ObjectStreamException;

These methods are described in the interface documentation Serializable. Basically, they replace the standard serialization form and allow you to define your own particular way of doing serialization. The method writeObject is responsible for serializing the object and the readObject to deserialize. The method readObjectNoData decides what to do when the object to be created comes from a stream corrupted or incompatible.

The ObjectOutputStream is the object responsible for serializing the object and it knows the object being serialized. Thus, if you use the methods ObjectOutputStream.defaultWriteObject() and ObjectInputStream.defaultReadObject(), the fields do not-transient of the object in question will be serialized and deserialized respectively in the standard way that java does. Therefore, you can use these methods to write and read the default fields and use the other methods in it stream to write and read the values of the other fields that will be marked as transient. Or you do not use these methods and add/get the values of the object fields manually when using the other methods of stream.

In addition, you may also prefer to implement the interface Externalizable to have a better control over the stream.

  • Victor speaking, baby? Unfortunately implement Exernalizable made no difference, it seems that this version of Inifinispan does not use the standard serialization mechanism. I found in the documentation references to Jboss Marshalling and User Defined Externalizers, I’m trying to see if I can put one of these examples to work. Anyway thanks for the help, you pointed in the right direction.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.