@Test public void noPreviousDocAccessAfterSweep() throws Exception { final Set<String> findCalls = newHashSet(); DocumentStore ds = new MemoryDocumentStore() { @Override public <T extends Document> T find(Collection<T> collection, String key) { findCalls.add(key); return super.find(collection, key); } }; DocumentNodeStore ns = createTestStore(ds, 0, 0, 0); NodeBuilder builder = ns.getRoot().builder(); builder.child("foo"); builder.child("bar"); merge(ns, builder); createTestData(singletonList(ns), new Random(), 200); ns.runBackgroundUpdateOperations(); NodeDocument doc = ds.find(NODES, getIdFromPath("/foo")); assertNotNull(doc); findCalls.clear(); doc.getNodeAtRevision(ns, ns.getHeadRevision(), null); assertTrue(findCalls.size() > 0); ns.runBackgroundSweepOperation(); doc = ds.find(NODES, getIdFromPath("/foo")); assertNotNull(doc); findCalls.clear(); doc.getNodeAtRevision(ns, ns.getHeadRevision(), null); assertEquals(0, findCalls.size()); ns.dispose(); }
@Nullable 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) { return null; } Path path = getPath(); List<PropertyState> props = Lists.newArrayList(); for (String key : keySet()) { if (!Utils.isPropertyName(key)) { continue; } SortedMap<Revision, String> local = getLocalMap(key); if (local.isEmpty()) { continue; } Value value = getLatestValue(nodeStore, local.entrySet(), readRevision, validRevisions, lastRevs); if (value != null && !getPreviousRanges().isEmpty() && !isMostRecentCommitted(local, value.revision, nodeStore)) { for (Revision prev : getPreviousRanges().keySet()) { if (prev.compareRevisionTimeThenClusterId(value.revision) > 0) { value = null; break; } } } if (value == null && !getPreviousRanges().isEmpty()) { 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)); } } RevisionVector lastRevision = new RevisionVector(min); RevisionVector branchBase = null; if (branch != null) { branchBase = branch.getBase(readRevision.getBranchRevision()); } for (Revision r : lastRevs) { if (readRevision.isRevisionNewer(r)) { Revision rev = readRevision.getRevision(r.getClusterId()); if (rev != null) { lastRevision = lastRevision.update(rev); } else { lastRevision = lastRevision.remove(r.getClusterId()); } } else if (branchBase != null && branchBase.isRevisionNewer(r)) { Revision rev = branchBase.getRevision(r.getClusterId()); if (rev != null) { lastRevision = lastRevision.update(rev); } else { lastRevision = lastRevision.remove(r.getClusterId()); } } else if (lastRevision.isRevisionNewer(r)) { lastRevision = lastRevision.update(r); } } if (branch != null) { 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); }
NodeDocument extends Document { @Nullable 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) { return null; } Path path = getPath(); List<PropertyState> props = Lists.newArrayList(); for (String key : keySet()) { if (!Utils.isPropertyName(key)) { continue; } SortedMap<Revision, String> local = getLocalMap(key); if (local.isEmpty()) { continue; } Value value = getLatestValue(nodeStore, local.entrySet(), readRevision, validRevisions, lastRevs); if (value != null && !getPreviousRanges().isEmpty() && !isMostRecentCommitted(local, value.revision, nodeStore)) { for (Revision prev : getPreviousRanges().keySet()) { if (prev.compareRevisionTimeThenClusterId(value.revision) > 0) { value = null; break; } } } if (value == null && !getPreviousRanges().isEmpty()) { 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)); } } RevisionVector lastRevision = new RevisionVector(min); RevisionVector branchBase = null; if (branch != null) { branchBase = branch.getBase(readRevision.getBranchRevision()); } for (Revision r : lastRevs) { if (readRevision.isRevisionNewer(r)) { Revision rev = readRevision.getRevision(r.getClusterId()); if (rev != null) { lastRevision = lastRevision.update(rev); } else { lastRevision = lastRevision.remove(r.getClusterId()); } } else if (branchBase != null && branchBase.isRevisionNewer(r)) { Revision rev = branchBase.getRevision(r.getClusterId()); if (rev != null) { lastRevision = lastRevision.update(rev); } else { lastRevision = lastRevision.remove(r.getClusterId()); } } else if (lastRevision.isRevisionNewer(r)) { lastRevision = lastRevision.update(r); } } if (branch != null) { 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); } }
NodeDocument extends Document { @Nullable 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) { return null; } Path path = getPath(); List<PropertyState> props = Lists.newArrayList(); for (String key : keySet()) { if (!Utils.isPropertyName(key)) { continue; } SortedMap<Revision, String> local = getLocalMap(key); if (local.isEmpty()) { continue; } Value value = getLatestValue(nodeStore, local.entrySet(), readRevision, validRevisions, lastRevs); if (value != null && !getPreviousRanges().isEmpty() && !isMostRecentCommitted(local, value.revision, nodeStore)) { for (Revision prev : getPreviousRanges().keySet()) { if (prev.compareRevisionTimeThenClusterId(value.revision) > 0) { value = null; break; } } } if (value == null && !getPreviousRanges().isEmpty()) { 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)); } } RevisionVector lastRevision = new RevisionVector(min); RevisionVector branchBase = null; if (branch != null) { branchBase = branch.getBase(readRevision.getBranchRevision()); } for (Revision r : lastRevs) { if (readRevision.isRevisionNewer(r)) { Revision rev = readRevision.getRevision(r.getClusterId()); if (rev != null) { lastRevision = lastRevision.update(rev); } else { lastRevision = lastRevision.remove(r.getClusterId()); } } else if (branchBase != null && branchBase.isRevisionNewer(r)) { Revision rev = branchBase.getRevision(r.getClusterId()); if (rev != null) { lastRevision = lastRevision.update(rev); } else { lastRevision = lastRevision.remove(r.getClusterId()); } } else if (lastRevision.isRevisionNewer(r)) { lastRevision = lastRevision.update(r); } } if (branch != null) { 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); } NodeDocument(@NotNull DocumentStore store);  NodeDocument(@NotNull DocumentStore store, long creationTime); }
NodeDocument extends Document { @Nullable 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) { return null; } Path path = getPath(); List<PropertyState> props = Lists.newArrayList(); for (String key : keySet()) { if (!Utils.isPropertyName(key)) { continue; } SortedMap<Revision, String> local = getLocalMap(key); if (local.isEmpty()) { continue; } Value value = getLatestValue(nodeStore, local.entrySet(), readRevision, validRevisions, lastRevs); if (value != null && !getPreviousRanges().isEmpty() && !isMostRecentCommitted(local, value.revision, nodeStore)) { for (Revision prev : getPreviousRanges().keySet()) { if (prev.compareRevisionTimeThenClusterId(value.revision) > 0) { value = null; break; } } } if (value == null && !getPreviousRanges().isEmpty()) { 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)); } } RevisionVector lastRevision = new RevisionVector(min); RevisionVector branchBase = null; if (branch != null) { branchBase = branch.getBase(readRevision.getBranchRevision()); } for (Revision r : lastRevs) { if (readRevision.isRevisionNewer(r)) { Revision rev = readRevision.getRevision(r.getClusterId()); if (rev != null) { lastRevision = lastRevision.update(rev); } else { lastRevision = lastRevision.remove(r.getClusterId()); } } else if (branchBase != null && branchBase.isRevisionNewer(r)) { Revision rev = branchBase.getRevision(r.getClusterId()); if (rev != null) { lastRevision = lastRevision.update(rev); } else { lastRevision = lastRevision.remove(r.getClusterId()); } } else if (lastRevision.isRevisionNewer(r)) { lastRevision = lastRevision.update(r); } } if (branch != null) { 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); } NodeDocument(@NotNull DocumentStore store);  NodeDocument(@NotNull DocumentStore store, long creationTime); static long getModifiedInSecs(long timestamp); @NotNull Map<Revision, String> getValueMap(@NotNull String key); long getCreated(); @Nullable Long getModified(); boolean hasChildren(); boolean wasDeletedOnce(); boolean hasBeenModifiedSince(long lastModifiedTime); boolean hasAllRevisionLessThan(long maxRevisionTime); boolean isSplitDocument(); SplitDocType getSplitDocType(); void markUpToDate(long checkTime); long getLastCheckTime(); boolean hasBinary(); @NotNull Path getMainPath(); @NotNull Map<Integer, Revision> getLastRev(); boolean containsRevision(@NotNull Revision revision); @Nullable Path getCommitRootPath(Revision revision); @Nullable DocumentNodeState getNodeAtRevision(@NotNull DocumentNodeStore nodeStore,
                                               @NotNull RevisionVector readRevision,
                                               @Nullable Revision lastModified); @Nullable Revision getLiveRevision(RevisionContext context,
                                    RevisionVector readRevision,
                                    Map<Revision, String> validRevisions,
                                    LastRevs lastRevs); @NotNull Iterable<UpdateOp> split(@NotNull RevisionContext context,
                                    @NotNull RevisionVector head,
                                    @NotNull Function<String, Long> binarySize); @NotNull Set<Revision> getLocalBranchCommits(); static void setChildrenFlag(@NotNull UpdateOp op,
                                       boolean hasChildNode); static void setModified(@NotNull UpdateOp op,
                                   @NotNull Revision revision); static void setRevision(@NotNull UpdateOp op,
                                   @NotNull Revision revision,
                                   @NotNull String commitValue); static void unsetRevision(@NotNull UpdateOp op,
                                     @NotNull Revision revision); static boolean isRevisionsEntry(String name); static boolean isCommitRootEntry(String name); static boolean isDeletedEntry(String name); static boolean isLastRevEntry(String name); static void removeRevision(@NotNull UpdateOp op,
                                      @NotNull Revision revision); static void addCollision(@NotNull UpdateOp op,
                                    @NotNull Revision revision,
                                    @NotNull Revision other); static void removeCollision(@NotNull UpdateOp op,
                                       @NotNull Revision revision); static void setLastRev(@NotNull UpdateOp op,
                                  @NotNull Revision revision); static void setCommitRoot(@NotNull UpdateOp op,
                                     @NotNull Revision revision,
                                     int commitRootDepth); static void removeCommitRoot(@NotNull UpdateOp op,
                                        @NotNull Revision revision); static void unsetCommitRoot(@NotNull UpdateOp op,
                                       @NotNull Revision revision); static void setDeleted(@NotNull UpdateOp op,
                                  @NotNull Revision revision,
                                  boolean deleted); static void setDeletedOnce(@NotNull UpdateOp op); static void removeDeleted(@NotNull UpdateOp op,
                                     @NotNull Revision revision); static void setPrevious(@NotNull UpdateOp op,
                                   @NotNull Range range); static void removePrevious(@NotNull UpdateOp op,
                                      @NotNull Range range); static void removePrevious(@NotNull UpdateOp op,
                                      @NotNull Revision revision); static void setStalePrevious(@NotNull UpdateOp op,
                                        @NotNull Revision revision,
                                        int height); static void removeStalePrevious(@NotNull UpdateOp op,
                                           @NotNull Revision revision); static void setHasBinary(@NotNull UpdateOp op); static void setBranchCommit(@NotNull UpdateOp op,
                                       @NotNull Revision revision); static void removeBranchCommit(@NotNull UpdateOp op,
                                          @NotNull Revision revision); static void setSweepRevision(@NotNull UpdateOp op,
                                        @NotNull Revision revision); static void hasLastRev(@NotNull UpdateOp op,
                                  @NotNull Revision revision); @NotNull Path getPath(); String asString(); static NodeDocument fromString(DocumentStore store, String s); }
NodeDocument extends Document { @Nullable 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) { return null; } Path path = getPath(); List<PropertyState> props = Lists.newArrayList(); for (String key : keySet()) { if (!Utils.isPropertyName(key)) { continue; } SortedMap<Revision, String> local = getLocalMap(key); if (local.isEmpty()) { continue; } Value value = getLatestValue(nodeStore, local.entrySet(), readRevision, validRevisions, lastRevs); if (value != null && !getPreviousRanges().isEmpty() && !isMostRecentCommitted(local, value.revision, nodeStore)) { for (Revision prev : getPreviousRanges().keySet()) { if (prev.compareRevisionTimeThenClusterId(value.revision) > 0) { value = null; break; } } } if (value == null && !getPreviousRanges().isEmpty()) { 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)); } } RevisionVector lastRevision = new RevisionVector(min); RevisionVector branchBase = null; if (branch != null) { branchBase = branch.getBase(readRevision.getBranchRevision()); } for (Revision r : lastRevs) { if (readRevision.isRevisionNewer(r)) { Revision rev = readRevision.getRevision(r.getClusterId()); if (rev != null) { lastRevision = lastRevision.update(rev); } else { lastRevision = lastRevision.remove(r.getClusterId()); } } else if (branchBase != null && branchBase.isRevisionNewer(r)) { Revision rev = branchBase.getRevision(r.getClusterId()); if (rev != null) { lastRevision = lastRevision.update(rev); } else { lastRevision = lastRevision.remove(r.getClusterId()); } } else if (lastRevision.isRevisionNewer(r)) { lastRevision = lastRevision.update(r); } } if (branch != null) { 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); } NodeDocument(@NotNull DocumentStore store);  NodeDocument(@NotNull DocumentStore store, long creationTime); static long getModifiedInSecs(long timestamp); @NotNull Map<Revision, String> getValueMap(@NotNull String key); long getCreated(); @Nullable Long getModified(); boolean hasChildren(); boolean wasDeletedOnce(); boolean hasBeenModifiedSince(long lastModifiedTime); boolean hasAllRevisionLessThan(long maxRevisionTime); boolean isSplitDocument(); SplitDocType getSplitDocType(); void markUpToDate(long checkTime); long getLastCheckTime(); boolean hasBinary(); @NotNull Path getMainPath(); @NotNull Map<Integer, Revision> getLastRev(); boolean containsRevision(@NotNull Revision revision); @Nullable Path getCommitRootPath(Revision revision); @Nullable DocumentNodeState getNodeAtRevision(@NotNull DocumentNodeStore nodeStore,
                                               @NotNull RevisionVector readRevision,
                                               @Nullable Revision lastModified); @Nullable Revision getLiveRevision(RevisionContext context,
                                    RevisionVector readRevision,
                                    Map<Revision, String> validRevisions,
                                    LastRevs lastRevs); @NotNull Iterable<UpdateOp> split(@NotNull RevisionContext context,
                                    @NotNull RevisionVector head,
                                    @NotNull Function<String, Long> binarySize); @NotNull Set<Revision> getLocalBranchCommits(); static void setChildrenFlag(@NotNull UpdateOp op,
                                       boolean hasChildNode); static void setModified(@NotNull UpdateOp op,
                                   @NotNull Revision revision); static void setRevision(@NotNull UpdateOp op,
                                   @NotNull Revision revision,
                                   @NotNull String commitValue); static void unsetRevision(@NotNull UpdateOp op,
                                     @NotNull Revision revision); static boolean isRevisionsEntry(String name); static boolean isCommitRootEntry(String name); static boolean isDeletedEntry(String name); static boolean isLastRevEntry(String name); static void removeRevision(@NotNull UpdateOp op,
                                      @NotNull Revision revision); static void addCollision(@NotNull UpdateOp op,
                                    @NotNull Revision revision,
                                    @NotNull Revision other); static void removeCollision(@NotNull UpdateOp op,
                                       @NotNull Revision revision); static void setLastRev(@NotNull UpdateOp op,
                                  @NotNull Revision revision); static void setCommitRoot(@NotNull UpdateOp op,
                                     @NotNull Revision revision,
                                     int commitRootDepth); static void removeCommitRoot(@NotNull UpdateOp op,
                                        @NotNull Revision revision); static void unsetCommitRoot(@NotNull UpdateOp op,
                                       @NotNull Revision revision); static void setDeleted(@NotNull UpdateOp op,
                                  @NotNull Revision revision,
                                  boolean deleted); static void setDeletedOnce(@NotNull UpdateOp op); static void removeDeleted(@NotNull UpdateOp op,
                                     @NotNull Revision revision); static void setPrevious(@NotNull UpdateOp op,
                                   @NotNull Range range); static void removePrevious(@NotNull UpdateOp op,
                                      @NotNull Range range); static void removePrevious(@NotNull UpdateOp op,
                                      @NotNull Revision revision); static void setStalePrevious(@NotNull UpdateOp op,
                                        @NotNull Revision revision,
                                        int height); static void removeStalePrevious(@NotNull UpdateOp op,
                                           @NotNull Revision revision); static void setHasBinary(@NotNull UpdateOp op); static void setBranchCommit(@NotNull UpdateOp op,
                                       @NotNull Revision revision); static void removeBranchCommit(@NotNull UpdateOp op,
                                          @NotNull Revision revision); static void setSweepRevision(@NotNull UpdateOp op,
                                        @NotNull Revision revision); static void hasLastRev(@NotNull UpdateOp op,
                                  @NotNull Revision revision); @NotNull Path getPath(); String asString(); static NodeDocument fromString(DocumentStore store, String s); static final NodeDocument NULL; static final String MIN_ID_VALUE; static final String MAX_ID_VALUE; static final String COLLISIONS; static final String MODIFIED_IN_SECS; static final String DELETED_ONCE; static final String PATH; static final String HAS_BINARY_FLAG; static final String SD_TYPE; static final String SD_MAX_REV_TIME_IN_SECS; static final long HAS_BINARY_VAL; }