use of org.apache.cassandra.utils.concurrent.Future in project cassandra by apache.
the class RepairJob method sendValidationRequest.
/**
* Creates {@link ValidationTask} and submit them to task executor in parallel.
*
* @param endpoints Endpoint addresses to send validation request
* @return Future that can get all {@link TreeResponse} from replica, if all validation succeed.
*/
private Future<List<TreeResponse>> sendValidationRequest(Collection<InetAddressAndPort> endpoints) {
state.phase.validationSubmitted();
String message = String.format("Requesting merkle trees for %s (to %s)", desc.columnFamily, endpoints);
logger.info("{} {}", session.previewKind.logPrefix(desc.sessionId), message);
Tracing.traceRepair(message);
int nowInSec = getNowInSeconds();
List<Future<TreeResponse>> tasks = new ArrayList<>(endpoints.size());
for (InetAddressAndPort endpoint : endpoints) {
ValidationTask task = newValidationTask(endpoint, nowInSec);
tasks.add(task);
session.trackValidationCompletion(Pair.create(desc, endpoint), task);
taskExecutor.execute(task);
}
return FutureCombiner.allOf(tasks);
}
use of org.apache.cassandra.utils.concurrent.Future in project cassandra by apache.
the class RepairSession method start.
/**
* Start RepairJob on given ColumnFamilies.
*
* This first validates if all replica are available, and if they are,
* creates RepairJobs and submit to run on given executor.
*
* @param executor Executor to run validation
*/
public void start(ExecutorPlus executor) {
state.phase.start();
String message;
if (terminated)
return;
logger.info("{} parentSessionId = {}: new session: will sync {} on range {} for {}.{}", previewKind.logPrefix(getId()), state.parentRepairSession, repairedNodes(), state.commonRange, state.keyspace, Arrays.toString(state.cfnames));
Tracing.traceRepair("Syncing range {}", state.commonRange);
if (!previewKind.isPreview() && !paxosOnly) {
SystemDistributedKeyspace.startRepairs(getId(), state.parentRepairSession, state.keyspace, state.cfnames, state.commonRange);
}
if (state.commonRange.endpoints.isEmpty()) {
logger.info("{} {}", previewKind.logPrefix(getId()), message = String.format("No neighbors to repair with on range %s: session completed", state.commonRange));
state.phase.skip(message);
Tracing.traceRepair(message);
trySuccess(new RepairSessionResult(state.id, state.keyspace, state.commonRange.ranges, Lists.<RepairResult>newArrayList(), state.commonRange.hasSkippedReplicas));
if (!previewKind.isPreview()) {
SystemDistributedKeyspace.failRepairs(getId(), state.keyspace, state.cfnames, new RuntimeException(message));
}
return;
}
// Checking all nodes are live
for (InetAddressAndPort endpoint : state.commonRange.endpoints) {
if (!FailureDetector.instance.isAlive(endpoint) && !state.commonRange.hasSkippedReplicas) {
message = String.format("Cannot proceed on repair because a neighbor (%s) is dead: session failed", endpoint);
state.phase.fail(message);
logger.error("{} {}", previewKind.logPrefix(getId()), message);
Exception e = new IOException(message);
tryFailure(e);
if (!previewKind.isPreview()) {
SystemDistributedKeyspace.failRepairs(getId(), state.keyspace, state.cfnames, e);
}
return;
}
}
// Create and submit RepairJob for each ColumnFamily
state.phase.jobsSubmitted();
List<Future<RepairResult>> jobs = new ArrayList<>(state.cfnames.length);
for (String cfname : state.cfnames) {
RepairJob job = new RepairJob(this, cfname);
state.register(job.state);
executor.execute(job);
jobs.add(job);
}
// When all RepairJobs are done without error, cleanup and set the final result
FBUtilities.allOf(jobs).addCallback(new FutureCallback<List<RepairResult>>() {
public void onSuccess(List<RepairResult> results) {
state.phase.success();
// this repair session is completed
logger.info("{} {}", previewKind.logPrefix(getId()), "Session completed successfully");
Tracing.traceRepair("Completed sync of range {}", state.commonRange);
trySuccess(new RepairSessionResult(state.id, state.keyspace, state.commonRange.ranges, results, state.commonRange.hasSkippedReplicas));
taskExecutor.shutdown();
// mark this session as terminated
terminate();
awaitTaskExecutorTermination();
}
public void onFailure(Throwable t) {
state.phase.fail(t);
String msg = "{} Session completed with the following error";
if (Throwables.anyCauseMatches(t, RepairException::shouldWarn))
logger.warn(msg + ": {}", previewKind.logPrefix(getId()), t.getMessage());
else
logger.error(msg, previewKind.logPrefix(getId()), t);
Tracing.traceRepair("Session completed with the following error: {}", t);
forceShutdown(t);
}
}, executor);
}
use of org.apache.cassandra.utils.concurrent.Future in project cassandra by apache.
the class CompactionManager method submitBackground.
/**
* Call this whenever a compaction might be needed on the given columnfamily.
* It's okay to over-call (within reason) if a call is unnecessary, it will
* turn into a no-op in the bucketing/candidate-scan phase.
*/
public List<Future<?>> submitBackground(final ColumnFamilyStore cfs) {
if (cfs.isAutoCompactionDisabled()) {
logger.trace("Autocompaction is disabled");
return Collections.emptyList();
}
/**
* If a CF is currently being compacted, and there are no idle threads, submitBackground should be a no-op;
* we can wait for the current compaction to finish and re-submit when more information is available.
* Otherwise, we should submit at least one task to prevent starvation by busier CFs, and more if there
* are idle threads stil. (CASSANDRA-4310)
*/
int count = compactingCF.count(cfs);
if (count > 0 && executor.getActiveTaskCount() >= executor.getMaximumPoolSize()) {
logger.trace("Background compaction is still running for {}.{} ({} remaining). Skipping", cfs.keyspace.getName(), cfs.name, count);
return Collections.emptyList();
}
logger.trace("Scheduling a background task check for {}.{} with {}", cfs.keyspace.getName(), cfs.name, cfs.getCompactionStrategyManager().getName());
List<Future<?>> futures = new ArrayList<>(1);
Future<?> fut = executor.submitIfRunning(new BackgroundCompactionCandidate(cfs), "background task");
if (!fut.isCancelled())
futures.add(fut);
else
compactingCF.remove(cfs);
return futures;
}
use of org.apache.cassandra.utils.concurrent.Future in project cassandra by apache.
the class CompactionManager method forceUserDefinedCompaction.
public void forceUserDefinedCompaction(String dataFiles) {
String[] filenames = dataFiles.split(",");
Multimap<ColumnFamilyStore, Descriptor> descriptors = ArrayListMultimap.create();
for (String filename : filenames) {
// extract keyspace and columnfamily name from filename
Descriptor desc = Descriptor.fromFilename(filename.trim());
if (Schema.instance.getTableMetadataRef(desc) == null) {
logger.warn("Schema does not exist for file {}. Skipping.", filename);
continue;
}
// group by keyspace/columnfamily
ColumnFamilyStore cfs = Keyspace.open(desc.ksname).getColumnFamilyStore(desc.cfname);
descriptors.put(cfs, cfs.getDirectories().find(new File(filename.trim()).name()));
}
List<Future<?>> futures = new ArrayList<>(descriptors.size());
int nowInSec = FBUtilities.nowInSeconds();
for (ColumnFamilyStore cfs : descriptors.keySet()) futures.add(submitUserDefined(cfs, descriptors.get(cfs), getDefaultGcBefore(cfs, nowInSec)));
FBUtilities.waitOnFutures(futures);
}
use of org.apache.cassandra.utils.concurrent.Future in project cassandra by apache.
the class ViewBuilder method build.
private synchronized void build() {
if (isStopped) {
logger.debug("Stopped build for view({}.{}) after covering {} keys", ksName, view.name, keysBuilt);
return;
}
// Get the local ranges for which the view hasn't already been built nor it's building
RangesAtEndpoint replicatedRanges = StorageService.instance.getLocalReplicas(ksName);
Replicas.temporaryAssertFull(replicatedRanges);
Set<Range<Token>> newRanges = replicatedRanges.ranges().stream().map(r -> r.subtractAll(builtRanges)).flatMap(Set::stream).map(r -> r.subtractAll(pendingRanges.keySet())).flatMap(Set::stream).collect(Collectors.toSet());
// If there are no new nor pending ranges we should finish the build
if (newRanges.isEmpty() && pendingRanges.isEmpty()) {
finish();
return;
}
// Split the new local ranges and add them to the pending set
DatabaseDescriptor.getPartitioner().splitter().map(s -> s.split(newRanges, NUM_TASKS)).orElse(newRanges).forEach(r -> pendingRanges.put(r, Pair.<Token, Long>create(null, 0L)));
// Submit a new view build task for each building range.
// We keep record of all the submitted tasks to be able of stopping them.
List<Future<Long>> futures = pendingRanges.entrySet().stream().map(e -> new ViewBuilderTask(baseCfs, view, e.getKey(), e.getValue().left, e.getValue().right)).peek(tasks::add).map(CompactionManager.instance::submitViewBuilder).collect(toList());
// Add a callback to process any eventual new local range and mark the view as built, doing a delayed retry if
// the tasks don't succeed
Future<List<Long>> future = FutureCombiner.allOf(futures);
future.addCallback(new FutureCallback<List<Long>>() {
public void onSuccess(List<Long> result) {
keysBuilt += result.stream().mapToLong(x -> x).sum();
builtRanges.addAll(pendingRanges.keySet());
pendingRanges.clear();
build();
}
public void onFailure(Throwable t) {
if (t instanceof CompactionInterruptedException) {
internalStop(true);
keysBuilt = tasks.stream().mapToLong(ViewBuilderTask::keysBuilt).sum();
logger.info("Interrupted build for view({}.{}) after covering {} keys", ksName, view.name, keysBuilt);
} else {
ScheduledExecutors.nonPeriodicTasks.schedule(() -> loadStatusAndBuild(), 5, TimeUnit.MINUTES);
logger.warn("Materialized View failed to complete, sleeping 5 minutes before restarting", t);
}
}
});
this.future = future;
}
Aggregations