Introduction
In the post I wrote on Partition Level Transactions, I showed how we could use data affinity (see here) to update multiple caches in a single atomic operation. This is a very powerful feature and I thought I would just add a bit more to the conversation around this.

When you implement key association, you get “related” entries always stored in the same partitions. E.g. you may have key association between a Customer and Orders on the customerId attribute. In this case you will always get the Orders for customer 1 in the same partition as the customer object “Customer 1”.

As described in the post above you can use “Partition Level Transactions” to update related cache objects in this way. But the other more obvious advantage is that if you are running an Entry Processor (EP) on Order 200 for Customer 1, you know that Customer 1 is in the same partition and you can get directly access the related object (Customer) via the BackingMapManagerContext.getBackingMapEntry() method.

This means direct memory access to the Objects rather than having to get them from another cluster member. Very fast!

The Potential Unintended Side Effect
On first glance the following code (from the previous blogs EP) makes sense if you just wanted to access the Customer object while running an EP against an Order entry:

@Override
public Object process(Entry entry)
{
...
BackingMapManagerContext ctx = ((BinaryEntry) entry).getContext();
// Get the Customer but we dont want to update. This will work, but the side effect
// is the Customer key will be added to "sandbox" of changes and locked.
BinaryEntry customerEntry =
(BinaryEntry) orderEntry.getContext().getBackingMapContext(Customer.CACHENAME)
.getBackingMapEntry(ctx.getKeyToInternalConverter()
.convert(newOrder.getCustomerId()));
Customer thisCustomer = ((Customer) customerEntry.getValue());
...

This will certainly work, but remember that calling getBackingMapEntry() adds the retrieved BinaryEntry to the “sandbox” of changes, which includes also applying the EP locking semantics to that key. So even if you wanted to just read the value, you are locking it for the duration of the EP as well.

This would then queue any other updates via EP’s to the Customer which is not what we intend in this case.

How to Avoid Locking When Getting Related Objects

This is where you need to subtly change the code to access the BackingMap directly (which only works for caches related via key association) to get the required Customer object. The following code shows how to get an Object, which is related object using getBackingMap().get() instead of getBackingMapEntry() in the case where you don’t want to update the related object:

@Override
public Object process(Entry entry)
{
...
BackingMapManagerContext ctx = ((BinaryEntry) entry).getContext();
// Get the Customer but we dont want to update. This will work, and no side effect of
// of locking.
Binary binCustomer =
(Binary)ctx.getBackingMapContext(Customer.CACHENAME)
.getBackingMap().get(ctx.getKeyToInternalConverter()
.convert(newOrder.getCustomerId()));
// Because we are getting a Binary instead of BinaryEntry, we need to deserialize with the
// serlializer for the Service.
Customer c = (Customer) ExternalizableHelper
.fromBinary(binCustomer, ctx.getCacheService().getSerializer());
...

Conclusion
So key things to remember are:

Use getBackingMap().get() if you just want to retrieve related cache objects you know are in the same partition and don’t want to update them.

Use getBackingMapEntry() if you want to update a related entry using Partition Level Transactions.

Yes, we are using EP, and we need to update some entries based on rules read form other entries, and we used getBackingMapEntry() for all entries before. Now we’ll try to use getBackingMapEntry() or getBackingMap().get() for different entries.

This is very helpful. I have a question more basic though.
I tried to typecast the Entry object to a BinaryEntry object but I receive a classcastexception continuously. To allow this typecast, would there be any other prerequisites? The caches I am working with are all DistributedCaches.

Blogroll

Copyright (c) 2017 Tim Middleton and other contributors. All Rights Reserved. The views expressed in this blog are our own and do not necessarily reflect the views of Oracle Corporation. All content is provided on an 'as is' basis, without warranties or conditions of any kind, either express or implied, including, without limitation, any warranties or conditions of title, non-infringement, merchantability, or fitness for a particular purpose. You are solely responsible for determining the appropriateness of using or redistributing and assume any risks.