use of org.apache.helix.BaseDataAccessor in project pinot by linkedin.
the class HelixHelper method updateIdealState.
/**
* Updates the ideal state, retrying if necessary in case of concurrent updates to the ideal state.
*
* @param helixManager The HelixManager used to interact with the Helix cluster
* @param resourceName The resource for which to update the ideal state
* @param updater A function that returns an updated ideal state given an input ideal state
*/
public static void updateIdealState(final HelixManager helixManager, final String resourceName, final Function<IdealState, IdealState> updater, RetryPolicy policy) {
boolean successful = policy.attempt(new Callable<Boolean>() {
@Override
public Boolean call() {
HelixDataAccessor dataAccessor = helixManager.getHelixDataAccessor();
PropertyKey propertyKey = dataAccessor.keyBuilder().idealStates(resourceName);
// Create an updated version of the ideal state
IdealState idealState = dataAccessor.getProperty(propertyKey);
PropertyKey key = dataAccessor.keyBuilder().idealStates(resourceName);
String path = key.getPath();
// Make a copy of the the idealState above to pass it to the updater, instead of querying again,
// as the state my change between the queries.
ZNRecordSerializer znRecordSerializer = new ZNRecordSerializer();
IdealState idealStateCopy = new IdealState((ZNRecord) znRecordSerializer.deserialize(znRecordSerializer.serialize(idealState.getRecord())));
IdealState updatedIdealState;
try {
updatedIdealState = updater.apply(idealStateCopy);
} catch (Exception e) {
LOGGER.error("Caught exception while updating ideal state", e);
return false;
}
// If there are changes to apply, apply them
if (!EqualityUtils.isEqual(idealState, updatedIdealState) && updatedIdealState != null) {
BaseDataAccessor<ZNRecord> baseDataAccessor = dataAccessor.getBaseDataAccessor();
boolean success;
// If the ideal state is large enough, enable compression
if (MAX_PARTITION_COUNT_IN_UNCOMPRESSED_IDEAL_STATE < updatedIdealState.getPartitionSet().size()) {
updatedIdealState.getRecord().setBooleanField("enableCompression", true);
}
try {
success = baseDataAccessor.set(path, updatedIdealState.getRecord(), idealState.getRecord().getVersion(), AccessOption.PERSISTENT);
} catch (Exception e) {
boolean idealStateIsCompressed = updatedIdealState.getRecord().getBooleanField("enableCompression", false);
LOGGER.warn("Caught exception while updating ideal state for resource {} (compressed={}), retrying.", resourceName, idealStateIsCompressed, e);
return false;
}
if (success) {
return true;
} else {
LOGGER.warn("Failed to update ideal state for resource {}, retrying.", resourceName);
return false;
}
} else {
LOGGER.warn("Idempotent or null ideal state update for resource {}, skipping update.", resourceName);
return true;
}
}
});
if (!successful) {
throw new RuntimeException("Failed to update ideal state for resource " + resourceName);
}
}
use of org.apache.helix.BaseDataAccessor in project helix by apache.
the class CallbackHandler method subscribeForChanges.
private void subscribeForChanges(NotificationContext.Type callbackType, String path, boolean watchChild) {
long start = System.currentTimeMillis();
if (_eventTypes.contains(EventType.NodeDataChanged) || _eventTypes.contains(EventType.NodeCreated) || _eventTypes.contains(EventType.NodeDeleted)) {
if (logger.isDebugEnabled()) {
logger.debug("Subscribing data change listener to path:" + path);
}
subscribeDataChange(path, callbackType);
}
if (_eventTypes.contains(EventType.NodeChildrenChanged)) {
if (logger.isDebugEnabled()) {
logger.debug("Subscribing child change listener to path:" + path);
}
subscribeChildChange(path, callbackType);
if (watchChild) {
if (logger.isDebugEnabled()) {
logger.debug("Subscribing data change listener to all children for path:" + path);
}
try {
switch(_changeType) {
case CURRENT_STATE:
case IDEAL_STATE:
case EXTERNAL_VIEW:
case TARGET_EXTERNAL_VIEW:
{
// check if bucketized
BaseDataAccessor<ZNRecord> baseAccessor = new ZkBaseDataAccessor<>(_zkClient);
List<ZNRecord> records = baseAccessor.getChildren(path, null, 0);
for (ZNRecord record : records) {
HelixProperty property = new HelixProperty(record);
String childPath = path + "/" + record.getId();
int bucketSize = property.getBucketSize();
if (bucketSize > 0) {
// subscribe both data-change and child-change on bucketized parent node
// data-change gives a delete-callback which is used to remove watch
subscribeChildChange(childPath, callbackType);
subscribeDataChange(childPath, callbackType);
// subscribe data-change on bucketized child
List<String> bucketizedChildNames = _zkClient.getChildren(childPath);
if (bucketizedChildNames != null) {
for (String bucketizedChildName : bucketizedChildNames) {
String bucketizedChildPath = childPath + "/" + bucketizedChildName;
subscribeDataChange(bucketizedChildPath, callbackType);
}
}
} else {
subscribeDataChange(childPath, callbackType);
}
}
break;
}
default:
{
List<String> childNames = _zkClient.getChildren(path);
if (childNames != null) {
for (String childName : childNames) {
String childPath = path + "/" + childName;
subscribeDataChange(childPath, callbackType);
}
}
break;
}
}
} catch (ZkNoNodeException e) {
logger.warn("fail to subscribe child/data change. path: " + path + ", listener: " + _listener, e);
}
}
}
long end = System.currentTimeMillis();
logger.info("Subscribing to path:" + path + " took:" + (end - start));
}
Aggregations