use of com.google.common.util.concurrent.FutureCallback in project buck by facebook.
the class CachingBuildEngine method processBuildRule.
private ListenableFuture<BuildResult> processBuildRule(BuildRule rule, BuildEngineBuildContext buildContext, ExecutionContext executionContext, ConcurrentLinkedQueue<ListenableFuture<Void>> asyncCallbacks) {
final RuleKeyFactories keyFactories = ruleKeyFactories.apply(rule.getProjectFilesystem());
final OnDiskBuildInfo onDiskBuildInfo = buildContext.createOnDiskBuildInfoFor(rule.getBuildTarget(), rule.getProjectFilesystem());
final BuildInfoRecorder buildInfoRecorder = buildContext.createBuildInfoRecorder(rule.getBuildTarget(), rule.getProjectFilesystem()).addBuildMetadata(BuildInfo.MetadataKey.RULE_KEY, keyFactories.getDefaultRuleKeyFactory().build(rule).toString());
final BuildableContext buildableContext = new DefaultBuildableContext(buildInfoRecorder);
final AtomicReference<Long> outputSize = Atomics.newReference();
ListenableFuture<BuildResult> buildResult = processBuildRule(rule, buildContext, executionContext, onDiskBuildInfo, buildInfoRecorder, buildableContext, asyncCallbacks);
// materialized locally by chaining up to our result future.
if (buildMode == BuildMode.DEEP || buildMode == BuildMode.POPULATE_FROM_REMOTE_CACHE) {
buildResult = MoreFutures.chainExceptions(getDepResults(rule, buildContext, executionContext, asyncCallbacks), buildResult);
}
// Setup a callback to handle either the cached or built locally cases.
AsyncFunction<BuildResult, BuildResult> callback = input -> {
if (input.getStatus() != BuildRuleStatus.SUCCESS) {
return Futures.immediateFuture(input);
}
BuildRuleSuccessType success = Preconditions.checkNotNull(input.getSuccess());
if (success != BuildRuleSuccessType.BUILT_LOCALLY) {
for (String str : onDiskBuildInfo.getValuesOrThrow(BuildInfo.MetadataKey.RECORDED_PATHS)) {
buildInfoRecorder.recordArtifact(Paths.get(str));
}
}
outputSize.set(buildInfoRecorder.getOutputSize());
if (success.outputsHaveChanged()) {
if (rule instanceof HasPostBuildSteps) {
executePostBuildSteps(rule, ((HasPostBuildSteps) rule).getPostBuildSteps(buildContext.getBuildContext()), executionContext);
}
for (Path path : buildInfoRecorder.getRecordedPaths()) {
fileHashCache.invalidate(rule.getProjectFilesystem().resolve(path));
}
}
if (useDependencyFileRuleKey(rule) && success == BuildRuleSuccessType.BUILT_LOCALLY) {
ImmutableList<SourcePath> inputs = ((SupportsDependencyFileRuleKey) rule).getInputsAfterBuildingLocally(buildContext.getBuildContext());
ImmutableList<String> inputStrings = inputs.stream().map(inputString -> DependencyFileEntry.fromSourcePath(inputString, pathResolver)).map(MoreFunctions.toJsonFunction(objectMapper)).collect(MoreCollectors.toImmutableList());
buildInfoRecorder.addMetadata(BuildInfo.MetadataKey.DEP_FILE, inputStrings);
Optional<RuleKeyAndInputs> depFileRuleKeyAndInputs = calculateDepFileRuleKey(rule, buildContext, Optional.of(inputStrings), false);
if (depFileRuleKeyAndInputs.isPresent()) {
RuleKey depFileRuleKey = depFileRuleKeyAndInputs.get().getRuleKey();
buildInfoRecorder.addBuildMetadata(BuildInfo.MetadataKey.DEP_FILE_RULE_KEY, depFileRuleKey.toString());
if (useManifestCaching(rule)) {
Optional<RuleKeyAndInputs> manifestKey = calculateManifestKey(rule, buildContext.getEventBus());
if (manifestKey.isPresent()) {
buildInfoRecorder.addBuildMetadata(BuildInfo.MetadataKey.MANIFEST_KEY, manifestKey.get().getRuleKey().toString());
updateAndStoreManifest(rule, depFileRuleKeyAndInputs.get().getRuleKey(), depFileRuleKeyAndInputs.get().getInputs(), manifestKey.get(), buildContext.getArtifactCache());
}
}
}
}
if (success == BuildRuleSuccessType.BUILT_LOCALLY && shouldUploadToCache(rule, Preconditions.checkNotNull(outputSize.get()))) {
ImmutableSortedMap.Builder<String, String> outputHashes = ImmutableSortedMap.naturalOrder();
for (Path path : buildInfoRecorder.getOutputPaths()) {
outputHashes.put(path.toString(), fileHashCache.get(rule.getProjectFilesystem().resolve(path)).toString());
}
buildInfoRecorder.addBuildMetadata(BuildInfo.MetadataKey.RECORDED_PATH_HASHES, outputHashes.build());
}
if (success != BuildRuleSuccessType.BUILT_LOCALLY && success.outputsHaveChanged()) {
Optional<ImmutableMap<String, String>> hashes = onDiskBuildInfo.getBuildMap(BuildInfo.MetadataKey.RECORDED_PATH_HASHES);
if (hashes.isPresent() && verifyRecordedPathHashes(rule.getBuildTarget(), rule.getProjectFilesystem(), hashes.get())) {
for (Map.Entry<String, String> ent : hashes.get().entrySet()) {
Path path = rule.getProjectFilesystem().getPath(ent.getKey());
HashCode hashCode = HashCode.fromString(ent.getValue());
fileHashCache.set(rule.getProjectFilesystem().resolve(path), hashCode);
}
}
}
buildInfoRecorder.addBuildMetadata(BuildInfo.MetadataKey.TARGET, rule.getBuildTarget().toString());
buildInfoRecorder.addMetadata(BuildInfo.MetadataKey.RECORDED_PATHS, buildInfoRecorder.getRecordedPaths().stream().map(Object::toString).collect(MoreCollectors.toImmutableList()));
if (success.shouldWriteRecordedMetadataToDiskAfterBuilding()) {
try {
boolean clearExistingMetadata = success.shouldClearAndOverwriteMetadataOnDisk();
buildInfoRecorder.writeMetadataToDisk(clearExistingMetadata);
} catch (IOException e) {
throw new IOException(String.format("Failed to write metadata to disk for %s.", rule), e);
}
}
try {
if (rule instanceof InitializableFromDisk) {
doInitializeFromDisk((InitializableFromDisk<?>) rule, onDiskBuildInfo);
}
} catch (IOException e) {
throw new IOException(String.format("Error initializing %s from disk.", rule), e);
}
return Futures.immediateFuture(input);
};
buildResult = Futures.transformAsync(buildResult, ruleAsyncFunction(rule, buildContext.getEventBus(), callback), serviceByAdjustingDefaultWeightsTo(RULE_KEY_COMPUTATION_RESOURCE_AMOUNTS));
// Handle either build success or failure.
final SettableFuture<BuildResult> result = SettableFuture.create();
asyncCallbacks.add(MoreFutures.addListenableCallback(buildResult, new FutureCallback<BuildResult>() {
// TODO(bolinfest): Delete all files produced by the rule, as they are not guaranteed
// to be valid at this point?
private void cleanupAfterError() {
try {
onDiskBuildInfo.deleteExistingMetadata();
} catch (Throwable t) {
buildContext.getEventBus().post(ThrowableConsoleEvent.create(t, "Error when deleting metadata for %s.", rule));
}
}
private void uploadToCache(BuildRuleSuccessType success) {
// Collect up all the rule keys we have index the artifact in the cache with.
Set<RuleKey> ruleKeys = Sets.newHashSet();
// If the rule key has changed (and is not already in the cache), we need to push
// the artifact to cache using the new key.
ruleKeys.add(keyFactories.getDefaultRuleKeyFactory().build(rule));
// using the new key.
if (SupportsInputBasedRuleKey.isSupported(rule)) {
Optional<RuleKey> calculatedRuleKey = calculateInputBasedRuleKey(rule, buildContext.getEventBus());
Optional<RuleKey> onDiskRuleKey = onDiskBuildInfo.getRuleKey(BuildInfo.MetadataKey.INPUT_BASED_RULE_KEY);
Optional<RuleKey> metaDataRuleKey = buildInfoRecorder.getBuildMetadataFor(BuildInfo.MetadataKey.INPUT_BASED_RULE_KEY).map(RuleKey::new);
Preconditions.checkState(calculatedRuleKey.equals(onDiskRuleKey), "%s (%s): %s: invalid on-disk input-based rule key: %s != %s", rule.getBuildTarget(), rule.getType(), success, calculatedRuleKey, onDiskRuleKey);
Preconditions.checkState(calculatedRuleKey.equals(metaDataRuleKey), "%s: %s: invalid meta-data input-based rule key: %s != %s", rule.getBuildTarget(), success, calculatedRuleKey, metaDataRuleKey);
ruleKeys.addAll(OptionalCompat.asSet(calculatedRuleKey));
}
// using the new key.
if (useManifestCaching(rule)) {
Optional<RuleKey> onDiskRuleKey = onDiskBuildInfo.getRuleKey(BuildInfo.MetadataKey.DEP_FILE_RULE_KEY);
Optional<RuleKey> metaDataRuleKey = buildInfoRecorder.getBuildMetadataFor(BuildInfo.MetadataKey.DEP_FILE_RULE_KEY).map(RuleKey::new);
Preconditions.checkState(onDiskRuleKey.equals(metaDataRuleKey), "%s: %s: inconsistent meta-data and on-disk dep-file rule key: %s != %s", rule.getBuildTarget(), success, onDiskRuleKey, metaDataRuleKey);
ruleKeys.addAll(OptionalCompat.asSet(onDiskRuleKey));
}
// Do the actual upload.
try {
// Verify that the recorded path hashes are accurate.
Optional<String> recordedPathHashes = buildInfoRecorder.getBuildMetadataFor(BuildInfo.MetadataKey.RECORDED_PATH_HASHES);
if (recordedPathHashes.isPresent() && !verifyRecordedPathHashes(rule.getBuildTarget(), rule.getProjectFilesystem(), recordedPathHashes.get())) {
return;
}
// Push to cache.
buildInfoRecorder.performUploadToArtifactCache(ImmutableSet.copyOf(ruleKeys), buildContext.getArtifactCache(), buildContext.getEventBus());
} catch (Throwable t) {
buildContext.getEventBus().post(ThrowableConsoleEvent.create(t, "Error uploading to cache for %s.", rule));
}
}
private void handleResult(BuildResult input) {
Optional<Long> outputSize = Optional.empty();
Optional<HashCode> outputHash = Optional.empty();
Optional<BuildRuleSuccessType> successType = Optional.empty();
BuildRuleEvent.Resumed resumedEvent = BuildRuleEvent.resumed(rule, buildRuleDurationTracker, keyFactories.getDefaultRuleKeyFactory());
buildContext.getEventBus().logVerboseAndPost(LOG, resumedEvent);
if (input.getStatus() == BuildRuleStatus.FAIL) {
// Make this failure visible for other rules, so that they can stop early.
firstFailure = input.getFailure();
// If we failed, cleanup the state of this rule.
cleanupAfterError();
}
// Unblock dependents.
result.set(input);
if (input.getStatus() == BuildRuleStatus.SUCCESS) {
BuildRuleSuccessType success = Preconditions.checkNotNull(input.getSuccess());
successType = Optional.of(success);
// Try get the output size.
try {
outputSize = Optional.of(buildInfoRecorder.getOutputSize());
} catch (IOException e) {
buildContext.getEventBus().post(ThrowableConsoleEvent.create(e, "Error getting output size for %s.", rule));
}
// If this rule is cacheable, upload it to the cache.
if (success.shouldUploadResultingArtifact() && outputSize.isPresent() && shouldUploadToCache(rule, outputSize.get())) {
uploadToCache(success);
}
// Calculate the hash of outputs that were built locally and are cacheable.
if (success == BuildRuleSuccessType.BUILT_LOCALLY && shouldUploadToCache(rule, outputSize.get())) {
try {
outputHash = Optional.of(buildInfoRecorder.getOutputHash(fileHashCache));
} catch (IOException e) {
buildContext.getEventBus().post(ThrowableConsoleEvent.create(e, "Error getting output hash for %s.", rule));
}
}
}
// Log the result to the event bus.
BuildRuleEvent.Finished finished = BuildRuleEvent.finished(resumedEvent, BuildRuleKeys.builder().setRuleKey(keyFactories.getDefaultRuleKeyFactory().build(rule)).setInputRuleKey(onDiskBuildInfo.getRuleKey(BuildInfo.MetadataKey.INPUT_BASED_RULE_KEY)).setDepFileRuleKey(onDiskBuildInfo.getRuleKey(BuildInfo.MetadataKey.DEP_FILE_RULE_KEY)).setManifestRuleKey(onDiskBuildInfo.getRuleKey(BuildInfo.MetadataKey.MANIFEST_KEY)).build(), input.getStatus(), input.getCacheResult(), successType, outputHash, outputSize);
buildContext.getEventBus().logVerboseAndPost(LOG, finished);
}
@Override
public void onSuccess(BuildResult input) {
handleResult(input);
}
@Override
public void onFailure(@Nonnull Throwable thrown) {
thrown = maybeAttachBuildRuleNameToException(thrown, rule);
handleResult(BuildResult.failure(rule, thrown));
// Reset interrupted flag once failure has been recorded.
if (thrown instanceof InterruptedException) {
Thread.currentThread().interrupt();
}
}
}));
return result;
}
use of com.google.common.util.concurrent.FutureCallback in project bitsquare by bitsquare.
the class WithdrawalView method onWithdraw.
///////////////////////////////////////////////////////////////////////////////////////////
// UI handlers
///////////////////////////////////////////////////////////////////////////////////////////
@FXML
public void onWithdraw() {
if (areInputsValid()) {
FutureCallback<Transaction> callback = new FutureCallback<Transaction>() {
@Override
public void onSuccess(@javax.annotation.Nullable Transaction transaction) {
if (transaction != null) {
log.debug("onWithdraw onSuccess tx ID:" + transaction.getHashAsString());
} else {
log.error("onWithdraw transaction is null");
}
List<Trade> trades = new ArrayList<>(tradeManager.getTrades());
trades.stream().filter(trade -> trade.getState().getPhase() == Trade.Phase.PAYOUT_PAID).forEach(trade -> {
if (walletService.getBalanceForAddress(walletService.getOrCreateAddressEntry(trade.getId(), AddressEntry.Context.TRADE_PAYOUT).getAddress()).isZero())
tradeManager.addTradeToClosedTrades(trade);
});
}
@Override
public void onFailure(@NotNull Throwable t) {
log.error("onWithdraw onFailure");
}
};
try {
// We need to use the max. amount (amountOfSelectedItems) as the senderAmount might be less then
// we have available and then the fee calculation would return 0
// TODO Get a proper fee calculation from BitcoinJ directly
Coin requiredFee = null;
try {
requiredFee = walletService.getRequiredFeeForMultipleAddresses(fromAddresses, withdrawToTextField.getText(), amountOfSelectedItems);
} catch (InsufficientFundsException e) {
try {
int txSize = walletService.getTransactionSize(fromAddresses, withdrawToTextField.getText(), senderAmountAsCoinProperty.get().subtract(FeePolicy.getNonTradeFeePerKb()));
new Popup<>().warning(e.getMessage() + "\n" + "Transaction size: " + (txSize / 1000d) + " Kb").show();
} catch (InsufficientMoneyException e2) {
new Popup<>().warning(e.getMessage()).show();
}
} catch (Throwable t) {
try {
// TODO Using amountOfSelectedItems caused problems if it exceeds the max size (in case of arbitrator)
log.warn("Error at getRequiredFeeForMultipleAddresses: " + t.toString() + "\n" + "We use the default fee instead to estimate tx size and then re-calculate fee.");
int tempTxSize = walletService.getTransactionSize(fromAddresses, withdrawToTextField.getText(), senderAmountAsCoinProperty.get().subtract(FeePolicy.getNonTradeFeePerKb()));
requiredFee = Coin.valueOf(FeePolicy.getNonTradeFeePerKb().value * tempTxSize / 1000);
} catch (Throwable t2) {
t2.printStackTrace();
log.error(t2.toString());
new Popup<>().error("Error at creating transaction: " + t2.toString()).show();
}
}
if (requiredFee != null) {
Coin receiverAmount = senderAmountAsCoinProperty.get().subtract(requiredFee);
int txSize = walletService.getTransactionSize(fromAddresses, withdrawToTextField.getText(), receiverAmount);
log.info("Fee for tx with size {}: {} BTC", txSize, requiredFee.toPlainString());
if (receiverAmount.isPositive()) {
if (DevFlags.DEV_MODE) {
doWithdraw(receiverAmount, callback);
} else {
double satPerByte = (double) requiredFee.value / (double) txSize;
new Popup().headLine("Confirm withdrawal request").confirmation("Sending: " + formatter.formatCoinWithCode(senderAmountAsCoinProperty.get()) + "\n" + "From address: " + withdrawFromTextField.getText() + "\n" + "To receiving address: " + withdrawToTextField.getText() + ".\n" + "Required transaction fee is: " + formatter.formatCoinWithCode(requiredFee) + " (" + MathUtils.roundDouble(satPerByte, 2) + " Satoshis/byte)\n" + "Transaction size: " + (txSize / 1000d) + " Kb\n\n" + "The recipient will receive: " + formatter.formatCoinWithCode(receiverAmount) + "\n\n" + "Are you sure you want to withdraw that amount?").actionButtonText("Yes").onAction(() -> doWithdraw(receiverAmount, callback)).closeButtonText("Cancel").show();
}
} else {
new Popup().warning("The amount you would like to send is too low as the bitcoin transaction fee will be deducted.\n" + "Please use a higher amount.").show();
}
}
} catch (Throwable e) {
e.printStackTrace();
log.error(e.toString());
new Popup().warning(e.getMessage()).show();
}
}
}
use of com.google.common.util.concurrent.FutureCallback in project cdap by caskdata.
the class ResourceCoordinator method fetchAndProcessAllResources.
/**
* Fetches all {@link ResourceRequirement} and perform assignment for the one that changed. Also, it will
* remove assignments for the resource requirements that are removed.
*/
private void fetchAndProcessAllResources(final Watcher watcher) {
Futures.addCallback(zkClient.getChildren(CoordinationConstants.REQUIREMENTS_PATH, watcher), wrapCallback(new FutureCallback<NodeChildren>() {
@Override
public void onSuccess(NodeChildren result) {
Set<String> children = ImmutableSet.copyOf(result.getChildren());
// Handle new resources
for (String child : children) {
String path = CoordinationConstants.REQUIREMENTS_PATH + "/" + child;
Watcher requirementWatcher = wrapWatcher(new ResourceRequirementWatcher(path));
fetchAndProcessRequirement(path, requirementWatcher);
}
// Handle removed resources
for (String removed : ImmutableSet.copyOf(Sets.difference(requirements.keySet(), children))) {
ResourceRequirement requirement = requirements.remove(removed);
LOG.info("Requirement deleted {}", requirement);
// Delete the assignment node.
removeAssignment(removed);
}
}
@Override
public void onFailure(Throwable t) {
// If the resource path node doesn't exists, resort to watch for exists.
if (t instanceof KeeperException.NoNodeException) {
beginWatch(watcher);
}
// Otherwise, it's a unexpected failure.
LOG.error("Failed to getChildren on ZK node {}{}", zkClient.getConnectString(), CoordinationConstants.REQUIREMENTS_PATH, t);
doNotifyFailed(t);
}
}), executor);
}
use of com.google.common.util.concurrent.FutureCallback in project cdap by caskdata.
the class ResourceCoordinatorClient method watchAssignmentOnExists.
/**
* Starts watch for assignment changes when the node exists.
*
* @param serviceName Name of the service.
*/
private void watchAssignmentOnExists(final String serviceName) {
final String zkPath = CoordinationConstants.ASSIGNMENTS_PATH + "/" + serviceName;
Watcher watcher = wrapWatcher(new AssignmentWatcher(serviceName, EnumSet.of(Watcher.Event.EventType.NodeCreated)));
Futures.addCallback(zkClient.exists(zkPath, watcher), wrapCallback(new FutureCallback<Stat>() {
@Override
public void onSuccess(Stat result) {
if (result != null) {
watchAssignment(serviceName);
}
}
@Override
public void onFailure(Throwable t) {
LOG.error("Failed to call exists on ZK {}{}", zkClient.getConnectString(), zkPath, t);
doNotifyFailed(t);
}
}), Threads.SAME_THREAD_EXECUTOR);
}
use of com.google.common.util.concurrent.FutureCallback in project cdap by caskdata.
the class DistributedStreamService method updateRequirement.
/**
* Updates stream resource requirement. It will retry if failed to do so.
*/
private void updateRequirement() {
final ResourceModifier modifier = createRequirementModifier();
Futures.addCallback(resourceCoordinatorClient.modifyRequirement(Constants.Service.STREAMS, modifier), new FutureCallback<ResourceRequirement>() {
@Override
public void onSuccess(ResourceRequirement result) {
// No-op
LOG.info("Stream resource requirement updated to {}", result);
}
@Override
public void onFailure(Throwable t) {
LOG.warn("Failed to update stream resource requirement: {}", t.getMessage());
LOG.debug("Failed to update stream resource requirement.", t);
if (isRunning()) {
final FutureCallback<ResourceRequirement> callback = this;
// Retry in 2 seconds. Shouldn't sleep in this callback thread. Should start a new thread for the retry.
Thread retryThread = new Thread("stream-resource-update") {
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(2);
LOG.info("Retrying update stream resource requirement");
Futures.addCallback(resourceCoordinatorClient.modifyRequirement(Constants.Service.STREAMS, modifier), callback);
} catch (InterruptedException e) {
LOG.warn("Stream resource retry thread interrupted", e);
}
}
};
retryThread.setDaemon(true);
retryThread.start();
}
}
});
}
Aggregations