/*
* Copyright 2013 LinkedIn, Inc
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package voldemort.store.rebalancing;
import org.apache.log4j.Logger;
import voldemort.cluster.Node;
import voldemort.store.Store;
import voldemort.store.UnreachableStoreException;
import voldemort.store.metadata.MetadataStore;
import voldemort.utils.ByteArray;
import voldemort.utils.ByteUtils;
import voldemort.versioning.ObsoleteVersionException;
import voldemort.versioning.Versioned;
/**
* Task that issues the proxy put against the old replica, based on the old
* cluster metadata. This is best effort async replication. Failures will be
* logged and the server log will be post processed in case the rebalancing
* fails and we move back to old topology
*
* NOTE : There is no need for any special ordering of the proxy puts in the
* async thread pool (although the threadpool will have a queue of pending proxy
* puts internally), since a later version being proxy put before an earlier
* version would simply result in an OVE for the earlier proxy put. Online
* traffic will not be affected since the proxy node is not a replica and hence
* no client will be reading from it (if we are at all wondering about read
* consistency)
*
*/
public class AsyncProxyPutTask implements Runnable {
private final static Logger logger = Logger.getLogger(AsyncProxyPutTask.class);
private final RedirectingStore redirectingStore;
private final ByteArray key;
private final Versioned<byte[]> value;
private final byte[] transforms;
private final int destinationNode;
private final MetadataStore metadata;
AsyncProxyPutTask(RedirectingStore redirectingStore,
ByteArray key,
Versioned<byte[]> value,
byte[] transforms,
int destinationNode) {
this.key = key;
this.value = value;
this.transforms = transforms;
this.redirectingStore = redirectingStore;
this.destinationNode = destinationNode;
this.metadata = redirectingStore.getMetadataStore();
}
@Override
public void run() {
Node proxyNode = metadata.getCluster().getNodeById(destinationNode);
long startNs = System.nanoTime();
try {
// TODO there are no retries now if the node we want to write to is
// unavailable
redirectingStore.checkNodeAvailable(proxyNode);
Store<ByteArray, byte[], byte[]> socketStore = redirectingStore.getRedirectingSocketStore(redirectingStore.getName(),
destinationNode);
socketStore.put(key, value, transforms);
redirectingStore.recordSuccess(proxyNode, startNs);
redirectingStore.reportProxyPutSuccess();
if(logger.isTraceEnabled()) {
logger.trace("Proxy write for store " + redirectingStore.getName() + " key "
+ ByteUtils.toHexString(key.get()) + " to destinationNode:"
+ destinationNode);
}
} catch(UnreachableStoreException e) {
redirectingStore.recordException(proxyNode, startNs, e);
logFailedProxyPutIfNeeded(e);
} catch(ObsoleteVersionException ove) {
/*
* Proxy puts can get an OVE if somehow there are two stealers for
* the same proxy node and the other stealer's proxy put already got
* tothe proxy node.. This will not result from online put winning,
* since we don't issue proxy puts if the proxy node is still a
* replica
*/
logFailedProxyPutIfNeeded(ove);
} catch(Exception e) {
// Just log the key.. Not sure having values in the log is a good
// idea.
logFailedProxyPutIfNeeded(e);
}
}
private void logFailedProxyPutIfNeeded(Exception e) {
redirectingStore.reportProxyPutFailure();
// only log OVE if trace debugging is on.
if(e instanceof ObsoleteVersionException && !logger.isTraceEnabled()) {
return;
}
logger.error("Exception in proxy put for proxyNode: " + destinationNode + " from node:"
+ metadata.getNodeId() + " on key " + ByteUtils.toHexString(key.get())
+ " Version:" + value.getVersion(), e);
}
}