CoordinatedRepairResult.java
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cassandra.repair;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import javax.annotation.Nullable;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import org.apache.cassandra.dht.Range;
import org.apache.cassandra.dht.Token;
public class CoordinatedRepairResult
{
public final Collection<Range<Token>> successfulRanges;
public final Collection<Range<Token>> failedRanges;
public final Collection<Range<Token>> skippedRanges;
public final Optional<List<RepairSessionResult>> results;
public CoordinatedRepairResult(Collection<Range<Token>> successfulRanges,
Collection<Range<Token>> failedRanges,
Collection<Range<Token>> skippedRanges,
List<RepairSessionResult> results)
{
this.successfulRanges = successfulRanges != null ? ImmutableList.copyOf(successfulRanges) : Collections.emptyList();
this.failedRanges = failedRanges != null ? ImmutableList.copyOf(failedRanges) : Collections.emptyList();
this.skippedRanges = skippedRanges != null ? ImmutableList.copyOf(skippedRanges) : Collections.emptyList();
this.results = Optional.ofNullable(results);
}
public static CoordinatedRepairResult create(List<Collection<Range<Token>>> ranges, List<RepairSessionResult> results)
{
if (results == null || results.isEmpty())
// something went wrong; assume all sessions failed
return failed(ranges);
assert ranges.size() == results.size() : String.format("range size %d != results size %d;ranges: %s, results: %s", ranges.size(), results.size(), ranges, results);
Collection<Range<Token>> successfulRanges = new ArrayList<>();
Collection<Range<Token>> failedRanges = new ArrayList<>();
Collection<Range<Token>> skippedRanges = new ArrayList<>();
int index = 0;
for (RepairSessionResult sessionResult : results)
{
if (sessionResult != null)
{
// don't record successful repair if we had to skip ranges
Collection<Range<Token>> replicas = sessionResult.skippedReplicas ? skippedRanges : successfulRanges;
replicas.addAll(sessionResult.ranges);
}
else
{
// FutureCombiner.successfulOf doesn't keep track of the original, but maintains order, so
// can fetch the original session
failedRanges.addAll(Objects.requireNonNull(ranges.get(index)));
}
index++;
}
return new CoordinatedRepairResult(successfulRanges, failedRanges, skippedRanges, results);
}
private static CoordinatedRepairResult failed(@Nullable List<Collection<Range<Token>>> ranges)
{
Collection<Range<Token>> failedRanges = new ArrayList<>(ranges == null ? 0 : ranges.size());
if (ranges != null)
ranges.forEach(failedRanges::addAll);
return new CoordinatedRepairResult(null, failedRanges, null, null);
}
/**
* Utility method for tests to produce a success result; should only be used by tests as syntaxtic sugar as all
* results must be present else an error is thrown.
*/
@VisibleForTesting
public static CoordinatedRepairResult success(List<RepairSessionResult> results)
{
assert results != null && results.stream().allMatch(a -> a != null) : String.format("results was null or had a null (failed) result: %s", results);
List<Collection<Range<Token>>> ranges = Lists.transform(results, a -> a.ranges);
return create(ranges, results);
}
public boolean hasFailed()
{
return !failedRanges.isEmpty();
}
}