in oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocument.java [945:1051]
public DocumentNodeState getNodeAtRevision(@NotNull DocumentNodeStore nodeStore,
@NotNull RevisionVector readRevision,
@Nullable Revision lastModified) {
Map<Revision, String> validRevisions = Maps.newHashMap();
Branch branch = nodeStore.getBranches().getBranch(readRevision);
LastRevs lastRevs = createLastRevs(readRevision,
nodeStore, branch, lastModified);
Revision min = getLiveRevision(nodeStore, readRevision, validRevisions, lastRevs);
if (min == null) {
// deleted
return null;
}
Path path = getPath();
List<PropertyState> props = Lists.newArrayList();
for (String key : keySet()) {
if (!Utils.isPropertyName(key)) {
continue;
}
// ignore when local map is empty (OAK-2442)
SortedMap<Revision, String> local = getLocalMap(key);
if (local.isEmpty()) {
continue;
}
// first check local map, which contains most recent values
Value value = getLatestValue(nodeStore, local.entrySet(),
readRevision, validRevisions, lastRevs);
// check if there may be more recent values in a previous document
if (value != null
&& !getPreviousRanges().isEmpty()
&& !isMostRecentCommitted(local, value.revision, nodeStore)) {
// not reading the most recent value, we may need to
// consider previous documents as well
for (Revision prev : getPreviousRanges().keySet()) {
if (prev.compareRevisionTimeThenClusterId(value.revision) > 0) {
// a previous document has more recent changes
// than value.revision
value = null;
break;
}
}
}
if (value == null && !getPreviousRanges().isEmpty()) {
// check revision history
value = getLatestValue(nodeStore, getVisibleChanges(key, readRevision),
readRevision, validRevisions, lastRevs);
}
String propertyName = Utils.unescapePropertyName(key);
String v = value != null ? value.value : null;
if (v != null){
props.add(nodeStore.createPropertyState(propertyName, v));
}
}
// when was this node last modified?
RevisionVector lastRevision = new RevisionVector(min);
RevisionVector branchBase = null;
if (branch != null) {
branchBase = branch.getBase(readRevision.getBranchRevision());
}
for (Revision r : lastRevs) {
if (readRevision.isRevisionNewer(r)) {
// the node has a _lastRev which is newer than readRevision
// this means we don't know when this node was
// modified by an operation on a descendant node between
// current lastRevision and readRevision. therefore we have
// to stay on the safe side and use readRevision
Revision rev = readRevision.getRevision(r.getClusterId());
if (rev != null) {
lastRevision = lastRevision.update(rev);
} else {
// readRevision does not have a revision for this
// clusterId -> remove from lastRevision
lastRevision = lastRevision.remove(r.getClusterId());
}
} else if (branchBase != null && branchBase.isRevisionNewer(r)) {
// readRevision is on a branch and the node has a
// _lastRev which is newer than the base of the branch
// we cannot use this _lastRev because it is not visible
// from this branch. highest possible revision of visible
// changes is the base of the branch
Revision rev = branchBase.getRevision(r.getClusterId());
if (rev != null) {
lastRevision = lastRevision.update(rev);
} else {
// branchBase does not have a revision for this
// clusterId -> remove from lastRevision
lastRevision = lastRevision.remove(r.getClusterId());
}
} else if (lastRevision.isRevisionNewer(r)) {
lastRevision = lastRevision.update(r);
}
}
if (branch != null) {
// read from a branch
// -> possibly overlay with unsaved last revs from branch
lastRevs.updateBranch(branch.getUnsavedLastRevision(path, readRevision.getBranchRevision()));
Revision r = lastRevs.getBranchRevision();
if (r != null) {
lastRevision = lastRevision.update(r);
}
}
return new DocumentNodeState(nodeStore, path, readRevision, props, hasChildren(), lastRevision);
}