Example usage for com.google.common.collect Iterables mergeSorted

List of usage examples for com.google.common.collect Iterables mergeSorted

Introduction

In this page you can find the example usage for com.google.common.collect Iterables mergeSorted.

Prototype

@Beta
public static <T> Iterable<T> mergeSorted(final Iterable<? extends Iterable<? extends T>> iterables,
        final Comparator<? super T> comparator) 

Source Link

Document

Returns an iterable over the merged contents of all given iterables .

Usage

From source file:org.apache.jackrabbit.oak.plugins.document.NodeDocument.java

/**
 * Get the revision of the latest change made to this node. At the same
 * time this method collects all collisions that happened for the given
 * {@code changeRev}. The reported latest change takes branches into
 * account. This means, if {@code changeRev} is on a branch, the latest
 * change is either a change that was done by a preceding branch commit or
 * a change that happened before the base of the branch. Changes done after
 * the branch base on trunk are not considered in this case. For a trunk
 * commit the latest change is reported similarly. In this case, unmerged
 * branch commits are not considered as latest change. Only commits to trunk
 * are considered.//  ww  w.  j  ava 2  s.  c o m
 *
 * Collisions include the following cases:
 * <ul>
 *     <li>The other change is not yet committed</li>
 *     <li>The other change is a branch commit and not yet merged</li>
 *     <li>The {@code changeRev} is a branch commit and the other change
 *       happened after the base revision of the branch</li>
 *     <li>The other change is from another cluster node and not yet
 *       visible</li>
 * </ul>
 *
 * @param context the revision context.
 * @param baseRev the base revision of the current change.
 * @param changeRev the revision of the current change.
 * @param branch the branch associated with the current change or
 *              {@code null} if {@code changeRev} is not a branch commit.
 * @param collisions changes that happened after {@code baseRev}.
 */
@CheckForNull
Revision getNewestRevision(final RevisionContext context, final RevisionVector baseRev,
        final Revision changeRev, final Branch branch, final Set<Revision> collisions) {
    checkArgument(!baseRev.isBranch() || branch != null,
            "Branch must be non-null if baseRev is a branch revision");
    RevisionVector head = context.getHeadRevision();
    RevisionVector lower = branch != null ? branch.getBase() : baseRev;
    // the clusterIds to check when walking the changes
    Set<Integer> clusterIds = Collections.emptySet();
    if (!getPreviousRanges().isEmpty()) {
        clusterIds = Sets.newHashSet();
        for (Revision prevRev : getPreviousRanges().keySet()) {
            if (lower.isRevisionNewer(prevRev) || equal(prevRev, lower.getRevision(prevRev.getClusterId()))) {
                clusterIds.add(prevRev.getClusterId());
            }
        }
        if (!clusterIds.isEmpty()) {
            // add clusterIds of local changes as well
            for (Revision r : getLocalCommitRoot().keySet()) {
                clusterIds.add(r.getClusterId());
            }
            for (Revision r : getLocalRevisions().keySet()) {
                clusterIds.add(r.getClusterId());
            }
        }
    }
    // if we don't have clusterIds, we can use the local changes only
    boolean fullScan = true;
    Iterable<Revision> changes = Iterables.mergeSorted(
            ImmutableList.of(getLocalRevisions().keySet(), getLocalCommitRoot().keySet()),
            getLocalRevisions().comparator());
    if (!clusterIds.isEmpty()) {
        // there are some previous documents that potentially
        // contain changes after 'lower' revision vector
        // include previous documents as well (only needed in rare cases)
        fullScan = false;
        changes = Iterables.mergeSorted(
                ImmutableList.of(changes, getChanges(REVISIONS, lower), getChanges(COMMIT_ROOT, lower)),
                getLocalRevisions().comparator());
        if (LOG.isDebugEnabled()) {
            LOG.debug("getNewestRevision() with changeRev {} on {}, " + "_revisions {}, _commitRoot {}",
                    changeRev, getId(), getLocalRevisions(), getLocalCommitRoot());
        }
    }
    Map<Integer, Revision> newestRevs = Maps.newHashMap();
    Map<Revision, String> validRevisions = Maps.newHashMap();
    for (Revision r : changes) {
        if (r.equals(changeRev)) {
            continue;
        }
        if (!fullScan) {
            // check if we can stop going through changes
            if (clusterIds.contains(r.getClusterId()) && !lower.isRevisionNewer(r)
                    && newestRevs.containsKey(r.getClusterId())) {
                clusterIds.remove(r.getClusterId());
                if (clusterIds.isEmpty()) {
                    // all remaining revisions are older than
                    // the lower bound
                    break;
                }
            }
        }
        if (newestRevs.containsKey(r.getClusterId())) {
            // we already found the newest revision for this clusterId
            // from a baseRev point of view
            // we still need to find collisions up to the base
            // of the branch if this is for a commit on a branch
            if (branch != null && !branch.containsCommit(r)) {
                // change does not belong to the branch
                if (branch.getBase(changeRev).isRevisionNewer(r)) {
                    // and happened after the base of the branch
                    collisions.add(r);
                }
            }
        } else {
            // we don't yet have the newest committed change
            // for this clusterId
            // check if change is visible from baseRev
            if (isValidRevision(context, r, null, baseRev, validRevisions)) {
                // consider for newestRev
                newestRevs.put(r.getClusterId(), r);
            } else {
                // not valid means:
                // 1) 'r' is not committed -> collision
                // 2) 'r' is on a branch, but not the same as
                //    changeRev -> collisions
                // 3) changeRev is on a branch and 'r' is newer than
                //    the base of the branch -> collision
                // 4) 'r' is committed but not yet visible to current
                //    cluster node -> collisions
                // 5) changeRev is not on a branch, 'r' is committed and
                //    newer than baseRev -> newestRev

                NodeDocument commitRoot = getCommitRoot(r);
                Revision commitRevision = null;
                if (commitRoot != null) {
                    commitRevision = commitRoot.getCommitRevision(r);
                }
                if (commitRevision != null // committed but not yet visible
                        && head.isRevisionNewer(commitRevision)) {
                    // case 4)
                    collisions.add(r);
                } else if (commitRevision != null // committed
                        && branch == null // changeRev not on branch
                        && baseRev.isRevisionNewer(r)) {
                    // case 5)
                    newestRevs.put(r.getClusterId(), r);
                } else {
                    // remaining cases 1), 2) and 3)
                    collisions.add(r);
                }
            }
        }

    }
    // select the newest committed change
    Revision newestRev = null;
    for (Revision r : newestRevs.values()) {
        newestRev = Utils.max(newestRev, r, StableRevisionComparator.INSTANCE);
    }

    if (newestRev == null) {
        return null;
    }

    // the local deleted map contains the most recent revisions
    SortedMap<Revision, String> deleted = getLocalDeleted();
    String value = deleted.get(newestRev);
    if (value == null && deleted.headMap(newestRev).isEmpty()) {
        // newestRev is newer than most recent entry in local deleted
        // no need to check previous docs
        return newestRev;
    }

    if (value == null) {
        // get from complete map
        value = getDeleted().get(newestRev);
    }
    if ("true".equals(value)) {
        // deleted in the newest revision
        return null;
    }
    return newestRev;
}

From source file:org.apache.jackrabbit.oak.plugins.document.NodeDocument.java

/**
 * Returns an {@link Iterable} of {@link Revision} of all changes performed
 * on this document. This covers all entries for {@link #REVISIONS} and
 * {@link #COMMIT_ROOT} including previous documents. The revisions are
 * returned in descending stable revision order using
 * {@link StableRevisionComparator#REVERSE}.
 *
 * @return revisions of all changes performed on this document.
 *//*  w  ww .java2s  . c  om*/
Iterable<Revision> getAllChanges() {
    RevisionVector empty = new RevisionVector();
    return Iterables.mergeSorted(ImmutableList.of(getChanges(REVISIONS, empty), getChanges(COMMIT_ROOT, empty)),
            StableRevisionComparator.REVERSE);
}

From source file:org.apache.jackrabbit.oak.plugins.document.NodeDocument.java

/**
 * Returns all changes for the given property back to {@code min} revision
 * (exclusive). The revisions include committed as well as uncommitted
 * changes. The returned revisions are sorted in reverse order (newest
 * first).//www  .ja  v a  2 s .  co  m
 *
 * @param property the name of the property.
 * @param min the lower bound revision (exclusive).
 * @return changes back to {@code min} revision.
 */
@Nonnull
Iterable<Revision> getChanges(@Nonnull final String property, @Nonnull final RevisionVector min) {
    Predicate<Revision> p = new Predicate<Revision>() {
        @Override
        public boolean apply(Revision input) {
            return min.isRevisionNewer(input);
        }
    };
    List<Iterable<Revision>> changes = Lists.newArrayList();
    changes.add(abortingIterable(getLocalMap(property).keySet(), p));
    for (Map.Entry<Revision, Range> e : getPreviousRanges().entrySet()) {
        if (min.isRevisionNewer(e.getKey())) {
            final NodeDocument prev = getPreviousDoc(e.getKey(), e.getValue());
            if (prev != null) {
                changes.add(abortingIterable(prev.getValueMap(property).keySet(), p));
            }
        }
    }
    if (changes.size() == 1) {
        return changes.get(0);
    } else {
        return Iterables.mergeSorted(changes, StableRevisionComparator.REVERSE);
    }
}