use of voldemort.routing.BaseStoreRoutingPlan in project voldemort by voldemort.
the class RedirectingStore method redirectingPut.
/**
* This is slightly different from other redirecting*** methods in that,
* this updates the remote proxy node, with this put request, so we can
* switch back to the old cluster topology if needed
*
* @param key
* @param value
* @param transforms
* @throws VoldemortException
*/
private void redirectingPut(ByteArray key, Versioned<byte[]> value, byte[] transforms) throws VoldemortException {
Cluster currentCluster = metadata.getCluster();
// TODO:refactor O(n) linear lookup of storedef here. Ideally should be
// a hash lookup.
StoreDefinition storeDef = metadata.getStoreDef(getName());
/*
* defensively, error out if this is a read-only store and someone is
* doing puts against it. We don't to do extra work and fill the log
* with errors in that case.
*/
if (storeDef.getType().compareTo(ReadOnlyStorageConfiguration.TYPE_NAME) == 0) {
throw new UnsupportedOperationException("put() not supported on read-only store");
}
BaseStoreRoutingPlan currentRoutingPlan = new BaseStoreRoutingPlan(currentCluster, storeDef);
Integer redirectNode = getProxyNode(currentRoutingPlan, storeDef, key.get());
/**
* If I am rebalancing for this key, try to do remote get() if this node
* does not have the key , put it locally first to get the correct
* version ignoring any {@link ObsoleteVersionException}
*/
if (redirectNode != null) {
/*
* first check if the key exists locally. If so, it means, it has
* been moved over (either by a proxy fetch or background fetch) and
* we are good simply issuing the put on top of that.
*/
List<Versioned<byte[]>> vals = getInnerStore().get(key, transforms);
if (vals.isEmpty()) {
// if not, then go proxy fetch it
if (logger.isTraceEnabled()) {
logger.trace("Proxying GET (before PUT) on stealer:" + metadata.getNodeId() + " for key " + ByteUtils.toHexString(key.get()) + " to node:" + redirectNode);
}
proxyGetAndLocalPut(key, redirectNode, transforms);
}
}
// Here we are sure that the current node has caught up with the proxy
// for this key. Moving on to the put logic.
// put the data locally, if this step fails, there will be no proxy puts
getInnerStore().put(key, value, transforms);
// OVE). So do not send proxy puts in those cases.
if (redirectNode != null && !currentRoutingPlan.getReplicationNodeList(key.get()).contains(redirectNode)) {
AsyncProxyPutTask asyncProxyPutTask = new AsyncProxyPutTask(this, key, value, transforms, redirectNode);
proxyPutStats.reportProxyPutSubmission();
proxyPutWorkerPool.submit(asyncProxyPutTask);
}
}
use of voldemort.routing.BaseStoreRoutingPlan in project voldemort by voldemort.
the class RedirectingStore method getProxyNode.
/**
* Checks if the server has to do any proxying of gets/puts to another
* server, as a part of an ongoing rebalance operation.
*
* Basic idea : Any given node which is a stealer of a partition, as the ith
* replica of a given zone, will proxy to the old ith replica of the
* partition in the given zone, as per the source cluster metadata.
* Exception : if this amounts to proxying to itself.
*
* Note on Zone Expansion : For zone expansion, there will be no proxying
* within the new zone. This is a practical assumption since if we fail, we
* fallback to a cluster topology without the new zone. As a result, reads
* from the new zone are not guaranteed to return some values during the
* course of zone expansion. This is a also reasonable since any
* organization undertaking such effort would need to have the data in place
* in the new zone, before the client apps are moved over.
*
* TODO:refactor Add helper methods to StoreRoutingPlan to simplify this
* code
*
* @param currentRoutingPlan routing plan object based on cluster's current
* topology
* @param storeDef definition of the store being redirected
* @param key to decide where to proxy to
* @return Null if no proxying is required else node id of the server to
* proxy to
*/
private Integer getProxyNode(BaseStoreRoutingPlan currentRoutingPlan, StoreDefinition storeDef, byte[] key) {
// get out if redirecting is disabled.
if (!isRedirectingStoreEnabled.get()) {
return null;
}
// TODO a better design would be to get these state changes from
// metadata listener callbacks, so we need not allocate these objects
// all the time. This has been implemented, but not integration tested,
// on the following branch:
// https://github.com/voldemort/voldemort/compare/proxy-put-metadata-listener
Cluster sourceCluster = metadata.getRebalancingSourceCluster();
// Logic to get the old storedef
List<StoreDefinition> sourceStoreDefs = metadata.getRebalancingSourceStores();
if (sourceCluster == null) {
if (logger.isTraceEnabled()) {
logger.trace("Old Cluster is null.. bail");
}
return null;
}
if (sourceStoreDefs == null) {
if (logger.isTraceEnabled()) {
logger.trace("Old stores def is null.. bail");
}
return null;
}
StoreDefinition sourceStoreDef = null;
sourceStoreDef = StoreUtils.getStoreDef(sourceStoreDefs, storeDef.getName());
Integer nodeId = metadata.getNodeId();
Integer zoneId = currentRoutingPlan.getCluster().getNodeById(nodeId).getZoneId();
// Use the old store definition to get the routing object
BaseStoreRoutingPlan oldRoutingPlan = new BaseStoreRoutingPlan(sourceCluster, sourceStoreDef);
// Check the current node's relationship to the key.
int zoneNAry = currentRoutingPlan.getZoneNAry(zoneId, nodeId, key);
// Determine which node held the key with the same relationship in the
// old cluster. That is your man!
Integer redirectNodeId;
try {
redirectNodeId = oldRoutingPlan.getNodeIdForZoneNary(zoneId, zoneNAry, key);
} catch (VoldemortException ve) {
/*
* If the zone does not exist, as in the case of Zone Expansion,
* there will be no proxy bridges built. The only other time an
* exception can be thrown here is when the replicaType is invalid.
* But that would mean we are changing say a 2/1/1 store to 3/2/2,
* which Voldemort currently does not support anyway
*/
return null;
}
// Unless he is the same as this node (where this is meaningless effort)
if (redirectNodeId == nodeId) {
return null;
}
return redirectNodeId;
}
use of voldemort.routing.BaseStoreRoutingPlan in project voldemort by voldemort.
the class RoutedStoreTest method testReadRepairWithFailures.
/**
* See Issue #89: Sequential retrieval in RoutedStore.get doesn't consider
* repairReads.
*/
@Test
public void testReadRepairWithFailures() throws Exception {
cluster = getNineNodeCluster();
RoutedStore routedStore = getStore(cluster, 2, 2, 1, 0);
BaseStoreRoutingPlan routingPlan = new BaseStoreRoutingPlan(cluster, this.storeDef);
List<Integer> replicatingNodes = routingPlan.getReplicationNodeList(aKey.get());
// This is node 1
Node primaryNode = Iterables.get(cluster.getNodes(), replicatingNodes.get(0));
// This is node 6
Node secondaryNode = Iterables.get(cluster.getNodes(), replicatingNodes.get(1));
// Disable primary node so that the first put happens with 6 as the
// pseudo master
recordException(failureDetector, primaryNode);
Store<ByteArray, byte[], byte[]> store = new InconsistencyResolvingStore<ByteArray, byte[], byte[]>(routedStore, new VectorClockInconsistencyResolver<byte[]>());
store.put(aKey, new Versioned<byte[]>(aValue), null);
byte[] anotherValue = "john".getBytes();
/*
* Disable the secondary node and enable primary node to prevent the
* secondary from getting the new version
*/
recordException(failureDetector, secondaryNode);
recordSuccess(failureDetector, primaryNode);
// Generate the clock based off secondary so that the resulting clock
// will be [1:1, 6:1] across the replicas, except for the secondary
// which will be [6:1]
VectorClock clock = getClock(6);
store.put(aKey, new Versioned<byte[]>(anotherValue, clock), null);
// Enable secondary and disable primary, the following get should cause
// a read repair on the secondary in the code path that is only executed
// if there are failures. This should repair the secondary with the
// superceding clock [1:1,6:1]
recordException(failureDetector, primaryNode);
recordSuccess(failureDetector, secondaryNode);
List<Versioned<byte[]>> versioneds = store.get(aKey, null);
assertEquals(1, versioneds.size());
assertEquals(new ByteArray(anotherValue), new ByteArray(versioneds.get(0).getValue()));
// Read repairs are done asynchronously, so we sleep for a short period.
// It may be a good idea to use a synchronous executor service.
Thread.sleep(500);
for (Map.Entry<Integer, Store<ByteArray, byte[], byte[]>> innerStoreEntry : routedStore.getInnerStores().entrySet()) {
// Only look at the nodes in the pref list
if (replicatingNodes.contains(innerStoreEntry.getKey())) {
List<Versioned<byte[]>> innerVersioneds = innerStoreEntry.getValue().get(aKey, null);
assertEquals(1, versioneds.size());
assertEquals(new ByteArray(anotherValue), new ByteArray(innerVersioneds.get(0).getValue()));
}
}
}
use of voldemort.routing.BaseStoreRoutingPlan in project voldemort by voldemort.
the class AbstractNonZonedRebalanceTest method populateData.
protected void populateData(Cluster cluster, StoreDefinition storeDef, AdminClient adminClient, boolean isReadOnly) throws Exception {
// Populate Read write stores
if (!isReadOnly) {
// Create SocketStores for each Node first
Map<Integer, Store<ByteArray, byte[], byte[]>> storeMap = new HashMap<Integer, Store<ByteArray, byte[], byte[]>>();
for (Node node : cluster.getNodes()) {
storeMap.put(node.getId(), getSocketStore(storeDef.getName(), node.getHost(), node.getSocketPort()));
}
BaseStoreRoutingPlan storeInstance = new BaseStoreRoutingPlan(cluster, storeDef);
for (Entry<String, String> entry : testEntries.entrySet()) {
ByteArray keyBytes = new ByteArray(ByteUtils.getBytes(entry.getKey(), "UTF-8"));
List<Integer> preferenceNodes = storeInstance.getReplicationNodeList(keyBytes.get());
// Go over every node
for (int nodeId : preferenceNodes) {
try {
storeMap.get(nodeId).put(keyBytes, new Versioned<byte[]>(ByteUtils.getBytes(entry.getValue(), "UTF-8")), null);
} catch (ObsoleteVersionException e) {
logger.info("Why are we seeing this at all here ?? ");
e.printStackTrace();
}
}
}
// close all socket stores
for (Store<ByteArray, byte[], byte[]> store : storeMap.values()) {
store.close();
}
} else {
// Populate Read only stores
File baseDir = TestUtils.createTempDir();
JsonReader reader = ReadOnlyStorageEngineTestInstance.makeTestDataReader(testEntries, baseDir);
RoutingStrategy router = new RoutingStrategyFactory().updateRoutingStrategy(storeDef, cluster);
File outputDir = TestUtils.createTempDir(baseDir);
JsonStoreBuilder storeBuilder = new JsonStoreBuilder(reader, cluster, storeDef, router, outputDir, null, testEntries.size() / 5, 1, NUM_RO_CHUNKS_PER_BUCKET, 10000, false);
storeBuilder.build(ReadOnlyStorageFormat.READONLY_V2);
AdminStoreSwapper swapper = new AdminStoreSwapper(Executors.newFixedThreadPool(cluster.getNumberOfNodes()), adminClient, 100000);
swapper.fetchAndSwapStoreData(testStoreNameRO, outputDir.getAbsolutePath(), 1L);
}
}
use of voldemort.routing.BaseStoreRoutingPlan in project voldemort by voldemort.
the class AbstractZonedRebalanceTest method populateData.
private void populateData(Cluster cluster, StoreDefinition storeDef) throws Exception {
// Create SocketStores for each Node first
Map<Integer, Store<ByteArray, byte[], byte[]>> storeMap = new HashMap<Integer, Store<ByteArray, byte[], byte[]>>();
for (Node node : cluster.getNodes()) {
storeMap.put(node.getId(), getSocketStore(storeDef.getName(), node.getHost(), node.getSocketPort()));
}
BaseStoreRoutingPlan storeInstance = new BaseStoreRoutingPlan(cluster, storeDef);
for (Entry<String, String> entry : testEntries.entrySet()) {
ByteArray keyBytes = new ByteArray(ByteUtils.getBytes(entry.getKey(), "UTF-8"));
List<Integer> preferenceNodes = storeInstance.getReplicationNodeList(keyBytes.get());
// Go over every node
for (int nodeId : preferenceNodes) {
try {
storeMap.get(nodeId).put(keyBytes, new Versioned<byte[]>(ByteUtils.getBytes(entry.getValue(), "UTF-8")), null);
} catch (ObsoleteVersionException e) {
logger.info("Why are we seeing this at all here ?? ");
e.printStackTrace();
}
}
}
// close all socket stores
for (Store<ByteArray, byte[], byte[]> store : storeMap.values()) {
store.close();
}
}
Aggregations