@Override
public void handleStateTransferState(XSiteStatePushCommand cmd) throws Exception {
//split the state and forward it to the primary owners...
if (!cache.getStatus().allowInvocations()) {
throw new CacheException("Cache is stopping or terminated: " + cache.getStatus());
}
final ClusteringDependentLogic clusteringDependentLogic = cache.getAdvancedCache().getComponentRegistry()
.getComponent(ClusteringDependentLogic.class);
final Map<Address, List<XSiteState>> primaryOwnersChunks = new HashMap<Address, List<XSiteState>>();
if (trace) {
log.tracef("Received X-Site state transfer '%s'. Splitting by primary owner.", cmd);
}
for (XSiteState state : cmd.getChunk()) {
final Address primaryOwner = clusteringDependentLogic.getPrimaryOwner(state.key());
List<XSiteState> primaryOwnerList = primaryOwnersChunks.get(primaryOwner);
if (primaryOwnerList == null) {
primaryOwnerList = new LinkedList<XSiteState>();
primaryOwnersChunks.put(primaryOwner, primaryOwnerList);
}
primaryOwnerList.add(state);
}
final List<XSiteState> localChunks = primaryOwnersChunks.remove(clusteringDependentLogic.getAddress());
final List<StatePushTask> tasks = new ArrayList<StatePushTask>(primaryOwnersChunks.size());
for (Map.Entry<Address, List<XSiteState>> entry : primaryOwnersChunks.entrySet()) {
if (entry.getValue() == null || entry.getValue().isEmpty()) {
continue;
}
if (trace) {
log.tracef("Node '%s' will apply %s", entry.getKey(), entry.getValue());
}
StatePushTask task = new StatePushTask(entry.getValue(), entry.getKey(), cache);
tasks.add(task);
task.executeRemote();
}
//help gc. this is safe because the chunks was already sent
primaryOwnersChunks.clear();
if (trace) {
log.tracef("Local node '%s' will apply %s", cache.getAdvancedCache().getRpcManager().getAddress(),
localChunks);
}
if (localChunks != null) {
LocalInvocation.newInstanceFromCache(cache, newStatePushCommand(cache, localChunks)).call();
//help gc
localChunks.clear();
}
if (trace) {
log.tracef("Waiting for the remote tasks...");
}
while (!tasks.isEmpty()) {
for (Iterator<StatePushTask> iterator = tasks.iterator(); iterator.hasNext(); ) {
awaitRemoteTask(cache, iterator.next());
iterator.remove();
}
}
//the put operation can fail silently. check in the end and it is better to resend the chunk than to lose keys.
if (!cache.getStatus().allowInvocations()) {
throw new CacheException("Cache is stopping or terminated: " + cache.getStatus());
}
}