// notify listeners that a rehash is about to start
notifier.notifyDataRehashed(oldCacheSet, newCacheSet, newViewId, true);
List<Object> removedKeys = new ArrayList<Object>();
NotifyingNotifiableFuture<Object> stateTransferFuture = new AggregatingNotifyingFutureImpl(null, newMembers.size());
try {
// Don't need to log anything, all transactions will be blocked
//distributionManager.getTransactionLogger().enable();
distributionManager.getTransactionLogger().blockNewTransactions();
int numOwners = configuration.getNumOwners();
// Contains the state to be pushed to various servers. The state is a hashmap of keys and values
final Map<Address, Map<Object, InternalCacheValue>> states = new HashMap<Address, Map<Object, InternalCacheValue>>();
for (InternalCacheEntry ice : dataContainer) {
rebalance(ice.getKey(), ice, numOwners, chOld, chNew, null, states, removedKeys);
}
// Only fetch the data from the cache store if the cache store is not shared
CacheStore cacheStore = distributionManager.getCacheStoreForRehashing();
if (cacheStore != null) {
for (Object key : cacheStore.loadAllKeys(new ReadOnlyDataContainerBackedKeySet(dataContainer))) {
rebalance(key, null, numOwners, chOld, chNew, cacheStore, states, removedKeys);
}
} else {
if (trace) log.trace("Shared cache store or fetching of persistent state disabled");
}
// Now for each server S in states.keys(): push states.get(S) to S via RPC
for (Map.Entry<Address, Map<Object, InternalCacheValue>> entry : states.entrySet()) {
final Address target = entry.getKey();
Map<Object, InternalCacheValue> state = entry.getValue();
if (trace)
log.tracef("pushing %d keys to %s", state.size(), target);
final RehashControlCommand cmd = cf.buildRehashControlCommand(RehashControlCommand.Type.APPLY_STATE, self,
state, chOld, chNew);
rpcManager.invokeRemotelyInFuture(Collections.singleton(target), cmd,
false, stateTransferFuture, configuration.getRehashRpcTimeout());
}
} finally {
distributionManager.getTransactionLogger().unblockNewTransactions();
}
// wait to see if all servers received the new state
// TODO should we retry the state transfer operation if it failed on some of the nodes?
try {
stateTransferFuture.get();
} catch (ExecutionException e) {
log.error("Error transferring state to node after rehash:", e);
}
// Notify listeners of completion of rehashing