use of org.apache.jackrabbit.oak.spi.state.DefaultNodeStateDiff in project jackrabbit-oak by apache.
the class DocumentNodeStoreTest method diffMany.
// OAK-1970
@Test
public void diffMany() throws Exception {
// make sure diffMany is used and not the new
// journal diff introduced with OAK-4528
System.setProperty("oak.disableJournalDiff", "true");
Clock clock = new Clock.Virtual();
clock.waitUntil(System.currentTimeMillis());
Revision.setClock(clock);
final List<Long> startValues = Lists.newArrayList();
MemoryDocumentStore ds = new MemoryDocumentStore() {
@Nonnull
@Override
public <T extends Document> List<T> query(Collection<T> collection, String fromKey, String toKey, String indexedProperty, long startValue, int limit) {
if (indexedProperty != null) {
startValues.add(startValue);
}
return super.query(collection, fromKey, toKey, indexedProperty, startValue, limit);
}
};
DocumentNodeStore ns = builderProvider.newBuilder().clock(clock).setDocumentStore(ds).setAsyncDelay(0).getNodeStore();
NodeBuilder builder = ns.getRoot().builder();
NodeBuilder test = builder.child("test");
for (int i = 0; i < DocumentMK.MANY_CHILDREN_THRESHOLD * 2; i++) {
test.child("node-" + i);
}
merge(ns, builder);
// 'wait one hour'
clock.waitUntil(clock.getTime() + TimeUnit.HOURS.toMillis(1));
// perform a change and use the resulting root as before state
builder = ns.getRoot().builder();
builder.child("foo");
DocumentNodeState before = asDocumentNodeState(merge(ns, builder));
NodeState beforeTest = before.getChildNode("test");
// perform another change to span the diff across multiple revisions
// this will prevent diff calls served from the local cache
builder = ns.getRoot().builder();
builder.child("bar");
merge(ns, builder);
// add a child node
builder = ns.getRoot().builder();
builder.child("test").child("bar");
NodeState after = merge(ns, builder);
NodeState afterTest = after.getChildNode("test");
startValues.clear();
// make sure diff is not served from node children cache entries
ns.invalidateNodeChildrenCache();
afterTest.compareAgainstBaseState(beforeTest, new DefaultNodeStateDiff());
assertEquals(1, startValues.size());
Revision localHead = before.getRootRevision().getRevision(ns.getClusterId());
assertNotNull(localHead);
long beforeModified = getModifiedInSecs(localHead.getTimestamp());
// startValue must be based on the revision of the before state
// and not when '/test' was last modified
assertEquals(beforeModified, (long) startValues.get(0));
System.clearProperty("oak.disableJournalDiff");
}
use of org.apache.jackrabbit.oak.spi.state.DefaultNodeStateDiff in project jackrabbit-oak by apache.
the class DocumentNodeStoreTest method longRunningTx.
// OAK-5602
@Test
public void longRunningTx() throws Exception {
Clock clock = new Clock.Virtual();
clock.waitUntil(System.currentTimeMillis());
Revision.setClock(clock);
MemoryDocumentStore docStore = new MemoryDocumentStore();
DocumentNodeStore ns = builderProvider.newBuilder().setDocumentStore(docStore).setUpdateLimit(100).setJournalGCMaxAge(TimeUnit.HOURS.toMillis(6)).setBundlingDisabled(true).setAsyncDelay(0).clock(clock).getNodeStore();
NodeBuilder builder = ns.getRoot().builder();
builder.child("test");
merge(ns, builder);
builder = ns.getRoot().builder();
NodeBuilder test = builder.child("test");
String firstChildId = Utils.getIdFromPath("/test/child-0");
for (int i = 0; ; i++) {
NodeBuilder child = test.child("child-" + i);
for (int j = 0; j < 10; j++) {
child.setProperty("p-" + j, "value");
}
if (docStore.find(NODES, firstChildId) != null) {
// branch was created
break;
}
}
// simulate a long running commit taking 2 hours
clock.waitUntil(clock.getTime() + TimeUnit.HOURS.toMillis(2));
// some other commit that moves the head revision forward
NodeBuilder builder2 = ns.getRoot().builder();
builder2.child("foo");
merge(ns, builder2);
NodeState before = ns.getRoot().getChildNode("test");
// merge the long running tx
merge(ns, builder);
// five hours later the branch commit can be collected by the journal GC
clock.waitUntil(clock.getTime() + TimeUnit.HOURS.toMillis(5));
// journal gc cleans up entries older than 6 hours
ns.getJournalGarbageCollector().gc();
// now the node state diff mechanism must not use the journal
// because the required journal entry with the branch commit
// is incomplete. the journal entry for the merge commit is still
// present, but the referenced branch commit has been GCed.
NodeState after = ns.getRoot().getChildNode("test");
after.compareAgainstBaseState(before, new DefaultNodeStateDiff());
}
use of org.apache.jackrabbit.oak.spi.state.DefaultNodeStateDiff in project jackrabbit-oak by apache.
the class DocumentNodeStoreTest method diffWithBrokenJournal.
// OAK-6495
@Test
public void diffWithBrokenJournal() throws Exception {
Clock clock = new Clock.Virtual();
clock.waitUntil(System.currentTimeMillis());
Revision.setClock(clock);
MemoryDocumentStore docStore = new MemoryDocumentStore();
DocumentNodeStore ns = builderProvider.newBuilder().setDocumentStore(docStore).setUpdateLimit(100).setJournalGCMaxAge(TimeUnit.HOURS.toMillis(6)).setBundlingDisabled(true).setAsyncDelay(0).clock(clock).getNodeStore();
NodeBuilder builder = ns.getRoot().builder();
builder.child("test");
merge(ns, builder);
NodeState before = ns.getRoot().getChildNode("test");
builder = ns.getRoot().builder();
NodeBuilder test = builder.child("test");
String firstChildId = Utils.getIdFromPath("/test/child-0");
for (int i = 0; ; i++) {
NodeBuilder child = test.child("child-" + i);
for (int j = 0; j < 10; j++) {
child.setProperty("p-" + j, "value");
}
if (docStore.find(NODES, firstChildId) != null) {
// branch was created
break;
}
}
merge(ns, builder);
ns.runBackgroundOperations();
Revision head = ns.getHeadRevision().getRevision(ns.getClusterId());
assertNotNull(head);
JournalEntry entry = ns.getDocumentStore().find(JOURNAL, JournalEntry.asId(head));
assertNotNull(entry);
// must reference at least one branch commit
assertThat(Iterables.size(entry.getBranchCommits()), greaterThan(0));
// now remove them
for (JournalEntry bc : entry.getBranchCommits()) {
docStore.remove(JOURNAL, bc.getId());
}
// compare must still succeed even when branch commits
// are missing in the journal
NodeState after = ns.getRoot().getChildNode("test");
after.compareAgainstBaseState(before, new DefaultNodeStateDiff());
}
use of org.apache.jackrabbit.oak.spi.state.DefaultNodeStateDiff in project jackrabbit-oak by apache.
the class JournalDiffLoaderTest method useJournal.
// OAK-5228
@Test
public void useJournal() throws Exception {
final AtomicInteger journalQueryCounter = new AtomicInteger();
DocumentStore ds = new MemoryDocumentStore() {
@Nonnull
@Override
public <T extends Document> List<T> query(Collection<T> collection, String fromKey, String toKey, int limit) {
if (collection == Collection.JOURNAL) {
journalQueryCounter.incrementAndGet();
}
return super.query(collection, fromKey, toKey, limit);
}
};
DocumentNodeStore ns1 = builderProvider.newBuilder().setClusterId(1).clock(clock).setLeaseCheck(false).setDocumentStore(ds).setAsyncDelay(0).getNodeStore();
DocumentNodeStore ns2 = builderProvider.newBuilder().setClusterId(2).clock(clock).setLeaseCheck(false).setDocumentStore(ds).setAsyncDelay(0).getNodeStore();
NodeBuilder b1 = ns1.getRoot().builder();
NodeBuilder foo = b1.child("foo");
for (int i = 0; i < DocumentMK.MANY_CHILDREN_THRESHOLD + 1; i++) {
foo.child("n" + i);
}
merge(ns1, b1);
ns1.runBackgroundOperations();
ns2.runBackgroundOperations();
clock.waitUntil(clock.getTime() + TimeUnit.MINUTES.toMillis(10));
NodeBuilder b2 = ns2.getRoot().builder();
b2.child("foo").child("bar");
merge(ns2, b2);
ns2.runBackgroundOperations();
ns1.runBackgroundOperations();
// collect journal entry created for /foo/nX
new JournalGarbageCollector(ns1, TimeUnit.MINUTES.toMillis(5)).gc();
// the next modification updates the root revision
// for clusterId 1 past the removed journal entry
b1 = ns1.getRoot().builder();
b1.child("qux");
merge(ns1, b1);
ns1.runBackgroundOperations();
ns2.runBackgroundOperations();
// remember before state
DocumentNodeState fooBefore = (DocumentNodeState) ns1.getRoot().getChildNode("foo");
b2 = ns2.getRoot().builder();
b2.child("foo").child("baz");
merge(ns2, b2);
ns2.runBackgroundOperations();
ns1.runBackgroundOperations();
b1 = ns1.getRoot().builder();
b1.child("foo").child("bar").remove();
merge(ns1, b1);
ns1.runBackgroundOperations();
ns2.runBackgroundOperations();
DocumentNodeState fooAfter = (DocumentNodeState) ns1.getRoot().getChildNode("foo");
journalQueryCounter.set(0);
final Set<String> changes = Sets.newHashSet();
fooAfter.compareAgainstBaseState(fooBefore, new DefaultNodeStateDiff() {
@Override
public boolean childNodeChanged(String name, NodeState before, NodeState after) {
changes.add(name);
return true;
}
@Override
public boolean childNodeAdded(String name, NodeState after) {
changes.add(name);
return true;
}
@Override
public boolean childNodeDeleted(String name, NodeState before) {
changes.add(name);
return true;
}
});
assertThat(changes, containsInAnyOrder("bar", "baz"));
assertTrue("must use JournalDiffLoader", journalQueryCounter.get() > 0);
}
use of org.apache.jackrabbit.oak.spi.state.DefaultNodeStateDiff in project jackrabbit-oak by apache.
the class CompositeCompareTest method nodesOutsideTheMountsAreIgnored.
@Test
public void nodesOutsideTheMountsAreIgnored() throws CommitFailedException {
MountInfoProvider mip = Mounts.newBuilder().mount("libs", "/libs").build();
NodeStore globalStore = new MemoryNodeStore();
NodeStore libsStore = new MemoryNodeStore();
List<MountedNodeStore> mounts = Lists.newArrayList();
mounts.add(new MountedNodeStore(mip.getMountByName("libs"), libsStore));
CompositeNodeStore compositeNodeStore = new CompositeNodeStore(mip, globalStore, mounts);
NodeState empty = compositeNodeStore.getRoot();
NodeBuilder builder = globalStore.getRoot().builder();
builder.child("global-child-1");
builder.child("global-child-2");
globalStore.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
NodeBuilder libsBuilder = libsStore.getRoot().builder();
libsBuilder.child("libs");
libsBuilder.child("libs-child-1");
libsBuilder.child("libs-child-2");
libsStore.merge(libsBuilder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
NodeState modified = compositeNodeStore.getRoot();
final Set<String> addedChildren = newHashSet();
modified.compareAgainstBaseState(empty, new DefaultNodeStateDiff() {
@Override
public boolean childNodeAdded(String name, NodeState after) {
addedChildren.add(name);
return true;
}
});
assertEquals(ImmutableSet.of("global-child-1", "global-child-2", "libs"), addedChildren);
}
Aggregations