use of voldemort.client.protocol.admin.AdminClient in project voldemort by voldemort.
the class AdminServiceRequestHandler method handleFetchFailure.
private Message handleFetchFailure(VAdminProto.HandleFetchFailureRequest handleFetchFailure) {
String storeName = handleFetchFailure.getStoreName();
long pushVersion = handleFetchFailure.getPushVersion();
String extraInfo = handleFetchFailure.getInfo();
Properties extraInfoProperties = new Properties();
try {
extraInfoProperties.load(new StringReader(extraInfo));
} catch (IOException e) {
logger.error("Got IOException while trying to decipher a HandleFetchFailureRequest's info.", e);
}
logger.info("Received HandleFetchFailureRequest:\n" + "\tstore_name: " + storeName + "\n" + "\tpush_version: " + pushVersion + "\n" + "\tinfo: " + extraInfoProperties.toString());
VAdminProto.HandleFetchFailureResponse.Builder response = VAdminProto.HandleFetchFailureResponse.newBuilder();
AdminClient adminClient = AdminClient.createTempAdminClient(voldemortConfig, metadataStore.getCluster(), 1);
try {
// Get replica.factor for current store
StoreDefinition storeDef = adminClient.metadataMgmtOps.getStoreDefinition(storeName);
if (null == storeDef) {
throw new StoreNotFoundException(storeName);
}
int replicaFactor = storeDef.getReplicationFactor();
int maxNodeFailure = voldemortConfig.getHighAvailabilityPushMaxNodeFailures();
// Considering replicaFactor could be smaller than maxNodeFailure configured in cluster level,
// we need to compare the node failure number with the smaller number of (RF - 1, maxNodeFailure)
// to make sure there is at least one replica running.
maxNodeFailure = Math.min(maxNodeFailure, replicaFactor - 1);
Set<Integer> nodesFailedInThisFetch = Sets.newHashSet(handleFetchFailure.getFailedNodesList());
int failureCount = nodesFailedInThisFetch.size();
boolean swapIsPossible = false;
String responseMessage = "";
if (failureCount > maxNodeFailure) {
// Too many nodes failed to tolerate this strategy... let's bail out.
responseMessage = "We cannot use pushHighAvailability because there is more than " + maxNodeFailure + " nodes that failed their fetches and build.replica.factor is " + replicaFactor + "...";
logger.error(responseMessage);
} else {
FailedFetchLock distributedLock = null;
try {
distributedLock = FailedFetchLock.getLock(voldemortConfig, new Props(extraInfoProperties));
distributedLock.acquireLock();
Set<Integer> alreadyDisabledNodes = distributedLock.getDisabledNodes();
Set<Integer> allNodesToBeDisabled = Sets.newHashSet();
allNodesToBeDisabled.addAll(alreadyDisabledNodes);
allNodesToBeDisabled.addAll(nodesFailedInThisFetch);
int disabledNodeSize = allNodesToBeDisabled.size();
if (disabledNodeSize > maxNodeFailure) {
// Too many exceptions to tolerate this strategy... let's bail out.
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("We cannot use pushHighAvailability because it would bring the total ");
stringBuilder.append("number of nodes with disabled stores to more than ");
stringBuilder.append(maxNodeFailure);
stringBuilder.append("... alreadyDisabledNodes: [");
boolean firstItem = true;
for (Integer nodeId : alreadyDisabledNodes) {
if (firstItem) {
firstItem = false;
} else {
stringBuilder.append(", ");
}
stringBuilder.append(nodeId);
}
stringBuilder.append("], nodesFailedInThisFetch: [");
firstItem = true;
for (Integer nodeId : nodesFailedInThisFetch) {
if (firstItem) {
firstItem = false;
} else {
stringBuilder.append(", ");
}
stringBuilder.append(nodeId);
}
stringBuilder.append("]");
stringBuilder.append(", and build.replica.factor is ").append(replicaFactor);
responseMessage = stringBuilder.toString();
logger.error(responseMessage);
} else {
String nodesString = "node";
if (nodesFailedInThisFetch.size() > 1) {
// Good grammar is important son
nodesString += "s";
}
nodesString += " [";
boolean firstNode = true;
for (Integer nodeId : nodesFailedInThisFetch) {
logger.warn("Will disable store '" + storeName + "' on node " + nodeId);
distributedLock.addDisabledNode(nodeId, storeName, pushVersion);
logger.warn("Store '" + storeName + "' is disabled on node " + nodeId);
if (firstNode) {
firstNode = false;
} else {
nodesString += ", ";
}
nodesString += nodeId;
response.addDisableStoreResponses(adminClient.readonlyOps.disableStoreVersion(nodeId, storeName, pushVersion, extraInfo));
}
nodesString += "]";
swapIsPossible = true;
responseMessage = "Swap will be possible even though " + nodesString + " failed to fetch.";
logger.info(responseMessage);
}
} catch (ClassNotFoundException e) {
String logMessage = "Failed to find requested FailedFetchLock implementation while setting up pushHighAvailability. ";
logger.error(responseMessage, e);
responseMessage = logMessage + "\n" + ExceptionUtils.stackTraceToString(e);
} catch (Exception e) {
String logMessage = "Got exception while trying to execute pushHighAvailability. ";
logger.error(responseMessage, e);
responseMessage = logMessage + "\n" + ExceptionUtils.stackTraceToString(e);
} finally {
if (distributedLock != null) {
try {
distributedLock.releaseLock();
} catch (Exception e) {
logger.error("Error while trying to release the shared lock used for pushHighAvailability!", e);
} finally {
try {
distributedLock.close();
} catch (Exception inception) {
logger.error("Error while trying to close the shared lock used for pushHighAvailability!", inception);
}
}
}
}
}
response.setSwapIsPossible(swapIsPossible);
response.setInfo(responseMessage);
} finally {
adminClient.close();
}
return response.build();
}
use of voldemort.client.protocol.admin.AdminClient in project voldemort by voldemort.
the class AdminServiceRequestHandler method handleAddStore.
public VAdminProto.AddStoreResponse handleAddStore(VAdminProto.AddStoreRequest request) {
VAdminProto.AddStoreResponse.Builder response = VAdminProto.AddStoreResponse.newBuilder();
// don't try to add a store when not in normal or offline state
if (!metadataStore.getServerStateUnlocked().equals(MetadataStore.VoldemortState.NORMAL_SERVER) && !metadataStore.getServerStateUnlocked().equals(MetadataStore.VoldemortState.OFFLINE_SERVER)) {
response.setError(ProtoUtils.encodeError(errorCodeMapper, new VoldemortException("Voldemort server is neither in normal state nor in offline state")));
return response.build();
}
AdminClient adminClient = null;
try {
// adding a store requires decoding the passed in store string
StoreDefinitionsMapper mapper = new StoreDefinitionsMapper();
StoreDefinition def = mapper.readStore(new StringReader(request.getStoreDefinition()));
adminClient = new AdminClient(metadataStore.getCluster());
synchronized (lock) {
if (!storeRepository.hasLocalStore(def.getName())) {
if (def.getReplicationFactor() > metadataStore.getCluster().getNumberOfNodes()) {
throw new StoreOperationFailureException("Cannot add a store whose replication factor ( " + def.getReplicationFactor() + " ) is greater than the number of nodes ( " + metadataStore.getCluster().getNumberOfNodes() + " )");
}
logger.info("Adding new store '" + def.getName() + "'");
// open the store
StorageEngine<ByteArray, byte[], byte[]> engine = storageService.openStore(def);
// effect of updating the stores.xml file)
try {
metadataStore.addStoreDefinition(def);
long defaultQuota = voldemortConfig.getDefaultStorageSpaceQuotaInKB();
QuotaUtils.setQuota(def.getName(), QuotaType.STORAGE_SPACE, storeRepository, metadataStore.getCluster().getNodeIds(), defaultQuota);
} catch (Exception e) {
// rollback open store operation
boolean isReadOnly = ReadOnlyStorageConfiguration.TYPE_NAME.equals(def.getType());
storageService.removeEngine(engine, isReadOnly, def.getType(), true);
throw new VoldemortException(e);
}
logger.info("Successfully added new store '" + def.getName() + "'");
} else {
logger.error("Failure to add a store with the same name '" + def.getName() + "'");
throw new StoreOperationFailureException(String.format("Store '%s' already exists on this server", def.getName()));
}
}
} catch (VoldemortException e) {
response.setError(ProtoUtils.encodeError(errorCodeMapper, e));
logger.error("handleAddStore failed for request(" + request.toString() + ")", e);
} finally {
if (adminClient != null) {
IOUtils.closeQuietly(adminClient);
}
}
return response.build();
}
use of voldemort.client.protocol.admin.AdminClient in project voldemort by voldemort.
the class AdminServiceBasicTest method testStateTransitions.
@Test
public void testStateTransitions() {
// change to REBALANCING STATE
AdminClient client = getAdminClient();
updateRemoteServerState(client, getVoldemortServer(0).getIdentityNode().getId(), MetadataStore.VoldemortState.REBALANCING_MASTER_SERVER, ((VectorClock) client.rebalanceOps.getRemoteServerState(0).getVersion()).incremented(0, System.currentTimeMillis()));
MetadataStore.VoldemortState state = getVoldemortServer(0).getMetadataStore().getServerStateUnlocked();
assertEquals("State should be changed correctly to rebalancing state", MetadataStore.VoldemortState.REBALANCING_MASTER_SERVER, state);
// change back to NORMAL state
updateRemoteServerState(client, getVoldemortServer(0).getIdentityNode().getId(), MetadataStore.VoldemortState.NORMAL_SERVER, ((VectorClock) client.rebalanceOps.getRemoteServerState(0).getVersion()).incremented(0, System.currentTimeMillis()));
state = getVoldemortServer(0).getMetadataStore().getServerStateUnlocked();
assertEquals("State should be changed correctly to rebalancing state", MetadataStore.VoldemortState.NORMAL_SERVER, state);
// lets revert back to REBALANCING STATE AND CHECK
updateRemoteServerState(client, getVoldemortServer(0).getIdentityNode().getId(), MetadataStore.VoldemortState.REBALANCING_MASTER_SERVER, ((VectorClock) client.rebalanceOps.getRemoteServerState(0).getVersion()).incremented(0, System.currentTimeMillis()));
state = getVoldemortServer(0).getMetadataStore().getServerStateUnlocked();
assertEquals("State should be changed correctly to rebalancing state", MetadataStore.VoldemortState.REBALANCING_MASTER_SERVER, state);
// change back to NORMAL_SERVER
updateRemoteServerState(client, getVoldemortServer(0).getIdentityNode().getId(), MetadataStore.VoldemortState.NORMAL_SERVER, ((VectorClock) client.rebalanceOps.getRemoteServerState(0).getVersion()).incremented(0, System.currentTimeMillis()));
state = getVoldemortServer(0).getMetadataStore().getServerStateUnlocked();
assertEquals("State should be changed correctly to normal state", MetadataStore.VoldemortState.NORMAL_SERVER, state);
// change to OFFLINE_SERVER
client.metadataMgmtOps.setRemoteOfflineState(getVoldemortServer(0).getIdentityNode().getId(), true);
state = getVoldemortServer(0).getMetadataStore().getServerStateUnlocked();
assertEquals("State should be changed correctly to offline state", MetadataStore.VoldemortState.OFFLINE_SERVER, state);
// change back to NORMAL_SERVER
client.metadataMgmtOps.setRemoteOfflineState(getVoldemortServer(0).getIdentityNode().getId(), false);
state = getVoldemortServer(0).getMetadataStore().getServerStateUnlocked();
assertEquals("State should be changed correctly to normal state", MetadataStore.VoldemortState.NORMAL_SERVER, state);
}
use of voldemort.client.protocol.admin.AdminClient in project voldemort by voldemort.
the class AdminServiceBasicTest method testAddStore.
@Test
public void testAddStore() throws Exception {
AdminClient adminClient = getAdminClient();
doClientOperation();
// Try to add a store whose replication factor is greater than the
// number of nodes
StoreDefinition definition = new StoreDefinitionBuilder().setName("updateTest").setType(InMemoryStorageConfiguration.TYPE_NAME).setKeySerializer(new SerializerDefinition("string")).setValueSerializer(new SerializerDefinition("string")).setRoutingPolicy(RoutingTier.CLIENT).setRoutingStrategyType(RoutingStrategyType.CONSISTENT_STRATEGY).setReplicationFactor(3).setPreferredReads(1).setRequiredReads(1).setPreferredWrites(1).setRequiredWrites(1).build();
try {
adminClient.storeMgmtOps.addStore(definition);
fail("Should have thrown an exception because we cannot add a store with a replication factor greater than number of nodes");
} catch (Exception e) {
}
// Try adding a legit store using inmemorystorage engine
definition = new StoreDefinitionBuilder().setName("updateTest").setType(InMemoryStorageConfiguration.TYPE_NAME).setKeySerializer(new SerializerDefinition("string")).setValueSerializer(new SerializerDefinition("string")).setRoutingPolicy(RoutingTier.CLIENT).setRoutingStrategyType(RoutingStrategyType.CONSISTENT_STRATEGY).setReplicationFactor(1).setPreferredReads(1).setRequiredReads(1).setPreferredWrites(1).setRequiredWrites(1).build();
adminClient.storeMgmtOps.addStore(definition);
validateQuota(definition.getName());
// now test the store
StoreClientFactory factory = new SocketStoreClientFactory(new ClientConfig().setBootstrapUrls(cluster.getNodeById(0).getSocketUrl().toString()));
StoreClient<Object, Object> client = factory.getStoreClient("updateTest");
client.put("abc", "123");
String s = (String) client.get("abc").getValue();
assertEquals(s, "123");
// test again with a unknown store
try {
client = factory.getStoreClient("updateTest2");
client.put("abc", "123");
s = (String) client.get("abc").getValue();
assertEquals(s, "123");
fail("Should have received bootstrap failure exception");
} catch (Exception e) {
if (!(e instanceof BootstrapFailureException))
throw e;
}
// make sure that the store list we get back from AdminClient
Versioned<List<StoreDefinition>> list = adminClient.metadataMgmtOps.getRemoteStoreDefList(0);
assertTrue(list.getValue().contains(definition));
// Now add a RO store
definition = new StoreDefinitionBuilder().setName("addStoreROFormatTest").setType(ReadOnlyStorageConfiguration.TYPE_NAME).setKeySerializer(new SerializerDefinition("string")).setValueSerializer(new SerializerDefinition("string")).setRoutingPolicy(RoutingTier.CLIENT).setRoutingStrategyType(RoutingStrategyType.CONSISTENT_STRATEGY).setReplicationFactor(1).setPreferredReads(1).setRequiredReads(1).setPreferredWrites(1).setRequiredWrites(1).build();
adminClient.storeMgmtOps.addStore(definition);
validateQuota(definition.getName());
// Retrieve list of read-only stores
List<String> storeNames = Lists.newArrayList();
for (StoreDefinition storeDef : adminClient.metadataMgmtOps.getRemoteStoreDefList(0).getValue()) {
if (storeDef.getType().compareTo(ReadOnlyStorageConfiguration.TYPE_NAME) == 0) {
storeNames.add(storeDef.getName());
}
}
Map<String, String> storeToStorageFormat = adminClient.readonlyOps.getROStorageFormat(0, storeNames);
for (String storeName : storeToStorageFormat.keySet()) {
assertEquals(storeToStorageFormat.get(storeName), "ro2");
}
doClientOperation();
}
use of voldemort.client.protocol.admin.AdminClient in project voldemort by voldemort.
the class AdminServiceBasicTest method testRebalanceQuota.
@Test
public void testRebalanceQuota() throws InterruptedException {
AdminClient client = getAdminClient();
String storeName = storeDefs.get(0).getName();
QuotaType quotaType = QuotaType.GET_THROUGHPUT;
Long quota = 1000L, targetQuota = quota / 2;
client.quotaMgmtOps.setQuotaForNode(storeName, quotaType, 0, quota);
client.quotaMgmtOps.rebalanceQuota(storeName, quotaType);
// rebalanceQuota use put. Put completes as soon as the required nodes
// are completed and rest of them are done in async. There is a race
// condition here if you poll too soon you will see inconsistent result,
// as some of the puts are still in async. Sleep here to avoid those
// conditions.
Thread.sleep(100);
Long getQuota0 = Long.parseLong(client.quotaMgmtOps.getQuotaForNode(storeName, quotaType, 0).getValue());
Long getQuota1 = Long.parseLong(client.quotaMgmtOps.getQuotaForNode(storeName, quotaType, 1).getValue());
assertEquals(targetQuota, getQuota0);
assertEquals(targetQuota, getQuota1);
}
Aggregations