* @param key the key the operation is operating upon
* @param o the operation
*/
@Override
public void addOperation(final String key, final Operation o) {
MemcachedNode placeIn = null;
MemcachedNode primary;
if(o instanceof ReplicaGetOperation
&& locator instanceof VBucketNodeLocator) {
primary = ((VBucketNodeLocator)locator).getReplica(key,
((ReplicaGetOperation)o).getReplicaIndex());
} else {
primary = locator.getPrimary(key);
}
if (primary == null) {
o.cancel();
cf.checkConfigUpdate();
return;
}
if (primary.isActive() || failureMode == FailureMode.Retry) {
placeIn = primary;
} else if (failureMode == FailureMode.Cancel) {
o.cancel();
} else {
// Look for another node in sequence that is ready.
for (Iterator<MemcachedNode> i = locator.getSequence(key); placeIn == null
&& i.hasNext();) {
MemcachedNode n = i.next();
if (n.isActive()) {
placeIn = n;
}
}
// If we didn't find an active node, queue it in the primary node
// and wait for it to come back online.
if (placeIn == null) {
placeIn = primary;
getLogger().warn(
"Node expected to receive data is inactive. This could be due to "
+ "a failure within the cluster. Will check for updated "
+ "configuration. Key without a configured node is: %s.", key);
cf.checkConfigUpdate();
}
}
assert o.isCancelled() || placeIn != null : "No node found for key " + key;
if (placeIn != null) {
// add the vbucketIndex to the operation
if (locator instanceof VBucketNodeLocator) {
VBucketNodeLocator vbucketLocator = (VBucketNodeLocator) locator;
short vbucketIndex = (short) vbucketLocator.getVBucketIndex(key);
if (o instanceof VBucketAware) {
VBucketAware vbucketAwareOp = (VBucketAware) o;
vbucketAwareOp.setVBucket(key, vbucketIndex);
if (!vbucketAwareOp.getNotMyVbucketNodes().isEmpty()) {
MemcachedNode alternative =
vbucketLocator.getAlternative(key,
vbucketAwareOp.getNotMyVbucketNodes());
if (alternative != null) {
placeIn = alternative;
}