Search code examples
javacachingignite

Getting following error while inserting data in Ignite cache?


This error is occurred while using JsonObject(GSON Library) in cache value if I used String instead of JsonObject then operation perform successfully.

Error which I have get while inserting data in cache:

javax.cache.CacheException: class org.apache.ignite.transactions.TransactionRollbackException: Transaction has been rolled back: 9557fcfb061-00000000-078a-a446-0000-000000000001
    at org.apache.ignite.internal.processors.cache.GridCacheUtils.convertToCacheException(GridCacheUtils.java:1287)
    at org.apache.ignite.internal.processors.cache.IgniteCacheProxyImpl.cacheException(IgniteCacheProxyImpl.java:1648)
    at org.apache.ignite.internal.processors.cache.IgniteCacheProxyImpl.put(IgniteCacheProxyImpl.java:1008)
    at org.apache.ignite.internal.processors.cache.GatewayProtectedCacheProxy.put(GatewayProtectedCacheProxy.java:872)
    at com.clouzer.databaseoperation.DataBaseOperation.getAllUSerGson(DataBaseOperation.java:527)
    at com.mstorm.ignition.gson.LoginCacheOperation.createLoginCache(LoginCacheOperation.java:38)
    at com.mstorm.ignition.gson.IgniteCacheCreator.createCaches(IgniteCacheCreator.java:30)
    at com.mstorm.ignition.gson.IgniteServer.main(IgniteServer.java:102)
Caused by: class org.apache.ignite.transactions.TransactionRollbackException: Transaction has been rolled back: 9557fcfb061-00000000-078a-a446-0000-000000000001
    at org.apache.ignite.internal.util.IgniteUtils$11.apply(IgniteUtils.java:860)
    at org.apache.ignite.internal.util.IgniteUtils$11.apply(IgniteUtils.java:858)
    ... 8 more
Caused by: class org.apache.ignite.internal.transactions.IgniteTxRollbackCheckedException: Transaction has been rolled back: 9557fcfb061-00000000-078a-a446-0000-000000000001
    at org.apache.ignite.internal.processors.cache.GridCacheAdapter.syncOp(GridCacheAdapter.java:4054)
    at org.apache.ignite.internal.processors.cache.GridCacheAdapter.put0(GridCacheAdapter.java:2340)
    at org.apache.ignite.internal.processors.cache.GridCacheAdapter.put(GridCacheAdapter.java:2321)
    at org.apache.ignite.internal.processors.cache.GridCacheAdapter.put(GridCacheAdapter.java:2298)
    at org.apache.ignite.internal.processors.cache.IgniteCacheProxyImpl.put(IgniteCacheProxyImpl.java:1005)
    ... 5 more
Caused by: class org.apache.ignite.IgniteCheckedException: Can not set final com.google.gson.internal.LinkedTreeMap field com.google.gson.JsonObject.members to java.util.LinkedHashMap
    at org.apache.ignite.internal.util.IgniteUtils.cast(IgniteUtils.java:7252)
    at org.apache.ignite.internal.util.future.GridFutureAdapter.resolve(GridFutureAdapter.java:259)
    at org.apache.ignite.internal.util.future.GridFutureAdapter.get0(GridFutureAdapter.java:171)
    at org.apache.ignite.internal.util.future.GridFutureAdapter.get(GridFutureAdapter.java:140)
    at org.apache.ignite.internal.processors.cache.distributed.near.GridNearTxLocal$10.applyx(GridNearTxLocal.java:2396)
    at org.apache.ignite.internal.processors.cache.distributed.near.GridNearTxLocal$10.applyx(GridNearTxLocal.java:2392)
    at org.apache.ignite.internal.util.lang.IgniteClosureX.apply(IgniteClosureX.java:38)
    at org.apache.ignite.internal.util.future.GridFutureChainListener.applyCallback(GridFutureChainListener.java:78)
    at org.apache.ignite.internal.util.future.GridFutureChainListener.apply(GridFutureChainListener.java:70)
    at org.apache.ignite.internal.util.future.GridFutureChainListener.apply(GridFutureChainListener.java:30)
    at org.apache.ignite.internal.util.future.GridFutureAdapter.notifyListener(GridFutureAdapter.java:383)
    at org.apache.ignite.internal.util.future.GridFutureAdapter.listen(GridFutureAdapter.java:353)
    at org.apache.ignite.internal.util.future.GridFutureAdapter$ChainFuture.<init>(GridFutureAdapter.java:572)
    at org.apache.ignite.internal.util.future.GridFutureAdapter.chain(GridFutureAdapter.java:358)
    at org.apache.ignite.internal.processors.cache.distributed.near.GridNearTxLocal.optimisticPutFuture(GridNearTxLocal.java:2391)
    at org.apache.ignite.internal.processors.cache.distributed.near.GridNearTxLocal.putAsync0(GridNearTxLocal.java:622)
    at org.apache.ignite.internal.processors.cache.distributed.near.GridNearTxLocal.putAsync(GridNearTxLocal.java:385)
    at org.apache.ignite.internal.processors.cache.GridCacheAdapter$22.op(GridCacheAdapter.java:2342)
    at org.apache.ignite.internal.processors.cache.GridCacheAdapter$22.op(GridCacheAdapter.java:2340)
    at org.apache.ignite.internal.processors.cache.GridCacheAdapter.syncOp(GridCacheAdapter.java:4040)
    ... 9 more

Cache Configuration:

CacheConfiguration<String, JsonObject> cacheConfig = new CacheConfiguration<>();
            cacheConfig.setName("CACHE_NAME");
            cacheConfig.setReadThrough(true);
            cacheConfig.setBackups(2);
            cacheConfig.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
            cacheConfig.setWriteThrough(true);
            cacheConfig.setCacheStoreFactory(FactoryBuilder.factoryOf(ObjectLoader.class));
            IgniteCache<String, JsonObject> cache = ignite.getOrCreateCache(cacheConfig);

Operations:

1.create JsonObject (use GSON library)

2.set cache loader to the given cache which used for persistent store

3.insert data into the cache from ignite client-side

4.observe the issue


Solution

  • The problem is that JsonObject has members field of type LinkedTreeMap, and Ignite BinaryMarshaller, which is default one, deserializes it into a LinkedHashMap for some reason.

    To avoid it you can use a different marshaller, for example, OptimizedMarshaller.

    UPD:

    Turns out, if you configure OptimizedMarshaller, then only puts and gets from cache will work fine. But if you try to get(...) some field of the deserialized representation of JsonObject, for example, then JVM will crash.

    The reason is that LinkedTreeMap has the following writeReplace() method:

    private Object writeReplace() throws ObjectStreamException {
        return new LinkedHashMap(this);
    }
    

    So, if you serialize it, and after that deserialize, then you will get an instance of LinkedHashMap instead of LinkedTreeMap. So, BinaryMarshaller is doing nothing wrong.

    Summary:

    Looks like you shouldn't put JsonObjects into cache. It doesn't implement Serializable, so the authors didn't think about serializing it. I think, you will have to replace JsonObject with JSON strings.