use of org.apache.jackrabbit.oak.stats.Clock in project jackrabbit-oak by apache.
the class SuggestionIntervalTest method createRepository.
@Override
protected ContentRepository createRepository() {
LuceneIndexProvider provider = new LuceneIndexProvider();
ContentRepository repository = new Oak().with(new InitialContent()).with(new OpenSecurityProvider()).with((QueryIndexProvider) provider).with((Observer) provider).with(new LuceneIndexEditorProvider()).createContentRepository();
clock = new Clock.Virtual();
try {
clock.waitUntil(System.currentTimeMillis());
} catch (Exception e) {
//eat exception if clock couldn't wait... that was just courteous anyway!
}
LuceneIndexEditorContext.setClock(clock);
return repository;
}
use of org.apache.jackrabbit.oak.stats.Clock in project jackrabbit-oak by apache.
the class LastRevRecoveryAgent method recoverCandidates.
/**
* Retrieves possible candidates which have been modified after the given
* {@code startTime} and recovers the missing updates.
*
* @param nodeInfo the info of the cluster node to recover.
* @param startTime the start time
* @param waitUntil wait at most until this time for an ongoing recovery
* done by another cluster node.
* @param info a string with additional information how recovery is run.
* @return the number of restored nodes or {@code -1} if recovery is still
* ongoing by another process even when {@code waitUntil} time was
* reached.
*/
private int recoverCandidates(final ClusterNodeInfoDocument nodeInfo, final long startTime, final long waitUntil, final String info) {
ClusterNodeInfoDocument infoDoc = nodeInfo;
int clusterId = infoDoc.getClusterId();
for (; ; ) {
if (missingLastRevUtil.acquireRecoveryLock(clusterId, nodeStore.getClusterId())) {
break;
}
Clock clock = nodeStore.getClock();
long remaining = waitUntil - clock.getTime();
if (remaining < 0) {
// no need to wait for lock release, waitUntil already reached
return -1;
}
log.info("Last revision recovery already being performed by " + "cluster node {}. Waiting at most until {} for recovery " + "to finish ({} seconds remaining).", infoDoc.getRecoveryBy(), Utils.timestampToString(waitUntil), remaining / 1000);
// check once every five seconds
long time = Math.min(waitUntil, clock.getTime() + 5000);
try {
clock.waitUntil(time);
} catch (InterruptedException e) {
Thread.interrupted();
String msg = "Interrupted while waiting for _lastRev recovery to finish.";
throw new DocumentStoreException(msg, e);
}
infoDoc = missingLastRevUtil.getClusterNodeInfo(clusterId);
if (!missingLastRevUtil.isRecoveryNeeded(infoDoc)) {
// meanwhile another process finished recovery
return 0;
}
}
// if we get here, the recovery lock was acquired successfully
boolean success = false;
try {
log.info("Recovering candidates modified after: [{}] for clusterId [{}] [{}]", Utils.timestampToString(startTime), clusterId, info);
Iterable<NodeDocument> suspects = missingLastRevUtil.getCandidates(startTime);
try {
log.info("Performing Last Revision Recovery for clusterNodeId {}", clusterId);
int num = recover(suspects, clusterId);
success = true;
return num;
} finally {
Utils.closeIfCloseable(suspects);
}
} finally {
missingLastRevUtil.releaseRecoveryLock(clusterId, success);
nodeStore.signalClusterStateChange();
}
}
use of org.apache.jackrabbit.oak.stats.Clock in project jackrabbit-oak by apache.
the class DocumentNodeStoreTest method conflictDetectionWithClockDifference.
// OAK-2929
@Test
public void conflictDetectionWithClockDifference() throws Exception {
MemoryDocumentStore store = new MemoryDocumentStore();
long now = System.currentTimeMillis();
Clock c1 = new Clock.Virtual();
c1.waitUntil(now);
Revision.setClock(c1);
DocumentNodeStore ns1 = builderProvider.newBuilder().clock(c1).setDocumentStore(store).setAsyncDelay(0).setClusterId(1).getNodeStore();
NodeBuilder b1 = ns1.getRoot().builder();
b1.child("node");
merge(ns1, b1);
// make /node visible
ns1.runBackgroundOperations();
Revision.resetClockToDefault();
Clock c2 = new Clock.Virtual();
// c2 is five seconds ahead
c2.waitUntil(now + 5000);
Revision.setClock(c2);
DocumentNodeStore ns2 = builderProvider.newBuilder().clock(c2).setDocumentStore(store).setAsyncDelay(0).setClusterId(2).getNodeStore();
// ns2 sees /node
assertTrue(ns2.getRoot().hasChildNode("node"));
// add a child /node/foo
NodeBuilder b2 = ns2.getRoot().builder();
b2.child("node").child("foo");
merge(ns2, b2);
// make /node/foo visible
ns2.runBackgroundOperations();
Revision.resetClockToDefault();
Revision.setClock(c1);
ns1.runBackgroundOperations();
b1 = ns1.getRoot().builder();
// ns1 sees /node/foo as well
assertTrue(b1.getChildNode("node").hasChildNode("foo"));
// remove both /node and /node/foo
b1.child("node").remove();
merge(ns1, b1);
Revision.resetClockToDefault();
Revision.setClock(c2);
b2 = ns2.getRoot().builder();
b2.child("node").child("bar");
try {
merge(ns2, b2);
// must not be able to add another child node
fail("must fail with CommitFailedException");
} catch (CommitFailedException e) {
// expected
}
}
use of org.apache.jackrabbit.oak.stats.Clock in project jackrabbit-oak by apache.
the class DocumentNodeStoreBranchesTest method commitHookChangesOnBranchWithInterference.
@Test
public void commitHookChangesOnBranchWithInterference() throws Exception {
Clock c = new Clock.Virtual();
c.waitUntil(System.currentTimeMillis());
Revision.setClock(c);
ClusterNodeInfo.setClock(c);
// enough nodes that diffManyChildren() is called
final int NUM_NODES = DocumentMK.MANY_CHILDREN_THRESHOLD * 2;
LOG.info("create new dns");
Builder nsBuilder = builderProvider.newBuilder();
nsBuilder.setAsyncDelay(0).clock(c);
final DocumentNodeStore ns = nsBuilder.getNodeStore();
// 0) initialization
{
LOG.info("initialization");
NodeBuilder initBuilder = ns.getRoot().builder();
for (int i = 0; i < NUM_NODES; i++) {
initBuilder.child("child" + i);
}
ns.merge(initBuilder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
}
// 1) do more than UPDATE_LIMIT changes
LOG.info("starting doing many changes to force a branch commit");
NodeBuilder rootBuilder = ns.getRoot().builder();
int totalUpdates = 5 * DocumentMK.UPDATE_LIMIT;
int updateShare = totalUpdates / NUM_NODES;
for (int i = 0; i < NUM_NODES; i++) {
NodeBuilder childBuilder = rootBuilder.child("child" + i);
childBuilder.child("grandChild" + i);
childBuilder.setProperty("p1", "originalValue");
for (int j = 0; j < updateShare; j++) {
childBuilder.setProperty("someProperty" + j, "sameValue");
}
}
// 2) wait 6 sec
LOG.info("after purge was triggered above, 'waiting' 6sec");
c.waitUntil(c.getTime() + 6000);
// 3) now in another 'session', do another merge - to change the head
LOG.info("in another session, do some unrelated changes to change the head");
NodeBuilder parallelBuilder = ns.getRoot().builder();
parallelBuilder.child("unrelated").setProperty("anyProp", "anywhere");
ns.merge(parallelBuilder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
// 4) now merge the first session - this should now fail
LOG.info("now merge the original builder - this should cause not all children to be visited");
ns.merge(rootBuilder, CompositeHook.compose(Arrays.<CommitHook>asList(new TestHook("p"), new TestHook("q"))), CommitInfo.EMPTY);
DocumentNodeState root = ns.getRoot();
for (int i = 0; i < NUM_NODES; i++) {
NodeState child = root.getChildNode("child" + i);
assertTrue(child.exists());
assertEquals("test", child.getProperty("p1").getValue(Type.STRING));
}
}
use of org.apache.jackrabbit.oak.stats.Clock in project jackrabbit-oak by apache.
the class DocumentNodeStoreTest method concurrentChildOperations.
// OAK-3646
@Test
public void concurrentChildOperations() throws Exception {
Clock clock = new Clock.Virtual();
clock.waitUntil(System.currentTimeMillis());
Revision.setClock(clock);
MemoryDocumentStore store = new MemoryDocumentStore();
DocumentNodeStore ns1 = builderProvider.newBuilder().setAsyncDelay(0).clock(clock).setDocumentStore(store).setClusterId(1).getNodeStore();
DocumentNodeStore ns2 = builderProvider.newBuilder().setAsyncDelay(0).clock(clock).setDocumentStore(store).setClusterId(2).getNodeStore();
// create some children under /foo/bar
NodeBuilder b1 = ns1.getRoot().builder();
NodeBuilder node = b1.child("foo").child("bar");
node.child("child-0");
node.child("child-1");
node.child("child-2");
merge(ns1, b1);
// make changes visible on both cluster nodes
ns1.runBackgroundOperations();
ns2.runBackgroundOperations();
// remove child-0 on cluster node 1
b1 = ns1.getRoot().builder();
b1.child("foo").child("bar").getChildNode("child-0").remove();
merge(ns1, b1);
// push _lastRev updates to DocumentStore
ns1.runBackgroundOperations();
// remove child-1 on cluster node 2
NodeBuilder b2 = ns2.getRoot().builder();
b2.child("foo").child("bar").getChildNode("child-1").remove();
merge(ns2, b2);
// on cluster node 2, remove of child-0 is not yet visible
DocumentNodeState bar = asDocumentNodeState(ns2.getRoot().getChildNode("foo").getChildNode("bar"));
List<ChildNodeEntry> children = Lists.newArrayList(bar.getChildNodeEntries());
assertEquals(2, Iterables.size(children));
RevisionVector invalidate = bar.getLastRevision();
assertNotNull(invalidate);
// this will make changes from cluster node 1 visible
ns2.runBackgroundOperations();
// wait two hours
clock.waitUntil(clock.getTime() + TimeUnit.HOURS.toMillis(2));
// collect everything older than one hour
// this will remove child-0 and child-1 doc
ns1.getVersionGarbageCollector().gc(1, TimeUnit.HOURS);
// forget cache entry for deleted node
ns2.invalidateNodeCache("/foo/bar/child-0", invalidate);
children = Lists.newArrayList(ns2.getRoot().getChildNode("foo").getChildNode("bar").getChildNodeEntries());
assertEquals(1, Iterables.size(children));
}
Aggregations