下面列出了java.util.SortedSet#isEmpty ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
private static String getFileName(String homePath, Pattern pattern) {
File home = new File(homePath);
SortedSet<String> files = Sets.newTreeSet();
if (home.exists() && home.isDirectory()) {
File[] listFiles = home.listFiles();
if (listFiles != null) {
for (File file : listFiles) {
final Matcher matcher = pattern.matcher(file.getName());
if (matcher.matches()) {
files.add(file.getAbsolutePath());
}
}
}
}
if (files.isEmpty()) {
throw new RuntimeException("cannot find " + pattern.toString() + " in " + homePath);
} else {
return files.last();
}
}
private void testSubSet(SortedSet<Integer> groundTruth, SortedSet<Integer> testSet, Random rand, int depth)
{
if(groundTruth.isEmpty() || groundTruth.last() - groundTruth.first() <= 0)//avoid bad tests
return;
int fromElement = groundTruth.first() + rand.nextInt(groundTruth.last() - groundTruth.first());
int toElement = fromElement + rand.nextInt(groundTruth.last() - fromElement);
SortedSet<Integer> g_s = groundTruth.subSet(fromElement, toElement);
SortedSet<Integer> t_s = testSet.subSet(fromElement, toElement);
assertSameContent(g_s, t_s);
for(int i = 0; i < 5; i++)
{
if(fromElement == toElement)
continue;//we can't add anything
int new_val = fromElement+rand.nextInt(toElement-fromElement);
g_s.add(new_val);
t_s.add(new_val);
}
assertSameContent(g_s, t_s);
assertSameContent(groundTruth, testSet);
if(depth-- > 0)
testSubSet(g_s, t_s, rand, depth);
assertSameContent(groundTruth, testSet);
}
public double map(float x) {
Sample t = new Sample(x, 0);
SortedSet<Sample> aset = samples.headSet(t);
SortedSet<Sample> bset = samples.tailSet(t);
if (aset.isEmpty()) {
return bset.first().y;
} else {
if (bset.isEmpty()) {
return aset.last().y;
} else {
Sample a = aset.last();
Sample b = bset.first();
return a.y + (b.y - a.y) * (x - a.x) / (b.x - a.x);
}
}
}
public void defineParameterType(ParameterType<?> parameterType) {
if (parameterType.getName() != null) {
if (parameterTypeByName.containsKey(parameterType.getName())) {
if (parameterType.getName().isEmpty()) {
throw new DuplicateTypeNameException("The anonymous parameter type has already been defined");
}
throw new DuplicateTypeNameException(String.format("There is already a parameter type with name %s", parameterType.getName()));
}
parameterTypeByName.put(parameterType.getName(), parameterType);
}
for (String parameterTypeRegexp : parameterType.getRegexps()) {
if (!parameterTypesByRegexp.containsKey(parameterTypeRegexp)) {
parameterTypesByRegexp.put(parameterTypeRegexp, new TreeSet<ParameterType<?>>());
}
SortedSet<ParameterType<?>> parameterTypes = parameterTypesByRegexp.get(parameterTypeRegexp);
if (!parameterTypes.isEmpty() && parameterTypes.first().preferForRegexpMatch() && parameterType.preferForRegexpMatch()) {
throw new CucumberExpressionException(String.format(
"There can only be one preferential parameter type per regexp. " +
"The regexp /%s/ is used for two preferential parameter types, {%s} and {%s}",
parameterTypeRegexp, parameterTypes.first().getName(), parameterType.getName()
));
}
parameterTypes.add(parameterType);
}
}
public ActionForward deleteAllContests(final ActionMapping mapping, final ActionForm actionForm,
final HttpServletRequest request, final HttpServletResponse response) {
OutboundMobilityContextBean outboundMobilityContextBean = getRenderedObject();
SortedSet<OutboundMobilityCandidacyContest> outboundMobilityCandidacyContest =
outboundMobilityContextBean.getOutboundMobilityCandidacyContest();
if (outboundMobilityCandidacyContest == null || outboundMobilityCandidacyContest.isEmpty()) {
return prepare(mapping, request, outboundMobilityContextBean);
} else {
try {
FenixFramework.atomic(() -> {
outboundMobilityCandidacyContest.forEach(OutboundMobilityCandidacyContest::delete);
});
}catch (DomainException e) {
addErrorMessage(request, "errors", e.getKey());
return prepare(mapping, request, outboundMobilityContextBean);
}
RenderUtils.invalidateViewState();
return prepare(mapping, request, new OutboundMobilityContextBean(outboundMobilityContextBean));
}
}
public boolean getServerSideEncryption() {
SortedSet<String> value = metadata.get(X_SERVER_SIDE_ENCRYPTION);
if (!value.isEmpty()) {
return equalsIgnoreCase("true", value.first());
}
return false;
}
/**
* Maintains additional invariant: if one entry is a
* prefix of another, keep only the prefix.
*
* @see java.util.Collection#add(java.lang.Object)
*/
public boolean add(String s) {
SortedSet<String> sub = headSet(s);
if (!sub.isEmpty() && s.startsWith((String)sub.last())) {
// no need to add; prefix is already present
return false;
}
boolean retVal = super.add(s);
sub = tailSet(s+"\0");
while(!sub.isEmpty() && ((String)sub.first()).startsWith(s)) {
// remove redundant entries
sub.remove(sub.first());
}
return retVal;
}
final public CurriculumLine getLastApprovement() {
final SortedSet<CurriculumLine> curriculumLines =
new TreeSet<CurriculumLine>(CurriculumLine.COMPARATOR_BY_APPROVEMENT_DATE_AND_ID);
curriculumLines.addAll(getApprovedCurriculumLines());
if (curriculumLines.isEmpty()) {
throw new DomainException("error.curriculum.group.has.no.approved.curriculum.lines", getName().getContent());
}
return curriculumLines.last();
}
private void checkIpExclusionList(final String ipExclusionList, final String cidr, final List<NicVO> nicsPresent) {
if (StringUtils.isNotBlank(ipExclusionList)) {
// validate ipExclusionList
// Perform a "syntax" check on the list
if (!NetUtils.validIpRangeList(ipExclusionList)) {
throw new InvalidParameterValueException("Syntax error in ipExclusionList");
}
final List<String> excludedIps = NetUtils.getAllIpsFromRangeList(ipExclusionList);
if (cidr != null) {
//Check that ipExclusionList (delimiters) is within the CIDR
if (!NetUtils.isIpRangeListInCidr(ipExclusionList, cidr)) {
throw new InvalidParameterValueException("An IP in the ipExclusionList is not part of the CIDR of the network " + cidr);
}
//Check that at least one IP is available after exclusion for the router interface
final SortedSet<Long> allPossibleIps = NetUtils.getAllIpsFromCidr(cidr, NetUtils.listIp2LongList(excludedIps));
if (allPossibleIps.isEmpty()) {
throw new InvalidParameterValueException("The ipExclusionList excludes all IPs in the CIDR; at least one needs to be available");
}
}
if (nicsPresent != null) {
// Check that no existing nics/ips are part of the exclusion list
for (final NicVO nic : nicsPresent) {
final String nicIp = nic.getIPv4Address();
//check if nic IP is exclusionList
if (excludedIps.contains(nicIp) && !(Nic.State.Deallocating.equals(nic.getState()))) {
throw new InvalidParameterValueException("Active IP " + nic.getIPv4Address() + " exist in ipExclusionList.");
}
}
}
}
}
/**
* Creates a new instance of {@code DefaultTickUnitSupplier} with specified multipliers.
*
* @param multipliers an array of ascending numbers, with at least one element, from 1 (inclusive) to 10
* (exclusive).
*/
public DefaultTickUnitSupplier(final SortedSet<? extends Number> multipliers) {
Objects.requireNonNull(multipliers, "The multipliers must not be null");
if (multipliers.isEmpty()) {
throw new IllegalArgumentException("The set of multipliers must not be empty");
}
DefaultTickUnitSupplier.checkRange(multipliers);
this.multipliers = multipliers.stream().mapToDouble(Number::doubleValue).toArray();
}
@Nullable
private TimeRegions getNextSetOfTimeRegions(Table stateTable, long time) throws IOException {
byte[] timeBytes = Bytes.toBytes(getInvertedTime(time));
Scan scan = new Scan(makeTimeRegionKey(timeBytes, EMPTY_BYTE_ARRAY), REGION_TIME_KEY_PREFIX_STOP);
scan.addColumn(FAMILY, REGION_TIME_COL);
long currentRegionTime = -1;
SortedSet<byte[]> regions = new TreeSet<>(Bytes.BYTES_COMPARATOR);
Result next;
try (ResultScanner scanner = stateTable.getScanner(scan)) {
while ((next = scanner.next()) != null) {
Map.Entry<Long, byte[]> timeRegion = getTimeRegion(next.getRow());
// Stop if reached next time value
if (currentRegionTime == -1) {
currentRegionTime = timeRegion.getKey();
} else if (timeRegion.getKey() < currentRegionTime) {
break;
} else if (timeRegion.getKey() > currentRegionTime) {
throw new IllegalStateException(
String.format("Got out of order time %d when expecting time less than or equal to %d",
timeRegion.getKey(), currentRegionTime));
}
regions.add(timeRegion.getValue());
}
}
return regions.isEmpty() ? null : new TimeRegions(currentRegionTime, Collections.unmodifiableSortedSet(regions));
}
private static Layer2Vni toL2Vni(
@Nonnull AristaEosVxlan vxlan, int vni, int vlan, @Nullable Interface sourceInterface) {
Ip sourceAddress =
sourceInterface == null
? null
: sourceInterface.getAddress() == null ? null : sourceInterface.getAddress().getIp();
// Prefer VLAN-specific or general flood address (in that order) over multicast address
SortedSet<Ip> bumTransportIps =
firstNonNull(vxlan.getVlanFloodAddresses().get(vlan), vxlan.getFloodAddresses());
// default to unicast flooding unless specified otherwise
BumTransportMethod bumTransportMethod = BumTransportMethod.UNICAST_FLOOD_GROUP;
// Check if multicast is enabled
Ip multicastAddress = vxlan.getMulticastGroup();
if (bumTransportIps.isEmpty() && multicastAddress != null) {
bumTransportMethod = BumTransportMethod.MULTICAST_GROUP;
bumTransportIps = ImmutableSortedSet.of(multicastAddress);
}
return Layer2Vni.builder()
.setBumTransportIps(bumTransportIps)
.setBumTransportMethod(bumTransportMethod)
.setSourceAddress(sourceAddress)
.setUdpPort(firstNonNull(vxlan.getUdpPort(), AristaEosVxlan.DEFAULT_UDP_PORT))
.setVlan(vlan)
.setVni(vni)
.setSrcVrf(Configuration.DEFAULT_VRF_NAME)
.build();
}
/**
* Attempt to swap the given source replica with a replica from the candidate replicas to swap with. The function
* returns the swapped in replica if succeeded, null otherwise.
* All the replicas in the given candidateReplicasToSwapWith must be from the same broker.
*
* @param clusterModel The state of the cluster.
* @param sourceReplica Replica to be swapped with.
* @param candidateReplicas Candidate replicas (from the same candidate broker) to swap with the source replica in the
* order of attempts to swap.
* @param optimizedGoals Optimized goals.
* @param optimizationOptions Options to take into account during optimization -- e.g. excluded brokers for leadership.
* @return The swapped in replica if succeeded, null otherwise.
*/
Replica maybeApplySwapAction(ClusterModel clusterModel,
Replica sourceReplica,
SortedSet<Replica> candidateReplicas,
Set<Goal> optimizedGoals,
OptimizationOptions optimizationOptions) {
SortedSet<Replica> eligibleReplicas = eligibleReplicasForSwap(clusterModel, sourceReplica, candidateReplicas, optimizationOptions);
if (eligibleReplicas.isEmpty()) {
return null;
}
Broker destinationBroker = eligibleReplicas.first().broker();
for (Replica destinationReplica : eligibleReplicas) {
BalancingAction swapProposal = new BalancingAction(sourceReplica.topicPartition(),
sourceReplica.broker().id(), destinationBroker.id(),
ActionType.INTER_BROKER_REPLICA_SWAP, destinationReplica.topicPartition());
// A sourceReplica should be swapped with a replicaToSwapWith if:
// 0. The swap from source to destination is legit.
// 1. The swap from destination to source is legit.
// 2. The goal requirements are not violated if this action is applied to the given cluster state.
// 3. The movement is acceptable by the previously optimized goals.
if (!legitMove(sourceReplica, destinationBroker, clusterModel, ActionType.INTER_BROKER_REPLICA_MOVEMENT)) {
LOG.trace("Swap from source to destination broker is not legit for {}.", swapProposal);
return null;
}
if (!legitMove(destinationReplica, sourceReplica.broker(), clusterModel, ActionType.INTER_BROKER_REPLICA_MOVEMENT)) {
LOG.trace("Swap from destination to source broker is not legit for {}.", swapProposal);
continue;
}
// The current goal is expected to know whether a swap is doable between given brokers.
if (!selfSatisfied(clusterModel, swapProposal)) {
// Unable to satisfy proposal for this eligible replica and the remaining eligible replicas in the list.
LOG.trace("Unable to self-satisfy swap proposal {}.", swapProposal);
return null;
}
ActionAcceptance acceptance = AnalyzerUtils.isProposalAcceptableForOptimizedGoals(optimizedGoals, swapProposal, clusterModel);
LOG.trace("Trying to apply legit and self-satisfied swap {}, actionAcceptance = {}.", swapProposal, acceptance);
if (acceptance == ACCEPT) {
Broker sourceBroker = sourceReplica.broker();
clusterModel.relocateReplica(sourceReplica.topicPartition(), sourceBroker.id(), destinationBroker.id());
clusterModel.relocateReplica(destinationReplica.topicPartition(), destinationBroker.id(), sourceBroker.id());
return destinationReplica;
} else if (acceptance == BROKER_REJECT) {
// Unable to swap the given source replica with any replicas in the destination broker.
return null;
}
}
return null;
}
private boolean rebalanceBySwappingLoadOut(Broker broker,
ClusterModel clusterModel,
Set<Goal> optimizedGoals,
OptimizationOptions optimizationOptions,
boolean moveImmigrantsOnly) {
long swapStartTimeMs = System.currentTimeMillis();
if (!broker.isAlive() || optimizationOptions.excludedBrokersForReplicaMove().contains(broker.id())) {
// If the source broker is (1) dead, or (2) excluded for replica move, then swap operation is not possible.
return true;
}
Set<String> excludedTopics = optimizationOptions.excludedTopics();
// Get the replicas to swap.
String sourceReplicaSortName = sortedCandidateReplicas(broker,
excludedTopics,
0.0,
false,
false,
resource() == Resource.NW_OUT,
moveImmigrantsOnly);
SortedSet<Replica> sourceReplicas = broker.trackedSortedReplicas(sourceReplicaSortName).sortedReplicas(false);
if (sourceReplicas.isEmpty()) {
// Source broker has no filtered replica to swap.
broker.untrackSortedReplicas(sourceReplicaSortName);
return true;
}
// If this broker is excluded for leadership, then it can swapped with only followers.
double maxSourceReplicaLoad = getMaxReplicaLoad(sourceReplicas);
boolean swapWithFollowersOnly = optimizationOptions.excludedBrokersForLeadership().contains(broker.id());
PriorityQueue<Broker> candidateBrokerPQ = new PriorityQueue<>(_brokerComparator);
String candidateReplicaSortName = null;
for (Broker candidate : clusterModel.aliveBrokersUnderThreshold(resource(), _balanceUpperThreshold)
.stream().filter(b -> !b.replicas().isEmpty()).collect(Collectors.toSet())) {
// Get candidate replicas on candidate broker to try swapping with -- sorted in the order of trial (ascending load).
candidateReplicaSortName = sortedCandidateReplicas(candidate,
excludedTopics,
maxSourceReplicaLoad,
true,
swapWithFollowersOnly,
false,
moveImmigrantsOnly);
candidateBrokerPQ.add(candidate);
}
while (!candidateBrokerPQ.isEmpty()) {
if (remainingPerBrokerSwapTimeMs(swapStartTimeMs) <= 0) {
LOG.debug("Swap load out timeout for broker {}.", broker.id());
break;
}
Broker cb = candidateBrokerPQ.poll();
Replica swappedInReplica = null;
for (Replica sourceReplica : sourceReplicas) {
// Try swapping the source with the candidate replicas. Get the swapped in replica if successful, null otherwise.
Replica swappedIn = maybeApplySwapAction(clusterModel,
sourceReplica,
cb.trackedSortedReplicas(candidateReplicaSortName).sortedReplicas(false),
optimizedGoals,
optimizationOptions);
if (swappedIn != null) {
if (isLoadUnderBalanceUpperLimit(broker)) {
// Successfully balanced this broker by swapping in.
clusterModel.clearSortedReplicas();
return false;
}
// Add swapped in/out replica for updating the list of replicas in source broker.
swappedInReplica = swappedIn;
break;
} else if (remainingPerBrokerSwapTimeMs(swapStartTimeMs) <= 0) {
LOG.debug("Swap load out timeout for source replica {}.", sourceReplica);
clusterModel.clearSortedReplicas();
return true;
}
}
if (swappedInReplica != null) {
sourceReplicas = broker.trackedSortedReplicas(sourceReplicaSortName).sortedReplicas(false);
// The broker is still considered as an eligible candidate replica, because the swap was successful -- i.e. there
// might be other potential candidate replicas on it to swap with.
candidateBrokerPQ.add(cb);
}
}
clusterModel.clearSortedReplicas();
return true;
}
/**
* the command that is run and retried for actually
* obtaining the lock
*
* @return if the command was successful or not
*/
public boolean execute() throws KeeperException, InterruptedException {
do {
if (id == null) {
long sessionId = zookeeper.getSessionId();
String prefix = "x-" + sessionId + "-";
// lets try look up the current ID if we failed
// in the middle of creating the znode
findPrefixInChildren(prefix, zookeeper, dir);
idName = new ZNodeName(id);
}
if (id != null) {
List<String> names = zookeeper.getChildren(dir, false);
if (names.isEmpty()) {
LOG.warn("No children in: " + dir + " when we've just " +
"created one! Lets recreate it...");
// lets force the recreation of the id
id = null;
} else {
// lets sort them explicitly (though they do seem to come back in order ususally :)
SortedSet<ZNodeName> sortedNames = new TreeSet<ZNodeName>();
for (String name : names) {
sortedNames.add(new ZNodeName(dir + "/" + name));
}
ownerId = sortedNames.first().getName();
SortedSet<ZNodeName> lessThanMe = sortedNames.headSet(idName);
if (!lessThanMe.isEmpty()) {
ZNodeName lastChildName = lessThanMe.last();
lastChildId = lastChildName.getName();
if (LOG.isDebugEnabled()) {
LOG.debug("watching less than me node: " + lastChildId);
}
Stat stat = zookeeper.exists(lastChildId, new LockWatcher());
if (stat != null) {
return Boolean.FALSE;
} else {
LOG.warn("Could not find the" +
" stats for less than me: " + lastChildName.getName());
}
} else {
if (isOwner()) {
if (callback != null) {
callback.lockAcquired();
}
return Boolean.TRUE;
}
}
}
}
} while (id == null);
return Boolean.FALSE;
}
final public CycleType getLastConcludedCycleType() {
final SortedSet<CycleType> concludedCycles = new TreeSet<CycleType>(getConcludedCycles());
return concludedCycles.isEmpty() ? null : concludedCycles.last();
}
/**
* Try to find the latest set of regions in which all regions have been major compacted, and
* compute prune upper bound from them. Starting from newest to oldest, this looks into the
* region set that has been saved periodically, and joins it with the prune upper bound data
* for a region recorded after a major compaction.
*
* @param timeRegions the latest set of regions
* @return prune upper bound
* @throws IOException when not able to talk to HBase
*/
private long computePruneUpperBound(TimeRegions timeRegions) throws IOException {
// Get the tables for the current time from the latest regions set
final Set<TableName> existingTables = getTableNamesForRegions(timeRegions.getRegions());
LOG.debug("Tables for time {} = {}", timeRegions.getTime(), existingTables);
do {
LOG.debug("Computing prune upper bound for {}", timeRegions);
SortedSet<byte[]> transactionalRegions = timeRegions.getRegions();
long time = timeRegions.getTime();
long inactiveTransactionBound = dataJanitorState.getInactiveTransactionBoundForTime(time);
LOG.debug("Got inactive transaction bound {}", inactiveTransactionBound);
// If inactiveTransactionBound is not recorded then that means the data is not complete for these regions
if (inactiveTransactionBound == -1) {
if (LOG.isDebugEnabled()) {
LOG.debug("Ignoring regions for time {} as no inactiveTransactionBound was found for that time, " +
"and hence the data must be incomplete", time);
}
continue;
}
// Remove non-existing tables from the transactional regions set, so that we don't lookup prune upper bounds
// for them. Since the deleted tables do not exist anymore, there is no need to make sure they have been
// compacted. This ensures that transient tables do not block pruning progress.
transactionalRegions = filterDeletedTableRegions(existingTables, transactionalRegions);
if (LOG.isDebugEnabled()) {
LOG.debug("Transactional regions after removing the regions of non-existing tables = {}",
Iterables.transform(transactionalRegions, TimeRegions.BYTE_ARR_TO_STRING_FN));
}
// Get the prune upper bounds for all the transactional regions
Map<byte[], Long> pruneUpperBoundRegions =
dataJanitorState.getPruneUpperBoundForRegions(transactionalRegions);
logPruneUpperBoundRegions(pruneUpperBoundRegions);
// Use inactiveTransactionBound as the prune upper bound for the empty regions since the regions that are
// recorded as empty after inactiveTransactionBoundTime will not have invalid data
// for transactions started on or before inactiveTransactionBoundTime
pruneUpperBoundRegions = handleEmptyRegions(inactiveTransactionBound, transactionalRegions,
pruneUpperBoundRegions);
// If prune upper bounds are found for all the transactional regions, then compute the prune upper bound
// across all regions
if (!transactionalRegions.isEmpty() &&
pruneUpperBoundRegions.size() == transactionalRegions.size()) {
Long minPruneUpperBoundRegions = Collections.min(pruneUpperBoundRegions.values());
long pruneUpperBound = Math.min(inactiveTransactionBound, minPruneUpperBoundRegions);
LOG.debug("Found prune upper bound {} for time {}", pruneUpperBound, time);
return pruneUpperBound;
} else {
if (LOG.isDebugEnabled()) {
Sets.SetView<byte[]> difference =
Sets.difference(transactionalRegions, pruneUpperBoundRegions.keySet());
LOG.debug("Ignoring regions for time {} because the following regions did not record a pruneUpperBound: {}",
time, Iterables.transform(difference, TimeRegions.BYTE_ARR_TO_STRING_FN));
}
}
timeRegions = dataJanitorState.getRegionsOnOrBeforeTime(time - 1);
} while (timeRegions != null);
return -1;
}
@Override
public String[] unparse(LoadContext context, PCTemplate pct)
{
Changes<CDOMReference<? extends PCClass>> changes =
context.getObjectContext().getListChanges(pct, ListKey.FAVORED_CLASS);
Changes<ChooseSelectionActor<?>> listChanges =
context.getObjectContext().getListChanges(pct, ListKey.NEW_CHOOSE_ACTOR);
Boolean anyfavored = context.getObjectContext().getObject(pct, ObjectKey.ANY_FAVORED_CLASS);
SortedSet<String> set = new TreeSet<>();
if (anyfavored != null && anyfavored)
{
set.add(Constants.HIGHEST_LEVEL_CLASS);
}
if (changes != null && !changes.isEmpty() && changes.hasAddedItems())
{
for (CDOMReference<? extends PCClass> ref : changes.getAdded())
{
String prefix = ref.getPersistentFormat();
if (prefix.startsWith("SUBCLASS="))
{
set.add(prefix.substring(9) + Constants.DOT + ref.getLSTformat(false));
}
else
{
set.add(ref.getLSTformat(false));
}
}
}
Collection<ChooseSelectionActor<?>> listAdded = listChanges.getAdded();
if (listAdded != null && !listAdded.isEmpty())
{
for (ChooseSelectionActor<?> cra : listAdded)
{
if (cra.getSource().equals(getTokenName()))
{
try
{
set.add(cra.getLstFormat());
}
catch (PersistenceLayerException e)
{
context.addWriteMessage("Error writing Prerequisite: " + e);
return null;
}
}
}
}
if (set.isEmpty())
{
// Zero indicates no add or clear
return null;
}
return new String[]{StringUtil.join(set, Constants.PIPE)};
}
/**
*
* @param paths a sorted set of Paths to use for the partitions/journals and
* the snapshot. The snapshot will always be written to the first path
* specified.
* @param partitionCount the number of partitions/journals to use. For best
* performance, this should be close to the number of threads that are
* expected to update the repository simultaneously
* @param serdeFactory the factory for the serializer/deserializer for records
* @param syncListener the listener
* @throws IOException if unable to initialize due to IO issue
*/
@SuppressWarnings("unchecked")
public MinimalLockingWriteAheadLog(final SortedSet<Path> paths, final int partitionCount, final SerDeFactory<T> serdeFactory, final SyncListener syncListener) throws IOException {
this.syncListener = syncListener;
requireNonNull(paths);
requireNonNull(serdeFactory);
if (paths.isEmpty()) {
throw new IllegalArgumentException("Paths must be non-empty");
}
int resolvedPartitionCount = partitionCount;
int existingPartitions = 0;
for (final Path path : paths) {
if (!Files.exists(path)) {
Files.createDirectories(path);
}
final File file = path.toFile();
if (!file.isDirectory()) {
throw new IOException("Path given [" + path + "] is not a directory");
}
if (!file.canWrite()) {
throw new IOException("Path given [" + path + "] is not writable");
}
if (!file.canRead()) {
throw new IOException("Path given [" + path + "] is not readable");
}
if (!file.canExecute()) {
throw new IOException("Path given [" + path + "] is not executable");
}
final File[] children = file.listFiles();
if (children != null) {
for (final File child : children) {
if (child.isDirectory() && child.getName().startsWith("partition-")) {
existingPartitions++;
}
}
if (existingPartitions != 0 && existingPartitions != partitionCount) {
logger.warn("Constructing MinimalLockingWriteAheadLog with partitionCount={}, but the repository currently has "
+ "{} partitions; ignoring argument and proceeding with {} partitions",
new Object[]{partitionCount, existingPartitions, existingPartitions});
resolvedPartitionCount = existingPartitions;
}
}
}
this.basePath = paths.iterator().next();
this.partialPath = basePath.resolve("snapshot.partial");
this.snapshotPath = basePath.resolve("snapshot");
this.serdeFactory = serdeFactory;
final Path lockPath = basePath.resolve("wali.lock");
lockChannel = new FileOutputStream(lockPath.toFile()).getChannel();
lockChannel.lock();
partitions = new Partition[resolvedPartitionCount];
Iterator<Path> pathIterator = paths.iterator();
for (int i = 0; i < resolvedPartitionCount; i++) {
// If we're out of paths, create a new iterator to start over.
if (!pathIterator.hasNext()) {
pathIterator = paths.iterator();
}
final Path partitionBasePath = pathIterator.next();
partitions[i] = new Partition<>(partitionBasePath.resolve("partition-" + i), serdeFactory, i, getVersion());
}
}
public PhysicalAddress getLastPersonalAddress() {
SortedSet<PhysicalAddress> addressSet = new TreeSet<PhysicalAddress>(DomainObjectUtil.COMPARATOR_BY_ID);
addressSet.addAll(getStudent().getPerson().getPhysicalAddresses());
return !addressSet.isEmpty() && addressSet.last() != null ? addressSet.last() : null;
}