use of org.apache.helix.PropertyKey in project helix by apache.
the class HelixStateTransitionHandler method preHandleMessage.
void preHandleMessage() throws Exception {
if (!_message.isValid()) {
String errorMessage = "Invalid Message, ensure that message: " + _message + " has all the required fields: " + Arrays.toString(Message.Attributes.values());
_statusUpdateUtil.logError(_message, HelixStateTransitionHandler.class, errorMessage, _manager);
logger.error(errorMessage);
throw new HelixException(errorMessage);
}
logger.info("handling message: " + _message.getMsgId() + " transit " + _message.getResourceName() + "." + _message.getPartitionName() + "|" + _message.getPartitionNames() + " from:" + _message.getFromState() + " to:" + _message.getToState() + ", relayedFrom: " + _message.getRelaySrcHost());
HelixDataAccessor accessor = _manager.getHelixDataAccessor();
String partitionName = _message.getPartitionName();
String fromState = _message.getFromState();
// Verify the fromState and current state of the stateModel
String state = _currentStateDelta.getState(partitionName);
// Set start time right before invoke client logic
_currentStateDelta.setStartTime(_message.getPartitionName(), System.currentTimeMillis());
if (fromState != null && !fromState.equals("*") && !fromState.equalsIgnoreCase(state)) {
String errorMessage = "Current state of stateModel does not match the fromState in Message" + ", Current State:" + state + ", message expected:" + fromState + ", partition: " + partitionName + ", from: " + _message.getMsgSrc() + ", to: " + _message.getTgtName();
_statusUpdateUtil.logError(_message, HelixStateTransitionHandler.class, errorMessage, _manager);
logger.error(errorMessage);
throw new HelixStateMismatchException(errorMessage);
}
// Reset the REQUESTED_STATE property if it exists.
try {
String instance = _manager.getInstanceName();
String sessionId = _message.getTgtSessionId();
String resource = _message.getResourceName();
ZNRecordBucketizer bucketizer = new ZNRecordBucketizer(_message.getBucketSize());
PropertyKey key = accessor.keyBuilder().currentState(instance, sessionId, resource, bucketizer.getBucketName(partitionName));
ZNRecord rec = new ZNRecord(resource);
Map<String, String> map = new TreeMap<String, String>();
map.put(CurrentState.CurrentStateProperty.REQUESTED_STATE.name(), null);
rec.getMapFields().put(partitionName, map);
ZNRecordDelta delta = new ZNRecordDelta(rec, ZNRecordDelta.MergeOperation.SUBTRACT);
List<ZNRecordDelta> deltaList = new ArrayList<ZNRecordDelta>();
deltaList.add(delta);
CurrentState currStateUpdate = new CurrentState(resource);
currStateUpdate.setDeltaList(deltaList);
// Update the ZK current state of the node
if (!accessor.updateProperty(key, currStateUpdate)) {
logger.error("Fails to persist current state back to ZK for resource " + resource + " partition: " + partitionName);
}
} catch (Exception e) {
logger.error("Error when removing " + CurrentState.CurrentStateProperty.REQUESTED_STATE.name() + " from current state.", e);
StateTransitionError error = new StateTransitionError(ErrorType.FRAMEWORK, ErrorCode.ERROR, e);
_stateModel.rollbackOnError(_message, _notificationContext, error);
_statusUpdateUtil.logError(_message, HelixStateTransitionHandler.class, e, "Error when removing " + CurrentState.CurrentStateProperty.REQUESTED_STATE.name() + " from current state.", _manager);
}
}
use of org.apache.helix.PropertyKey in project helix by apache.
the class HelixTaskExecutor method updateMessageState.
private void updateMessageState(List<Message> readMsgs, HelixDataAccessor accessor, String instanceName) {
Builder keyBuilder = accessor.keyBuilder();
List<PropertyKey> readMsgKeys = new ArrayList<>();
for (Message msg : readMsgs) {
readMsgKeys.add(msg.getKey(keyBuilder, instanceName));
_knownMessageIds.add(msg.getId());
}
accessor.setChildren(readMsgKeys, readMsgs);
}
use of org.apache.helix.PropertyKey in project ambry by linkedin.
the class HelixHealthReportAggregationTaskTest method initializeNodeReports.
/**
* Initialize the reports and create instances in helix if not exists.
* @param type The type of reports to create
* @param numNode The number of nodes to initiate.
* @param startingPort The starting port number, which will then be incremented to represent different nodes.
* @throws IOException
*/
private void initializeNodeReports(StatsReportType type, int numNode, int startingPort) throws IOException {
String healthReportName = type == StatsReportType.ACCOUNT_REPORT ? HEALTH_REPORT_NAME_ACCOUNT : HEALTH_REPORT_NAME_PARTITION;
String statsFieldName = type == StatsReportType.ACCOUNT_REPORT ? STATS_FIELD_NAME_ACCOUNT : STATS_FIELD_NAME_PARTITION;
List<StatsSnapshot> storeSnapshots = new ArrayList<>();
Random random = new Random();
for (int i = 3; i < 6; i++) {
storeSnapshots.add(TestUtils.generateStoreStats(i, 3, random, type));
}
StatsWrapper nodeStats = TestUtils.generateNodeStats(storeSnapshots, 1000, type);
String nodeStatsJSON = mapper.writeValueAsString(nodeStats);
HelixDataAccessor dataAccessor = mockHelixManager.getHelixDataAccessor();
for (int i = 0; i < numNode; i++) {
String instanceName = ClusterMapUtils.getInstanceName("localhost", startingPort);
InstanceConfig instanceConfig = new InstanceConfig(instanceName);
instanceConfig.setHostName("localhost");
instanceConfig.setPort(Integer.toString(startingPort));
mockHelixAdmin.addInstance(CLUSTER_NAME, instanceConfig);
PropertyKey key = dataAccessor.keyBuilder().healthReport(instanceName, healthReportName);
ZNRecord znRecord = new ZNRecord(instanceName);
// Set the same reports for all instances
znRecord.setSimpleField(statsFieldName, nodeStatsJSON);
HelixProperty helixProperty = new HelixProperty(znRecord);
dataAccessor.setProperty(key, helixProperty);
startingPort++;
}
}
use of org.apache.helix.PropertyKey in project ambry by linkedin.
the class MockHelixDataAccessor method getProperty.
@Override
public <T extends HelixProperty> List<T> getProperty(List<PropertyKey> keys, boolean throwException) {
List<T> result = new ArrayList<>();
for (PropertyKey key : keys) {
if (key.toString().matches("/Ambry-/INSTANCES/.*/CURRENTSTATES/\\d+/\\d+")) {
// an example for the key: /Ambry-/INSTANCES/localhost_18089/CURRENTSTATES/sessionId/0
String[] segments = key.toString().split("/");
String instanceName = segments[3];
String resourceName = segments[6];
Map<String, Map<String, String>> partitionStateMap = mockHelixAdmin.getPartitionStateMapForInstance(instanceName);
ZNRecord record = new ZNRecord(resourceName);
record.setMapFields(partitionStateMap);
result.add((T) (new CurrentState(record)));
} else if (key.toString().matches("/Ambry-/LIVEINSTANCES/.*_\\d+")) {
String[] segments = key.toString().split("/");
String instanceName = segments[3];
ZNRecord record = new ZNRecord(instanceName);
record.setEphemeralOwner(SESSION_ID);
result.add((T) (new LiveInstance(record)));
} else if (key.toString().matches("/Ambry-/CONFIGS/PARTICIPANT/.*_\\d+")) {
String[] segments = key.toString().split("/");
String instanceName = segments[4];
InstanceConfig instanceConfig = mockHelixAdmin.getInstanceConfigs(clusterName).stream().filter(config -> config.getInstanceName().equals(instanceName)).findFirst().get();
result.add((T) instanceConfig);
} else {
result.add((T) properties.get(key));
}
}
return result;
}
use of org.apache.helix.PropertyKey in project helix by apache.
the class CurrentStateSnapshot method getNewCurrentStateEndTimes.
/**
* Return the end times of all recent changed current states update.
*/
public Map<PropertyKey, Map<String, Long>> getNewCurrentStateEndTimes() {
Map<PropertyKey, Map<String, Long>> endTimeMap = new HashMap<>();
if (_updatedStateKeys != null && _prevStateMap != null) {
// Note if the prev state map is empty, this is the first time refresh.
// So the update is not considered as "recent" change.
// clock drift count for comparing timestamp
int driftCnt = 0;
for (PropertyKey propertyKey : _updatedStateKeys) {
CurrentState prevState = _prevStateMap.get(propertyKey);
CurrentState curState = _properties.get(propertyKey);
Map<String, Long> partitionUpdateEndTimes = null;
for (String partition : curState.getPartitionStateMap().keySet()) {
long newEndTime = curState.getEndTime(partition);
// statePropagation latency calculation in RoutingTableProvider would spit out extremely large metrics.
if ((prevState == null || prevState.getEndTime(partition) < newEndTime) && newEndTime != -1) {
if (partitionUpdateEndTimes == null) {
partitionUpdateEndTimes = new HashMap<>();
}
partitionUpdateEndTimes.put(partition, newEndTime);
} else if (prevState != null && prevState.getEndTime(partition) > newEndTime) {
// If clock drift turns out to be common, we can consider print out more logs, or expose an metric.
if (driftCnt < 1) {
LOG.warn("clock drift. partition:" + partition + " curState:" + curState.getState(partition) + " prevState: " + prevState.getState(partition));
}
driftCnt++;
}
}
if (partitionUpdateEndTimes != null) {
endTimeMap.put(propertyKey, partitionUpdateEndTimes);
}
}
}
return endTimeMap;
}
Aggregations