2
votes

I have this wired error when I use the cache query scan from a client node

        List<Account> data = accounts.query(new ScanQuery<UUID, Account>()).getAll().stream().map(uuidAccountEntry -> uuidAccountEntry.getValue()).collect(Collectors.toList());

but if I try to return just the objects (not the Entry) with the filter I get an exception

        List<Account> data = accounts.query(new ScanQuery<UUID, Account>(), Cache.Entry::getValue).getAll();

NOTE* running in docker

ignite_1 | 09:54:05.663 [query-#58] ERROR o.a.i.i.b.BinaryContext - Failed to deserialize object [typeName=java.lang.invoke.SerializedLambda] ignite_1 | org.apache.ignite.binary.BinaryObjectException: Failed to read field [name=capturingClass] ignite_1 | at org.apache.ignite.internal.binary.BinaryFieldAccessor.read(BinaryFieldAccessor.java:192) ignite_1 | at org.apache.ignite.internal.binary.BinaryClassDescriptor.read(BinaryClassDescriptor.java:875) ignite_1 | at org.apache.ignite.internal.binary.BinaryReaderExImpl.deserialize0(BinaryReaderExImpl.java:1764) ignite_1 | at org.apache.ignite.internal.binary.BinaryReaderExImpl.deserialize(BinaryReaderExImpl.java:1716) ignite_1 | at org.apache.ignite.internal.binary.GridBinaryMarshaller.deserialize(GridBinaryMarshaller.java:313) ignite_1 | at org.apache.ignite.internal.binary.BinaryMarshaller.unmarshal0(BinaryMarshaller.java:102) ignite_1 | at org.apache.ignite.marshaller.AbstractNodeNameAwareMarshaller.unmarshal(AbstractNodeNameAwareMarshaller.java:82) ignite_1 | at org.apache.ignite.internal.util.IgniteUtils.unmarshal(IgniteUtils.java:10140) ignite_1 | at org.apache.ignite.internal.processors.cache.query.GridCacheQueryRequest.finishUnmarshal(GridCacheQueryRequest.java:344) ignite_1 | at org.apache.ignite.internal.processors.cache.GridCacheIoManager.unmarshall(GridCacheIoManager.java:1530) ignite_1 | at org.apache.ignite.internal.processors.cache.GridCacheIoManager.onMessage0(GridCacheIoManager.java:576) ignite_1 | at org.apache.ignite.internal.processors.cache.GridCacheIoManager.handleMessage(GridCacheIoManager.java:380) ignite_1 | at org.apache.ignite.internal.processors.cache.GridCacheIoManager.handleMessage(GridCacheIoManager.java:306) ignite_1 | at org.apache.ignite.internal.processors.cache.GridCacheIoManager.access$100(GridCacheIoManager.java:101) ignite_1 | at org.apache.ignite.internal.processors.cache.GridCacheIoManager$1.onMessage(GridCacheIoManager.java:295) ignite_1 | at org.apache.ignite.internal.managers.communication.GridIoManager.invokeListener(GridIoManager.java:1569) ignite_1 | at org.apache.ignite.internal.managers.communication.GridIoManager.processRegularMessage0(GridIoManager.java:1197) ignite_1 | at org.apache.ignite.internal.managers.communication.GridIoManager.access$4200(GridIoManager.java:127) ignite_1 | at org.apache.ignite.internal.managers.communication.GridIoManager$9.run(GridIoManager.java:1093) ignite_1 | at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ignite_1 | at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ignite_1 | at java.lang.Thread.run(Thread.java:748)

All other queries and put/get/... work perfect and no issues with serializing the Account object.

I tried many cache configurations but none seemed to make a difference.

Anyone had this issue or know how to resolve this? Thanks in advance.

2
Might be a bug (probably a bug). Try using a private static class instead of lambda for now. This is a general advice for Ignite anyway - lambda serialization is weird, especially in a distributed environment, so it's best to avoid it. - Stanislav Lukyanov
Thanks, @Stanislav This worked!.. but only after I created a public class in my shared model jar. see my answer. - Gadi
Actually... Does it work if you just change the method reference to a lambda? I mean change Cache.Entry::getValue to e -> e.getValue()? - Stanislav Lukyanov
Also, what's your Java version? - Stanislav Lukyanov
no, I tried that too. Java version: 1.8.0_191, vendor: Oracle Corporation, runtime: /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-11.fc29.x86_64/jre - Gadi

2 Answers

0
votes

Thanks to the comments from @ Stanislav Lukyanov I changed my code and added a new class that implement the IgniteClosure and available on all nodes as part of my shared model jar.

import javax.cache.Cache;
import java.util.UUID;

public class AccountValueClosure implements IgniteClosure<Cache.Entry<UUID, Account>, Account> {
    @Override
    public Account apply(Cache.Entry<UUID, Account> e) {
        return e.getValue();
    }
}

Now I can call the cache query as expected with the closure instance...

        List<Account> data = accounts.query(new ScanQuery<UUID, Account>(), new AccountValueClosure()).getAll();

this ia ugly but works.

any feedback is welcomed.

0
votes

As far as I read in mailing list it was a bug IGNITE-13212 in ScanQuery (fixed in v2.9) that prevented from using lambdas or anonymous classes in query.

Recommendation from Ignite team:

My advice is to avoid using lambdas and anonymous classes due to this specificity. Instead, you can create "private static classes" and Ignite will be serializing an instance of that class only:

private static class MyFilter implements IgniteClosure { .... }

Lamdas are nice for demos and simple code samples where Inner/OuterClasses are simple Java classes. While in real production environments, things can get messy.

If it does not help then you will have to make sure that your filter/code is deployed to all cluster nodes. Or you can try to upgrade to newer version and check if it works there.