Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/model/CommitBuilder.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/model/CommitBuilder.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/model/CommitBuilder.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,408 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.model; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.jackrabbit.oak.commons.json.JsonObject; -import org.apache.jackrabbit.oak.commons.json.JsopBuilder; -import org.apache.jackrabbit.mk.store.NotFoundException; -import org.apache.jackrabbit.mk.store.RevisionStore; -import org.apache.jackrabbit.oak.commons.PathUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * - */ -public class CommitBuilder { - - private static final Logger LOG = LoggerFactory.getLogger(CommitBuilder.class); - - /** revision changes are based upon */ - private Id baseRevId; - - private final String msg; - - private final RevisionStore store; - - // staging area - private final StagedNodeTree stagedTree; - - // change log - private final List changeLog = new ArrayList(); - - public CommitBuilder(Id baseRevId, String msg, RevisionStore store) throws Exception { - this.baseRevId = baseRevId; - this.msg = msg; - this.store = store; - stagedTree = new StagedNodeTree(store, baseRevId); - } - - public void addNode(String parentNodePath, String nodeName, JsonObject node) throws Exception { - Change change = new AddNode(parentNodePath, nodeName, node); - change.apply(); - // update change log - changeLog.add(change); - } - - public void removeNode(String nodePath) throws NotFoundException, Exception { - Change change = new RemoveNode(nodePath); - change.apply(); - // update change log - changeLog.add(change); - } - - public void moveNode(String srcPath, String destPath) throws NotFoundException, Exception { - Change change = new MoveNode(srcPath, destPath); - change.apply(); - // update change log - changeLog.add(change); - } - - public void copyNode(String srcPath, String destPath) throws NotFoundException, Exception { - Change change = new CopyNode(srcPath, destPath); - change.apply(); - // update change log - changeLog.add(change); - } - - public void setProperty(String nodePath, String propName, String propValue) throws Exception { - Change change = new SetProperty(nodePath, propName, propValue); - change.apply(); - // update change log - changeLog.add(change); - } - - public Id /* new revId */ doCommit() throws Exception { - return doCommit(false); - } - - public Id /* new revId */ doCommit(boolean createBranch) throws Exception { - if (stagedTree.isEmpty() && !createBranch) { - // nothing to commit - return baseRevId; - } - - StoredCommit baseCommit = store.getCommit(baseRevId); - if (createBranch && baseCommit.getBranchRootId() != null) { - throw new Exception("cannot branch off a private branch"); - } - - boolean privateCommit = createBranch || baseCommit.getBranchRootId() != null; - - if (!privateCommit) { - Id currentHead = store.getHeadCommitId(); - if (!currentHead.equals(baseRevId)) { - // todo gracefully handle certain conflicts (e.g. changes on moved sub-trees, competing deletes etc) - // update base revision to more recent current head - baseRevId = currentHead; - // reset staging area - stagedTree.reset(baseRevId); - // replay change log on new base revision - for (Change change : changeLog) { - change.apply(); - } - } - } - - RevisionStore.PutToken token = store.createPutToken(); - Id rootNodeId = - changeLog.isEmpty() ? baseCommit.getRootNodeId() : stagedTree.persist(token); - - Id newRevId; - - if (!privateCommit) { - store.lockHead(); - try { - Id currentHead = store.getHeadCommitId(); - if (!currentHead.equals(baseRevId)) { - // there's a more recent head revision - // perform a three-way merge - rootNodeId = stagedTree.merge(store.getNode(rootNodeId), currentHead, baseRevId, token); - // update base revision to more recent current head - baseRevId = currentHead; - } - - if (store.getCommit(currentHead).getRootNodeId().equals(rootNodeId)) { - // the commit didn't cause any changes, - // no need to create new commit object/update head revision - return currentHead; - } - // persist new commit - MutableCommit newCommit = new MutableCommit(); - newCommit.setParentId(baseRevId); - newCommit.setCommitTS(System.currentTimeMillis()); - newCommit.setMsg(msg); - StringBuilder diff = new StringBuilder(); - for (Change change : changeLog) { - if (diff.length() > 0) { - diff.append('\n'); - } - diff.append(change.asDiff()); - } - newCommit.setChanges(diff.toString()); - newCommit.setRootNodeId(rootNodeId); - newCommit.setBranchRootId(null); - newRevId = store.putHeadCommit(token, newCommit, null, null); - } finally { - store.unlockHead(); - } - } else { - // private commit/branch - MutableCommit newCommit = new MutableCommit(); - newCommit.setParentId(baseCommit.getId()); - newCommit.setCommitTS(System.currentTimeMillis()); - newCommit.setMsg(msg); - StringBuilder diff = new StringBuilder(); - for (Change change : changeLog) { - if (diff.length() > 0) { - diff.append('\n'); - } - diff.append(change.asDiff()); - } - newCommit.setChanges(diff.toString()); - newCommit.setRootNodeId(rootNodeId); - if (createBranch) { - newCommit.setBranchRootId(baseCommit.getId()); - } else { - newCommit.setBranchRootId(baseCommit.getBranchRootId()); - } - newRevId = store.putCommit(token, newCommit); - } - - // reset instance - stagedTree.reset(newRevId); - changeLog.clear(); - - return newRevId; - } - - public Id rebase(Id fromId, Id toId) throws Exception { - RevisionStore.PutToken token = store.createPutToken(); - - Id rebasedId = stagedTree.rebase(baseRevId, fromId, toId, token); - - if (store.getCommit(toId).getRootNodeId().equals(rebasedId)) { - // the rebase didn't cause any changes, - // no need to create new commit object/update head revision - return toId; - } - - StoredCommit baseCommit = store.getCommit(baseRevId); - MutableCommit newCommit = new MutableCommit(); - newCommit.setParentId(baseRevId); - newCommit.setCommitTS(System.currentTimeMillis()); - newCommit.setMsg(msg); - // dynamically build diff for rebased commit - String diff = new DiffBuilder( - store.getRootNode(toId), - store.getNode(rebasedId), - "/", -1, store, "").build(); - newCommit.setChanges(diff); - newCommit.setRootNodeId(rebasedId); - newCommit.setBranchRootId(baseCommit.getBranchRootId()); - Id newRevId = store.putCommit(token, newCommit); - - // reset instance - stagedTree.reset(newRevId); - changeLog.clear(); - - return newRevId; - } - - public Id /* new revId */ doMerge() throws Exception { - StoredCommit branchCommit = store.getCommit(baseRevId); - Id branchRootId = branchCommit.getBranchRootId(); - if (branchRootId == null) { - throw new Exception("can only merge a private branch commit"); - } - - RevisionStore.PutToken token = store.createPutToken(); - Id rootNodeId = - changeLog.isEmpty() ? branchCommit.getRootNodeId() : stagedTree.persist(token); - - Id newRevId; - - store.lockHead(); - try { - Id currentHead = store.getHeadCommitId(); - - StoredNode ourRoot = store.getNode(rootNodeId); - - rootNodeId = stagedTree.merge(ourRoot, currentHead, branchRootId, token); - - if (store.getCommit(currentHead).getRootNodeId().equals(rootNodeId)) { - // the merge didn't cause any changes, - // no need to create new commit object/update head revision - return currentHead; - } - MutableCommit newCommit = new MutableCommit(); - newCommit.setParentId(currentHead); - newCommit.setCommitTS(System.currentTimeMillis()); - newCommit.setMsg(msg); - // dynamically build diff of merged commit - String diff = new DiffBuilder( - store.getRootNode(currentHead), - store.getNode(rootNodeId), - "/", -1, store, "").build(); - if (diff.isEmpty()) { - LOG.debug("merge of empty branch {} with differing content hashes encountered, ignore and keep current head {}", - baseRevId, currentHead); - return currentHead; - } - newCommit.setChanges(diff); - newCommit.setRootNodeId(rootNodeId); - newCommit.setBranchRootId(null); - newRevId = store.putHeadCommit(token, newCommit, branchRootId, baseRevId); - } finally { - store.unlockHead(); - } - - // reset instance - stagedTree.reset(newRevId); - changeLog.clear(); - - return newRevId; - } - - //--------------------------------------------------------< inner classes > - - abstract class Change { - abstract void apply() throws Exception; - abstract String asDiff(); - } - - class AddNode extends Change { - String parentNodePath; - String nodeName; - JsonObject node; - - AddNode(String parentNodePath, String nodeName, JsonObject node) { - this.parentNodePath = parentNodePath; - this.nodeName = nodeName; - this.node = node; - } - - @Override - void apply() throws Exception { - stagedTree.add(parentNodePath, nodeName, node); - } - - @Override - String asDiff() { - JsopBuilder diff = new JsopBuilder(); - diff.tag('+').key(PathUtils.concat(parentNodePath, nodeName)); - node.toJson(diff); - return diff.toString(); - } - } - - class RemoveNode extends Change { - String nodePath; - - RemoveNode(String nodePath) { - this.nodePath = nodePath; - } - - @Override - void apply() throws Exception { - stagedTree.remove(nodePath); - } - - @Override - String asDiff() { - JsopBuilder diff = new JsopBuilder(); - diff.tag('-').value(nodePath); - return diff.toString(); - } - } - - class MoveNode extends Change { - String srcPath; - String destPath; - - MoveNode(String srcPath, String destPath) { - this.srcPath = srcPath; - this.destPath = destPath; - } - - @Override - void apply() throws Exception { - stagedTree.move(srcPath, destPath); - } - - @Override - String asDiff() { - JsopBuilder diff = new JsopBuilder(); - diff.tag('>').key(srcPath).value(destPath); - return diff.toString(); - } - } - - class CopyNode extends Change { - String srcPath; - String destPath; - - CopyNode(String srcPath, String destPath) { - this.srcPath = srcPath; - this.destPath = destPath; - } - - @Override - void apply() throws Exception { - stagedTree.copy(srcPath, destPath); - } - - @Override - String asDiff() { - JsopBuilder diff = new JsopBuilder(); - diff.tag('*').key(srcPath).value(destPath); - return diff.toString(); - } - } - - class SetProperty extends Change { - String nodePath; - String propName; - String propValue; - - SetProperty(String nodePath, String propName, String propValue) { - this.nodePath = nodePath; - this.propName = propName; - this.propValue = propValue; - } - - @Override - void apply() throws Exception { - stagedTree.setProperty(nodePath, propName, propValue); - } - - @Override - String asDiff() { - JsopBuilder diff = new JsopBuilder(); - diff.tag('^').key(PathUtils.concat(nodePath, propName)); - if (propValue != null) { - diff.encodedValue(propValue); - } else { - diff.value(null); - } - return diff.toString(); - } - } -} Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/store/RevisionStore.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/store/RevisionStore.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/store/RevisionStore.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,96 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.store; - -import org.apache.jackrabbit.mk.model.ChildNodeEntries; -import org.apache.jackrabbit.mk.model.Id; -import org.apache.jackrabbit.mk.model.MutableCommit; -import org.apache.jackrabbit.mk.model.MutableNode; - -/** - * Write operations. - */ -public interface RevisionStore extends RevisionProvider { - - /** - * Token that must be created first before invoking any put operation. - */ - public abstract class PutToken { - - /* Prevent other implementations. */ - PutToken() {} - } - - /** - * Create a put token. - * - * @return put token - */ - PutToken createPutToken(); - - Id /*id*/ putNode(PutToken token, MutableNode node) throws Exception; - Id /*id*/ putCNEMap(PutToken token, ChildNodeEntries map) throws Exception; - - /** - * Lock the head. Must be called prior to putting a new head commit. - * - * @see #putHeadCommit(PutToken, MutableCommit, Id, Id) - * @see #unlockHead() - */ - void lockHead(); - - /** - * Put a new head commit. Must be called while holding a lock on the head. - * - * @param token - * put token - * @param commit - * commit - * @param branchRootId - * former branch root id, if this is a merge; otherwise - * {@code null} - * @param branchRevId - * current branch head, i.e. last commit on this branch, - * if this is a merge; otherwise {@code null} - * @return head commit id - * @throws Exception - * if an error occurs - * @see #lockHead() - */ - Id /*id*/ putHeadCommit(PutToken token, MutableCommit commit, Id branchRootId, Id branchRevId) throws Exception; - - /** - * Unlock the head. - * - * @see #lockHead() - */ - void unlockHead(); - - /** - * Store a new commit. - *

- * Unlike {@code putHeadCommit(MutableCommit)}, this method - * does not affect the current head commit and therefore doesn't - * require a lock on the head. - * - * @param token put token - * @param commit commit - * @return new commit id - * @throws Exception if an error occurs - */ - Id /*id*/ putCommit(PutToken token, MutableCommit commit) throws Exception; -} Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/core/MicroKernelImpl.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/core/MicroKernelImpl.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/core/MicroKernelImpl.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,741 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.core; - -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import javax.annotation.Nonnull; - -import org.apache.jackrabbit.mk.api.MicroKernel; -import org.apache.jackrabbit.mk.api.MicroKernelException; -import org.apache.jackrabbit.oak.commons.json.JsonObject; -import org.apache.jackrabbit.oak.commons.json.JsopBuilder; -import org.apache.jackrabbit.oak.commons.json.JsopReader; -import org.apache.jackrabbit.oak.commons.json.JsopTokenizer; -import org.apache.jackrabbit.mk.model.ChildNodeEntry; -import org.apache.jackrabbit.mk.model.Commit; -import org.apache.jackrabbit.mk.model.CommitBuilder; -import org.apache.jackrabbit.mk.model.DiffBuilder; -import org.apache.jackrabbit.mk.model.Id; -import org.apache.jackrabbit.mk.model.StoredCommit; -import org.apache.jackrabbit.mk.model.StoredNode; -import org.apache.jackrabbit.mk.store.NotFoundException; -import org.apache.jackrabbit.mk.store.RevisionStore; -import org.apache.jackrabbit.mk.util.CommitGate; -import org.apache.jackrabbit.mk.util.NameFilter; -import org.apache.jackrabbit.mk.util.NodeFilter; -import org.apache.jackrabbit.oak.commons.PathUtils; - -/** - * - */ -public class MicroKernelImpl implements MicroKernel { - - protected Repository rep; - private final CommitGate gate = new CommitGate(); - - public MicroKernelImpl(String homeDir) throws MicroKernelException { - init(homeDir); - } - - /** - * Creates a new in-memory kernel instance that doesn't need to be - * explicitly closed, i.e. standard Java garbage collection will take - * care of releasing any acquired resources when no longer needed. - * Useful especially for test cases and other similar scenarios. - */ - public MicroKernelImpl() { - this(new Repository()); - } - - /** - * Alternate constructor, used for testing. - * - * @param rep repository, already initialized - */ - public MicroKernelImpl(Repository rep) { - this.rep = rep; - try { - // initialize commit gate with current head - gate.commit(rep.getHeadRevision().toString()); - } catch (Exception e) { - throw new MicroKernelException(e); - } - } - - protected void init(String homeDir) throws MicroKernelException { - try { - rep = new Repository(homeDir); - rep.init(); - // initialize commit gate with current head - gate.commit(rep.getHeadRevision().toString()); - } catch (Exception e) { - throw new MicroKernelException(e); - } - } - - public void dispose() { - gate.commit("end"); - if (rep != null) { - try { - rep.shutDown(); - } catch (Exception ignore) { - // fail silently - } - rep = null; - } - } - - public String getHeadRevision() throws MicroKernelException { - if (rep == null) { - throw new IllegalStateException("this instance has already been disposed"); - } - return getHeadRevisionId().toString(); - } - - public String checkpoint(long lifetime) throws MicroKernelException { - // FIXME: need to signal to the garbage collector that this revision - // should not be collected until the requested lifetime is over - return getHeadRevision(); - } - - /** - * Same as {@code getHeadRevisionId}, with typed {@code Id} return value instead of string. - * - * @see #getHeadRevision() - */ - private Id getHeadRevisionId() throws MicroKernelException { - try { - return rep.getHeadRevision(); - } catch (Exception e) { - throw new MicroKernelException(e); - } - } - - private Id getBaseRevisionId(Id branchId) throws MicroKernelException { - try { - return rep.getBaseRevision(branchId); - } - catch (Exception e) { - throw new MicroKernelException(e); - } - } - - public String getRevisionHistory(long since, int maxEntries, String path) throws MicroKernelException { - if (rep == null) { - throw new IllegalStateException("this instance has already been disposed"); - } - - path = (path == null || "".equals(path)) ? "/" : path; - boolean filtered = !"/".equals(path); - - maxEntries = maxEntries < 0 ? Integer.MAX_VALUE : maxEntries; - List history = new ArrayList(); - try { - StoredCommit commit = rep.getHeadCommit(); - while (commit != null - && history.size() < maxEntries - && commit.getCommitTS() >= since) { - if (filtered) { - try { - RevisionStore rs = rep.getRevisionStore(); - String diff = new DiffBuilder( - rs.getRootNode(commit.getParentId()), - rs.getNode(commit.getRootNodeId()), - "/", -1, rep.getRevisionStore(), path).build(); - if (!diff.isEmpty()) { - history.add(commit); - } - } catch (Exception e) { - throw new MicroKernelException(e); - } - } else { - history.add(commit); - } - - Id commitId = commit.getParentId(); - if (commitId == null) { - break; - } - commit = rep.getCommit(commitId); - } - } catch (Exception e) { - throw new MicroKernelException(e); - } - - JsopBuilder buff = new JsopBuilder().array(); - for (int i = history.size() - 1; i >= 0; i--) { - StoredCommit commit = history.get(i); - buff.object(). - key("id").value(commit.getId().toString()). - key("ts").value(commit.getCommitTS()). - key("msg").value(commit.getMsg()). - endObject(); - } - return buff.endArray().toString(); - } - - public String waitForCommit(String oldHeadRevisionId, long maxWaitMillis) throws MicroKernelException, InterruptedException { - return gate.waitForCommit(oldHeadRevisionId, maxWaitMillis); - } - - public String getJournal(String fromRevision, String toRevision, String path) throws MicroKernelException { - if (rep == null) { - throw new IllegalStateException("this instance has already been disposed"); - } - - path = (path == null || "".equals(path)) ? "/" : path; - boolean filtered = !"/".equals(path); - - Id fromRevisionId = Id.fromString(fromRevision); - Id toRevisionId = toRevision == null ? getHeadRevisionId() : Id.fromString(toRevision); - - List commits = new ArrayList(); - try { - StoredCommit toCommit = rep.getCommit(toRevisionId); - - Commit fromCommit; - if (toRevisionId.equals(fromRevisionId)) { - fromCommit = toCommit; - } else { - fromCommit = rep.getCommit(fromRevisionId); - } - - if (fromCommit.getBranchRootId() != null) { - if (!fromCommit.getBranchRootId().equals(toCommit.getBranchRootId())) { - throw new MicroKernelException("inconsistent range specified: fromRevision denotes a private branch while toRevision denotes a head or another private branch"); - } - } - - if (fromCommit.getCommitTS() > toCommit.getCommitTS()) { - // negative range, return empty journal - return "[]"; - } - - // collect commits, starting with toRevisionId - // and traversing parent commit links until we've reached - // fromRevisionId - StoredCommit commit = toCommit; - while (commit != null) { - commits.add(commit); - if (commit.getId().equals(fromRevisionId)) { - break; - } - Id commitId = commit.getParentId(); - if (commitId == null) { - // inconsistent revision history, ignore silently... - break; - } - commit = rep.getCommit(commitId); - if (commit.getCommitTS() < fromCommit.getCommitTS()) { - // inconsistent revision history, ignore silently... - break; - } - } - } catch (MicroKernelException e) { - // re-throw - throw e; - } catch (Exception e) { - throw new MicroKernelException(e); - } - - JsopBuilder commitBuff = new JsopBuilder().array(); - // iterate over commits in chronological order, - // starting with oldest commit - for (int i = commits.size() - 1; i >= 0; i--) { - StoredCommit commit = commits.get(i); - if (commit.getParentId() == null) { - continue; - } - String diff = commit.getChanges(); - if (filtered) { - try { - RevisionStore rs = rep.getRevisionStore(); - diff = new DiffBuilder( - rs.getRootNode(commit.getParentId()), - rs.getNode(commit.getRootNodeId()), - "/", -1, rep.getRevisionStore(), path).build(); - if (diff.isEmpty()) { - continue; - } - } catch (Exception e) { - throw new MicroKernelException(e); - } - } - commitBuff.object(). - key("id").value(commit.getId().toString()). - key("ts").value(commit.getCommitTS()). - key("msg").value(commit.getMsg()); - if (commit.getBranchRootId() != null) { - commitBuff.key("branchRootId").value(commit.getBranchRootId().toString()); - } - commitBuff.key("changes").value(diff).endObject(); - } - return commitBuff.endArray().toString(); - } - - public String diff(String fromRevision, String toRevision, String path, int depth) throws MicroKernelException { - path = (path == null || "".equals(path)) ? "/" : path; - - if (depth < -1) { - throw new IllegalArgumentException("depth"); - } - - Id fromRevisionId, toRevisionId; - if (fromRevision == null || toRevision == null) { - Id head = getHeadRevisionId(); - fromRevisionId = fromRevision == null ? head : Id.fromString(fromRevision); - toRevisionId = toRevision == null ? head : Id.fromString(toRevision); - } else { - fromRevisionId = Id.fromString(fromRevision); - toRevisionId = Id.fromString(toRevision); - } - - if (fromRevisionId.equals(toRevisionId)) { - return ""; - } - - try { - if ("/".equals(path)) { - StoredCommit toCommit = rep.getCommit(toRevisionId); - if (toCommit.getParentId().equals(fromRevisionId) && depth == -1) { - // specified range spans a single commit and depth is not limited: - // use diff stored in commit instead of building it dynamically - return toCommit.getChanges(); - } - } - - StoredNode from = null, to = null; - try { - from = rep.getNode(fromRevisionId, path); - } catch (NotFoundException ignore) { - } - try { - to = rep.getNode(toRevisionId, path); - } catch (NotFoundException ignore) { - } - return new DiffBuilder(from, to, path, depth, rep.getRevisionStore(), path).build(); - } catch (Exception e) { - throw new MicroKernelException(e); - } - } - - public boolean nodeExists(String path, String revisionId) throws MicroKernelException { - if (rep == null) { - throw new IllegalStateException("this instance has already been disposed"); - } - - Id revId = revisionId == null ? getHeadRevisionId() : Id.fromString(revisionId); - try { - return rep.nodeExists(revId, path); - } catch (Exception e) { - throw new MicroKernelException(e); - } - } - - public long getChildNodeCount(String path, String revisionId) throws MicroKernelException { - if (rep == null) { - throw new IllegalStateException("this instance has already been disposed"); - } - - Id revId = revisionId == null ? getHeadRevisionId() : Id.fromString(revisionId); - - try { - return rep.getNode(revId, path).getChildNodeCount(); - } catch (NotFoundException e) { - throw new MicroKernelException("Path " + path + " not found in revision " + revisionId); - } catch (Exception e) { - throw new MicroKernelException(e); - } - } - - public String getNodes(String path, String revisionId, int depth, long offset, int maxChildNodes, String filter) throws MicroKernelException { - if (rep == null) { - throw new IllegalStateException("this instance has already been disposed"); - } - - Id id = null; - if (!path.startsWith("/")) { - // OAK-468: Identifier- or hash-based access in the MicroKernel - id = Id.fromString(path); - } - Id revId = revisionId == null ? getHeadRevisionId() : Id.fromString(revisionId); - - NodeFilter nodeFilter = filter == null || filter.isEmpty() ? null : NodeFilter.parse(filter); - if (offset > 0 && nodeFilter != null && nodeFilter.getChildNodeFilter() != null) { - // both an offset > 0 and a filter on node names have been specified... - throw new IllegalArgumentException("offset > 0 with child node filter"); - } - - try { - StoredNode node; - try { - if (id != null) { - node = rep.getRevisionStore().getNode(id); - } else { - node = rep.getNode(revId, path); - } - } catch (NotFoundException e) { - return null; - } - - JsopBuilder buf = new JsopBuilder().object(); - toJson(buf, node, depth, (int) offset, maxChildNodes, true, nodeFilter); - return buf.endObject().toString(); - } catch (Exception e) { - throw new MicroKernelException(e); - } - } - - public String commit(String path, String jsonDiff, String revisionId, String message) throws MicroKernelException { - if (rep == null) { - throw new IllegalStateException("this instance has already been disposed"); - } - if (path.length() > 0 && !PathUtils.isAbsolute(path)) { - throw new IllegalArgumentException("absolute path expected: " + path); - } - if (jsonDiff == null || jsonDiff.length() == 0) { - return revisionId != null ? revisionId : getHeadRevision(); - } - - Id revId = revisionId == null ? getHeadRevisionId() : Id.fromString(revisionId); - - try { - JsopTokenizer t = new JsopTokenizer(jsonDiff); - CommitBuilder cb = rep.getCommitBuilder(revId, message); - while (true) { - int r = t.read(); - if (r == JsopReader.END) { - break; - } - int pos; // used for error reporting - switch (r) { - case '+': { - pos = t.getLastPos(); - String subPath = t.readString(); - t.read(':'); - t.read('{'); - String nodePath = PathUtils.concat(path, subPath); - if (!PathUtils.isAbsolute(nodePath)) { - throw new Exception("absolute path expected: " + nodePath + ", pos: " + pos); - } - String parentPath = PathUtils.getParentPath(nodePath); - String nodeName = PathUtils.getName(nodePath); - cb.addNode(parentPath, nodeName, JsonObject.create(t)); - break; - } - case '-': { - pos = t.getLastPos(); - String subPath = t.readString(); - String targetPath = PathUtils.concat(path, subPath); - if (!PathUtils.isAbsolute(targetPath)) { - throw new Exception("absolute path expected: " + targetPath + ", pos: " + pos); - } - cb.removeNode(targetPath); - break; - } - case '^': { - pos = t.getLastPos(); - String subPath = t.readString(); - t.read(':'); - String value; - if (t.matches(JsopReader.NULL)) { - value = null; - } else { - value = t.readRawValue().trim(); - } - String targetPath = PathUtils.concat(path, subPath); - if (!PathUtils.isAbsolute(targetPath)) { - throw new Exception("absolute path expected: " + targetPath + ", pos: " + pos); - } - String parentPath = PathUtils.getParentPath(targetPath); - String propName = PathUtils.getName(targetPath); - cb.setProperty(parentPath, propName, value); - break; - } - case '>': { - pos = t.getLastPos(); - String subPath = t.readString(); - String srcPath = PathUtils.concat(path, subPath); - if (!PathUtils.isAbsolute(srcPath)) { - throw new Exception("absolute path expected: " + srcPath + ", pos: " + pos); - } - t.read(':'); - pos = t.getLastPos(); - String targetPath = t.readString(); - if (!PathUtils.isAbsolute(targetPath)) { - targetPath = PathUtils.concat(path, targetPath); - if (!PathUtils.isAbsolute(targetPath)) { - throw new Exception("absolute path expected: " + targetPath + ", pos: " + pos); - } - } - cb.moveNode(srcPath, targetPath); - break; - } - case '*': { - pos = t.getLastPos(); - String subPath = t.readString(); - String srcPath = PathUtils.concat(path, subPath); - if (!PathUtils.isAbsolute(srcPath)) { - throw new Exception("absolute path expected: " + srcPath + ", pos: " + pos); - } - t.read(':'); - pos = t.getLastPos(); - String targetPath = t.readString(); - if (!PathUtils.isAbsolute(targetPath)) { - targetPath = PathUtils.concat(path, targetPath); - if (!PathUtils.isAbsolute(targetPath)) { - throw new Exception("absolute path expected: " + targetPath + ", pos: " + pos); - } - } - cb.copyNode(srcPath, targetPath); - break; - } - default: - throw new IllegalArgumentException("jsonDiff: illegal token '" + t.getToken() + "' at pos: " + t.getLastPos()); - } - } - Id newHead = cb.doCommit(); - if (!newHead.equals(revId)) { - // non-empty commit - if (rep.getCommit(newHead).getBranchRootId() == null) { - // OAK-265: only trigger commit gate for non-branch commits - gate.commit(newHead.toString()); - } - } - return newHead.toString(); - } catch (Exception e) { - throw new MicroKernelException(e); - } - } - - public String branch(String trunkRevisionId) throws MicroKernelException { - // create a private branch - - if (rep == null) { - throw new IllegalStateException("this instance has already been disposed"); - } - - Id revId = trunkRevisionId == null ? getHeadRevisionId() : Id.fromString(trunkRevisionId); - - try { - CommitBuilder cb = rep.getCommitBuilder(revId, ""); - return cb.doCommit(true).toString(); - } catch (Exception e) { - throw new MicroKernelException(e); - } - } - - public String merge(String branchRevisionId, String message) throws MicroKernelException { - // merge a private branch with current head revision - - if (rep == null) { - throw new IllegalStateException("this instance has already been disposed"); - } - - Id revId = Id.fromString(branchRevisionId); - - try { - return rep.getCommitBuilder(revId, message).doMerge().toString(); - } catch (Exception e) { - throw new MicroKernelException(e); - } - } - - public String rebase(String branchRevisionId, String newBaseRevisionId) { - Id branchId = Id.fromString(branchRevisionId); - Id baseId = getBaseRevisionId(branchId); - Id newBaseId = newBaseRevisionId == null ? getHeadRevisionId() : Id.fromString(newBaseRevisionId); - - if (baseId.equals(newBaseId)) { - return branchRevisionId; - } - else { - Id newBranchId = Id.fromString(branch(newBaseRevisionId)); - try { - CommitBuilder cb = rep.getCommitBuilder(newBranchId, - "rebasing " + branchRevisionId + " onto " + newBaseRevisionId); - return cb.rebase(baseId, branchId).toString(); - } - catch (Exception e) { - throw new MicroKernelException(e); - } - } - } - - @Nonnull - @Override - public String reset(@Nonnull String branchRevisionId, - @Nonnull String ancestorRevisionId) - throws MicroKernelException { - Id branchId = Id.fromString(branchRevisionId); - Id ancestorId = Id.fromString(ancestorRevisionId); - StoredCommit commit; - try { - commit = rep.getCommit(branchId); - } catch (Exception e) { - throw new MicroKernelException(e); - } - Id baseId = commit.getBranchRootId(); - if (baseId == null) { - throw new MicroKernelException("Not a private branch: " + branchRevisionId); - } - // verify ancestorId is in fact an ancestor of branchId - while (!ancestorId.equals(branchId)) { - try { - commit = rep.getCommit(branchId); - } catch (Exception e) { - throw new MicroKernelException(e); - } - if (commit.getBranchRootId() == null) { - throw new MicroKernelException(ancestorRevisionId + " is not " + - "an ancestor revision of " + branchRevisionId); - } - branchId = commit.getParentId(); - } - return ancestorRevisionId; - } - - public long getLength(String blobId) throws MicroKernelException { - if (rep == null) { - throw new IllegalStateException("this instance has already been disposed"); - } - try { - return rep.getBlobStore().getBlobLength(blobId); - } catch (Exception e) { - throw new MicroKernelException(e); - } - } - - public int read(String blobId, long pos, byte[] buff, int off, int length) throws MicroKernelException { - if (rep == null) { - throw new IllegalStateException("this instance has already been disposed"); - } - try { - return rep.getBlobStore().readBlob(blobId, pos, buff, off, length); - } catch (Exception e) { - throw new MicroKernelException(e); - } - } - - public String write(InputStream in) throws MicroKernelException { - if (rep == null) { - throw new IllegalStateException("this instance has already been disposed"); - } - try { - return rep.getBlobStore().writeBlob(in); - } catch (Exception e) { - throw new MicroKernelException(e); - } - } - - //-------------------------------------------------------< implementation > - - void toJson(JsopBuilder builder, StoredNode node, - int depth, int offset, int maxChildNodes, - boolean inclVirtualProps, NodeFilter filter) throws Exception { - for (Map.Entry prop : node.getProperties().entrySet()) { - if (filter == null || filter.includeProperty(prop.getKey())) { - builder.key(prop.getKey()).encodedValue(prop.getValue()); - } - } - long childCount = node.getChildNodeCount(); - if (inclVirtualProps) { - if (filter == null || filter.includeProperty(":childNodeCount")) { - // :childNodeCount is by default always included - // unless it is explicitly excluded in the filter - builder.key(":childNodeCount").value(childCount); - } - if (filter != null) { - NameFilter nf = filter.getPropertyFilter(); - if (nf != null) { - // check whether :id has been explicitly included - if (nf.getInclusionPatterns().contains(":hash") - && !nf.getExclusionPatterns().contains(":hash")) { - builder.key(":hash").value(node.getId().toString()); - } - // check whether :id has been explicitly included - if (nf.getInclusionPatterns().contains(":id") - && !nf.getExclusionPatterns().contains(":id")) { - builder.key(":id").value(node.getId().toString()); - } - } - } - } - if (childCount > 0 && depth >= 0) { - if (filter != null) { - NameFilter childFilter = filter.getChildNodeFilter(); - if (childFilter != null && !childFilter.containsWildcard()) { - // optimization for large child node lists: - // no need to iterate over the entire child node list if the filter - // does not include wildcards - int count = maxChildNodes == -1 ? Integer.MAX_VALUE : maxChildNodes; - for (String name : childFilter.getInclusionPatterns()) { - ChildNodeEntry cne = node.getChildNodeEntry(name); - if (cne != null) { - boolean incl = true; - for (String exclName : childFilter.getExclusionPatterns()) { - if (name.equals(exclName)) { - incl = false; - break; - } - } - if (incl) { - if (count-- <= 0) { - break; - } - builder.key(name).object(); - if (depth > 0) { - toJson(builder, rep.getRevisionStore().getNode(cne.getId()), depth - 1, 0, maxChildNodes, inclVirtualProps, filter); - } - builder.endObject(); - } - } - } - return; - } - } - - int count = maxChildNodes; - if (count != -1 - && filter != null - && filter.getChildNodeFilter() != null) { - // specific maxChildNodes limit and child node filter - count = -1; - } - int numSiblings = 0; - - for (Iterator it = node.getChildNodeEntries(offset, count); it.hasNext(); ) { - ChildNodeEntry cne = it.next(); - if (filter == null || filter.includeNode(cne.getName())) { - if (maxChildNodes != -1 && ++numSiblings > maxChildNodes) { - break; - } - builder.key(cne.getName()).object(); - if (depth > 0) { - toJson(builder, rep.getRevisionStore().getNode(cne.getId()), depth - 1, 0, maxChildNodes, inclVirtualProps, filter); - } - builder.endObject(); - } - } - } - } -} Index: oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreCacheTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreCacheTest.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreCacheTest.java (revision ) @@ -27,7 +27,7 @@ import org.apache.jackrabbit.mk.api.MicroKernel; import org.apache.jackrabbit.mk.api.MicroKernelException; -import org.apache.jackrabbit.mk.core.MicroKernelImpl; +import org.apache.jackrabbit.oak.plugins.document.DocumentMK.Builder; import org.apache.jackrabbit.oak.spi.commit.CommitInfo; import org.apache.jackrabbit.oak.spi.commit.EmptyHook; import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry; @@ -52,7 +52,7 @@ @Before public void setUp() throws Exception { - wrapper = new MicroKernelWrapper(new MicroKernelImpl()); + wrapper = new MicroKernelWrapper(new Builder().open()); store = new KernelNodeStore(wrapper); NodeBuilder builder = store.getRoot().builder(); Index: oak-run/src/main/java/org/apache/jackrabbit/oak/fixture/OakFixture.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-run/src/main/java/org/apache/jackrabbit/oak/fixture/OakFixture.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-run/src/main/java/org/apache/jackrabbit/oak/fixture/OakFixture.java (revision ) @@ -27,8 +27,6 @@ import org.apache.jackrabbit.core.data.DataStore; import org.apache.jackrabbit.core.data.DataStoreException; import org.apache.jackrabbit.core.data.FileDataStore; -import org.apache.jackrabbit.mk.api.MicroKernel; -import org.apache.jackrabbit.mk.core.MicroKernelImpl; import org.apache.jackrabbit.oak.Oak; import org.apache.jackrabbit.oak.commons.PropertiesUtil; import org.apache.jackrabbit.oak.kernel.KernelNodeStore; @@ -48,8 +46,6 @@ public abstract class OakFixture { public static final String OAK_MEMORY = "Oak-Memory"; - public static final String OAK_MEMORY_NS = "Oak-MemoryNS"; - public static final String OAK_MEMORY_MK = "Oak-MemoryMK"; public static final String OAK_MONGO = "Oak-Mongo"; public static final String OAK_MONGO_FDS = "Oak-Mongo-FDS"; @@ -58,7 +54,6 @@ public static final String OAK_RDB = "Oak-RDB"; - public static final String OAK_H2 = "Oak-H2"; public static final String OAK_TAR = "Oak-Tar"; public static final String OAK_TAR_FDS = "Oak-Tar-FDS"; @@ -85,28 +80,15 @@ } public static OakFixture getMemory(long cacheSize) { - return getMemory(OAK_MEMORY, false, cacheSize); + return getMemory(OAK_MEMORY, cacheSize); } - public static OakFixture getMemoryNS(long cacheSize) { - return getMemory(OAK_MEMORY_NS, false, cacheSize); - } - - public static OakFixture getMemoryMK(long cacheSize) { - return getMemory(OAK_MEMORY_MK, true, cacheSize); - } - - public static OakFixture getMemory(String name, final boolean useMk, final long cacheSize) { + public static OakFixture getMemory(String name, final long cacheSize) { return new OakFixture(name) { @Override public Oak getOak(int clusterId) throws Exception { Oak oak; - if (useMk) { - MicroKernel kernel = new MicroKernelImpl(); - oak = new Oak(new KernelNodeStore(kernel, cacheSize)); - } else { - oak = new Oak(new MemoryNodeStore()); + oak = new Oak(new MemoryNodeStore()); - } return oak; } @@ -115,12 +97,7 @@ Oak[] cluster = new Oak[n]; for (int i = 0; i < cluster.length; i++) { Oak oak; - if (useMk) { - MicroKernel kernel = new MicroKernelImpl(); - oak = new Oak(new KernelNodeStore(kernel, cacheSize)); - } else { - oak = new Oak(new MemoryNodeStore()); + oak = new Oak(new MemoryNodeStore()); - } cluster[i] = oak; } return cluster; @@ -423,34 +400,4 @@ }; } - - - public static OakFixture getH2MK(final File base, final long cacheSize) { - return new OakFixture(OAK_H2) { - private MicroKernelImpl[] kernels; - - @Override - public Oak getOak(int clusterId) throws Exception { - return new Oak(new KernelNodeStore(new MicroKernelImpl(base.getPath()), cacheSize)); - } - - @Override - public Oak[] setUpCluster(int n) throws Exception { - Oak[] cluster = new Oak[n]; - kernels = new MicroKernelImpl[cluster.length]; - for (int i = 0; i < cluster.length; i++) { - kernels[i] = new MicroKernelImpl(new File(base, unique).getPath()); - cluster[i] = new Oak(new KernelNodeStore(kernels[i], cacheSize)); - } - return cluster; - } - @Override - public void tearDownCluster() { - for (MicroKernelImpl kernel : kernels) { - kernel.dispose(); - } - FileUtils.deleteQuietly(new File(base, unique)); - } - }; - } } \ No newline at end of file Index: oak-mk/src/test/java/org/apache/jackrabbit/mk/ConcurrentWriteIT.java =================================================================== --- oak-mk/src/test/java/org/apache/jackrabbit/mk/ConcurrentWriteIT.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/test/java/org/apache/jackrabbit/mk/ConcurrentWriteIT.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,105 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk; - -import java.util.Random; - -import junit.framework.TestCase; -import org.apache.jackrabbit.mk.api.MicroKernel; -import org.apache.jackrabbit.mk.core.MicroKernelImpl; - -public class ConcurrentWriteIT extends TestCase { - - protected static final String TEST_PATH = "/" + ConcurrentWriteIT.class.getName(); - - private static final int NUM_THREADS = 20; - private static final int NUM_CHILDNODES = 1000; - - final MicroKernel mk = new MicroKernelImpl(); - - public void setUp() throws Exception { - mk.commit("/", "+ \"" + TEST_PATH.substring(1) + "\": {\"jcr:primaryType\":\"nt:unstructured\"}", null, null); - } - - public void tearDown() throws InterruptedException { - } - - /** - * Runs the test. - */ - public void testConcurrentWriting() throws Exception { - - String oldHead = mk.getHeadRevision(); - - TestThread[] threads = new TestThread[NUM_THREADS]; - for (int i = 0; i < threads.length; i++) { - TestThread thread = new TestThread(oldHead, "t" + i); - threads[i] = thread; - - assertFalse(mk.nodeExists(TEST_PATH + "/" + thread.getName(), null)); - } - - // long t0 = System.currentTimeMillis(); - - for (TestThread t : threads) { - if (t != null) { - t.start(); - } - } - - for (TestThread t : threads) { - if (t != null) { - t.join(); - } - } - - // long t1 = System.currentTimeMillis(); - // System.out.println("duration: " + (t1 - t0) + "ms"); - - for (Thread t : threads) { - assertTrue(mk.nodeExists(TEST_PATH + "/" + t.getName(), null)); - } - } - - class TestThread extends Thread { - String revId; - Random rand; - - TestThread(String revId, String name) { - super(name); - this.revId = revId; - rand = new Random(); - } - - public void run() { - StringBuilder sb = new StringBuilder(); - sb.append("+\""); - sb.append(getName()); - sb.append("\" : {\"jcr:primaryType\":\"nt:unstructured\",\n"); - for (int i = 0; i < NUM_CHILDNODES; i++) { - sb.append("\"sub" + i + "\" : {\"jcr:primaryType\":\"nt:unstructured\", \"prop\":\"" + rand.nextLong() + "\"}"); - if (i == NUM_CHILDNODES - 1) { - sb.append('\n'); - } else { - sb.append(",\n"); - } - } - sb.append('}'); - revId = mk.commit(TEST_PATH, sb.toString(), revId, null); - } - } -} Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/model/TraversingNodeDiffHandler.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/model/TraversingNodeDiffHandler.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/model/TraversingNodeDiffHandler.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.model; - -import org.apache.jackrabbit.mk.store.RevisionProvider; -import org.apache.jackrabbit.oak.commons.PathUtils; - -import java.util.Stack; - -/** - * - */ -public abstract class TraversingNodeDiffHandler implements NodeDiffHandler { - - protected Stack paths = new Stack(); - - protected final RevisionProvider rp; - - public TraversingNodeDiffHandler(RevisionProvider rp) { - this.rp = rp; - } - - public void start(Node before, Node after, String path) { - paths.clear(); - paths.push(path); - before.diff(after, this); - } - - protected String getCurrentPath() { - return paths.peek(); - } - - @Override - public void childNodeChanged(ChildNodeEntry changed, Id newId) { - paths.push(PathUtils.concat(getCurrentPath(), changed.getName())); - try { - rp.getNode(changed.getId()).diff(rp.getNode(newId), this); - } catch (Exception e) { - throw new RuntimeException(e); - } - paths.pop(); - } -} Index: oak-mk/src/test/java/org/apache/jackrabbit/mk/util/NameFilterTest.java =================================================================== --- oak-mk/src/test/java/org/apache/jackrabbit/mk/util/NameFilterTest.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/test/java/org/apache/jackrabbit/mk/util/NameFilterTest.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,91 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.util; - -import org.junit.Test; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -/** - * Tests the NameFilter utility class. - */ -public class NameFilterTest { - - @Test - public void test() { - NameFilter filter = new NameFilter(new String[]{"foo*", "-foo99"}); - assertTrue(filter.matches("foo1")); - assertTrue(filter.matches("foo*")); - assertTrue(filter.matches("foo bar")); - assertTrue(filter.matches("foo 99")); - assertFalse(filter.matches("foo99")); - assertTrue(filter.containsWildcard()); - - filter = new NameFilter(new String[]{"*foo"}); - assertTrue(filter.matches("foo")); - assertTrue(filter.matches("-123foo")); - assertFalse(filter.matches("bar")); - assertTrue(filter.containsWildcard()); - - filter = new NameFilter(new String[]{"foo\\*bar"}); - assertFalse(filter.matches("foo bar")); - assertTrue(filter.matches("foo*bar")); - assertFalse(filter.containsWildcard()); - - filter = new NameFilter(new String[]{"foo\\bar"}); - assertTrue(filter.matches("foo\\bar")); - assertFalse(filter.containsWildcard()); - - filter = new NameFilter(new String[]{"foo\\"}); - assertTrue(filter.matches("foo\\")); - assertFalse(filter.containsWildcard()); - - filter = new NameFilter(new String[]{"*"}); - assertTrue(filter.matches("*")); - assertTrue(filter.matches("\\*")); - assertTrue(filter.matches("blah")); - assertTrue(filter.containsWildcard()); - - filter = new NameFilter(new String[]{"\\*"}); - assertTrue(filter.matches("*")); - assertFalse(filter.matches("\\*")); - assertFalse(filter.matches("blah")); - assertFalse(filter.containsWildcard()); - - filter = new NameFilter(new String[]{"\\- topic"}); - assertTrue(filter.matches("- topic")); - assertFalse(filter.containsWildcard()); - - filter = new NameFilter(new String[]{"*", "- topic"}); - assertFalse(filter.matches(" topic")); - assertTrue(filter.matches("- topic")); - assertTrue(filter.matches("blah")); - assertTrue(filter.containsWildcard()); - - filter = new NameFilter(new String[]{"foo\\-bar"}); - assertFalse(filter.matches("foo-bar")); - assertTrue(filter.matches("foo\\-bar")); - assertFalse(filter.containsWildcard()); - - filter = new NameFilter(new String[]{"foo\\\\*bar"}); - assertTrue(filter.matches("foo\\*bar")); - assertFalse(filter.matches("foo\\ blah bar")); - assertFalse(filter.matches("foo*bar")); - assertFalse(filter.containsWildcard()); - } -} Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/util/CommitGate.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/util/CommitGate.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/util/CommitGate.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,75 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.util; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; - -/** - * A gate where listeners can wait for a new commit. - */ -public class CommitGate { - - private volatile String currentHead; - private volatile AtomicReference latchRef = new AtomicReference(); - - /** - * Wait for a new commit to occur. In very few cases, this method may return - * with the old head before the requested timeout. - * - * @param lastHead the last head - * @param millis the maximum number of milliseconds to wait (0 means don't wait) - * @return the new head (or old head, if no new commit occurred) - * @throws InterruptedException if the thread was interrupted - */ - public String waitForCommit(String lastHead, long millis) throws InterruptedException { - if (millis == 0 || (currentHead != null && !currentHead.equals(lastHead))) { - return currentHead; - } - CountDownLatch latch = latchRef.get(); - if (latch == null) { - latch = new CountDownLatch(1); - CountDownLatch old = latchRef.getAndSet(latch); - if (old != null) { - // may cause a spurious release, but that's ok - old.countDown(); - } - } - latch.await(millis, TimeUnit.MILLISECONDS); - return currentHead; - } - - /** - * Commit a new head. Waiting threads are awoken. - * - * @param newHead the new head - */ - public void commit(String newHead) { - currentHead = newHead; - CountDownLatch latch = latchRef.get(); - if (latch != null) { - // may cause a spurious release, but that's ok - latch.countDown(); - latch = latchRef.getAndSet(null); - if (latch != null) { - latch.countDown(); - } - } - } - -} Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/model/StoredCommit.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/model/StoredCommit.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/model/StoredCommit.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,58 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.model; - -import org.apache.jackrabbit.mk.store.Binding; - -/** - * - */ -public class StoredCommit extends AbstractCommit { - - private final Id id; - - public static StoredCommit deserialize(Id id, Binding binding) throws Exception { - Id rootNodeId = new Id(binding.readBytesValue("rootNodeId")); - long commitTS = binding.readLongValue("commitTS"); - String msg = binding.readStringValue("msg"); - String changes = binding.readStringValue("changes"); - String parentId = binding.readStringValue("parentId"); - String branchRootId = binding.readStringValue("branchRootId"); - return new StoredCommit(id, "".equals(parentId) ? null : Id.fromString(parentId), - commitTS, rootNodeId, "".equals(msg) ? null : msg, changes, - "".equals(branchRootId) ? null : Id.fromString(branchRootId)); - } - - public StoredCommit(Id id, Id parentId, long commitTS, Id rootNodeId, String msg, String changes, Id branchRootId) { - this.id = id; - this.parentId = parentId; - this.commitTS = commitTS; - this.rootNodeId = rootNodeId; - this.msg = msg; - this.changes = changes; - this.branchRootId = branchRootId; - } - - public StoredCommit(Id id, Commit commit) { - super(commit); - this.id = id; - } - - public Id getId() { - return id; - } -} Index: oak-mk/src/test/java/org/apache/jackrabbit/mk/store/DefaultRevisionStoreTest.java =================================================================== --- oak-mk/src/test/java/org/apache/jackrabbit/mk/store/DefaultRevisionStoreTest.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/test/java/org/apache/jackrabbit/mk/store/DefaultRevisionStoreTest.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,243 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.store; - -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import org.apache.jackrabbit.mk.core.MicroKernelImpl; -import org.apache.jackrabbit.mk.core.Repository; -import org.apache.jackrabbit.mk.model.Id; -import org.apache.jackrabbit.mk.model.StoredCommit; -import org.apache.jackrabbit.mk.persistence.GCPersistence; -import org.apache.jackrabbit.mk.persistence.InMemPersistence; -import org.apache.jackrabbit.mk.store.DefaultRevisionStore.PutTokenImpl; -import org.apache.jackrabbit.mk.store.RevisionStore.PutToken; -import org.apache.jackrabbit.oak.spi.blob.MemoryBlobStore; -import org.json.simple.JSONArray; -import org.json.simple.parser.JSONParser; -import org.junit.After; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -/** - * Tests verifying the inner workings of DefaultRevisionStore. - */ -public class DefaultRevisionStoreTest { - - /* avoid synthetic accessor */ DefaultRevisionStore rs; - private MicroKernelImpl mk; - - @Before - public void setup() throws Exception { - rs = new DefaultRevisionStore(createPersistence()) { - @Override - protected Id markCommits() throws Exception { - // Keep head commit only - StoredCommit commit = getHeadCommit(); - markCommit(commit); - return commit.getId(); - } - }; - rs.initialize(); - - mk = new MicroKernelImpl(new Repository(rs, new MemoryBlobStore())); - } - - protected GCPersistence createPersistence() throws Exception { - return new InMemPersistence(); - } - - @After - public void tearDown() throws Exception { - if (mk != null) { - mk.dispose(); - } - } - - /** - * Verify revision history works with garbage collection. - * - * @throws Exception if an error occurs - */ - @Test - public void testRevisionHistory() { - mk.commit("/", "+\"a\" : { \"c\":{ \"d\":{} }}", mk.getHeadRevision(), null); - mk.commit("/", "+\"b\" : {}", mk.getHeadRevision(), null); - mk.commit("/b", "+\"e\" : {}", mk.getHeadRevision(), null); - mk.commit("/a/c", "+\"f\" : {}", mk.getHeadRevision(), null); - - String headRevision = mk.getHeadRevision(); - String contents = mk.getNodes("/", headRevision, 1, 0, -1, null); - - rs.gc(); - - assertEquals(headRevision, mk.getHeadRevision()); - assertEquals(contents, mk.getNodes("/", headRevision, 1, 0, -1, null)); - - String history = mk.getRevisionHistory(Long.MIN_VALUE, Integer.MIN_VALUE, null); - assertEquals(1, parseJSONArray(history).size()); - } - - /** - * Verify branch and merge works with garbage collection. - * - * @throws Exception if an error occurs - */ - @Test - public void testBranchMerge() throws Exception { - mk.commit("/", "+\"a\" : { \"b\":{}, \"c\":{} }", mk.getHeadRevision(), null); - String branchRevisionId = mk.branch(mk.getHeadRevision()); - - mk.commit("/a", "+\"d\" : {}", mk.getHeadRevision(), null); - branchRevisionId = mk.commit("/a", "+\"e\" : {}", branchRevisionId, null); - - rs.gc(); - - branchRevisionId = mk.commit("/a", "+\"f\" : {}", branchRevisionId, null); - mk.merge(branchRevisionId, null); - - rs.gc(); - - String history = mk.getRevisionHistory(Long.MIN_VALUE, Integer.MIN_VALUE, null); - assertEquals(1, parseJSONArray(history).size()); - } - - /** - * Verify garbage collection can run concurrently with commits. - * - * @throws Exception if an error occurs - */ - @Test - @Ignore - public void testConcurrentGC() throws Exception { - ScheduledExecutorService gcExecutor = Executors.newScheduledThreadPool(1); - gcExecutor.scheduleWithFixedDelay(new Runnable() { - @Override - public void run() { - rs.gc(); - } - }, 10, 2, TimeUnit.MILLISECONDS); - - mk.commit("/", "+\"a\" : { \"b\" : { \"c\" : { \"d\" : {} } } }", - mk.getHeadRevision(), null); - - try { - for (int i = 0; i < 2000; i++) { - mk.commit("/a/b/c/d", "+\"e\" : {}", mk.getHeadRevision(), null); - Thread.sleep(1); - mk.commit("/a/b/c/d/e", "+\"f\" : {}", mk.getHeadRevision(), null); - Thread.sleep(3); - mk.commit("/a/b/c/d", "-\"e\"", mk.getHeadRevision(), null); - } - } finally { - gcExecutor.shutdown(); - } - } - - /** - * Verify garbage collection can run concurrently with branch & merge. - * - * @throws Exception if an error occurs - */ - @Test - @Ignore - public void testConcurrentMergeGC() throws Exception { - ScheduledExecutorService gcExecutor = Executors.newScheduledThreadPool(1); - gcExecutor.scheduleWithFixedDelay(new Runnable() { - @Override - public void run() { - rs.gc(); - } - }, 100, 20, TimeUnit.MILLISECONDS); - - mk.commit("/", "+\"a\" : { \"b\" : { \"c\" : { \"d\" : {} } } }", - mk.getHeadRevision(), null); - - try { - for (int i = 0; i < 20; i++) { - String branchId = mk.branch(mk.getHeadRevision()); - if ((i & 1) == 0) { - /* add some data in even runs */ - branchId = mk.commit("/a/b/c/d", "+\"e\" : {}", branchId, null); - Thread.sleep(10); - branchId = mk.commit("/a/b/c/d/e", "+\"f\" : {}", branchId, null); - } else { - /* remove added data in odd runs */ - branchId = mk.commit("/a/b/c/d", "-\"e\"", branchId, null); - } - Thread.sleep(30); - mk.merge(branchId, null); - } - } finally { - gcExecutor.shutdown(); - } - } - - @Test - public void putTokenImpl() throws InterruptedException, ExecutionException { - final Set tokens = Collections.synchronizedSet(new HashSet()); - Set> results = new HashSet>(); - - ExecutorService executorService = Executors.newFixedThreadPool(100); - for (int i = 0; i < 100; i++) { - results.add(executorService.submit(new Callable() { - @Override - public Void call() throws Exception { - for (int j = 0; j < 10000; j++) { - assertTrue(tokens.add(new PutTokenImpl())); - } - return null; - } - })); - } - - for (Future result : results) { - result.get(); - } - } - - /** - * Parses the provided string into a {@code JSONArray}. - * - * @param json string to be parsed - * @return a {@code JSONArray} - * @throws {@code AssertionError} if the string cannot be parsed into a {@code JSONArray} - */ - private JSONArray parseJSONArray(String json) throws AssertionError { - JSONParser parser = new JSONParser(); - try { - Object obj = parser.parse(json); - assertTrue(obj instanceof JSONArray); - return (JSONArray) obj; - } catch (Exception e) { - throw new AssertionError("not a valid JSON array: " + e.getMessage()); - } - } -} Index: oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/SameNamePropertyNodeTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/SameNamePropertyNodeTest.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/SameNamePropertyNodeTest.java (revision ) @@ -22,8 +22,6 @@ import javax.jcr.Repository; import org.apache.jackrabbit.api.JackrabbitRepository; -import org.apache.jackrabbit.mk.core.MicroKernelImpl; -import org.apache.jackrabbit.oak.kernel.KernelNodeStore; import org.apache.jackrabbit.oak.spi.state.NodeStore; import org.apache.jackrabbit.test.AbstractJCRTest; import org.apache.jackrabbit.test.NotExecutableException; @@ -118,7 +116,7 @@ */ @Test public void testMicroKernelSupport() throws Exception { - NodeStore nodeStore = new KernelNodeStore(new MicroKernelImpl()); + NodeStore nodeStore = NodeStoreFixture.DOCUMENT_MK.createNodeStore(); JackrabbitRepository repository = (JackrabbitRepository) new Jcr(nodeStore).createRepository(); try { assertFalse(repository.getDescriptorValue(Repository.OPTION_NODE_AND_PROPERTY_WITH_SAME_NAME_SUPPORTED).getBoolean()); \ No newline at end of file Index: oak-jcr/pom.xml IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-jcr/pom.xml (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-jcr/pom.xml (revision ) @@ -337,12 +337,6 @@ test - org.apache.jackrabbit - oak-mk - ${project.version} - test - - com.googlecode.json-simple json-simple 1.1.1 Index: oak-run/README.md IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-run/README.md (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-run/README.md (revision ) @@ -138,8 +138,6 @@ |---------------|-------------------------------------------------------| | Jackrabbit | Jackrabbit with the default embedded Derby bundle PM | | Oak-Memory | Oak with default in-memory storage | -| Oak-MemoryNS | Oak with default in-memory NodeStore | -| Oak-MemoryMK | Oak with default in-memory MicroKernel | | Oak-Mongo | Oak with the default Mongo backend | | Oak-Mongo-FDS | Oak with the default Mongo backend and FileDataStore | | Oak-MongoNS | Oak with the Mongo NodeStore | @@ -244,8 +242,6 @@ |---------------|-------------------------------------------------------| | Jackrabbit | Jackrabbit with the default embedded Derby bundle PM | | Oak-Memory | Oak with default in-memory storage | -| Oak-MemoryNS | Oak with default in-memory NodeStore | -| Oak-MemoryMK | Oak with default in-memory MicroKernel | | Oak-Mongo | Oak with the default Mongo backend | | Oak-Mongo-FDS | Oak with the default Mongo backend and FileDataStore | | Oak-MongoNS | Oak with the Mongo NodeStore | Index: oak-run/src/main/java/org/apache/jackrabbit/oak/scalability/ScalabilityRunner.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-run/src/main/java/org/apache/jackrabbit/oak/scalability/ScalabilityRunner.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-run/src/main/java/org/apache/jackrabbit/oak/scalability/ScalabilityRunner.java (revision ) @@ -18,16 +18,21 @@ */ package org.apache.jackrabbit.oak.scalability; +import static java.util.Arrays.asList; + import java.io.File; import java.io.PrintStream; import java.util.List; import java.util.Map; import java.util.Set; +import com.google.common.base.Splitter; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import joptsimple.OptionParser; import joptsimple.OptionSet; import joptsimple.OptionSpec; - import org.apache.commons.io.FileUtils; import org.apache.jackrabbit.oak.benchmark.CSVResultGenerator; import org.apache.jackrabbit.oak.benchmark.util.Date; @@ -35,13 +40,6 @@ import org.apache.jackrabbit.oak.fixture.OakRepositoryFixture; import org.apache.jackrabbit.oak.fixture.RepositoryFixture; -import com.google.common.base.Splitter; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; - -import static java.util.Arrays.asList; - /** * Main class for running scalability/longevity tests. * @@ -95,9 +93,6 @@ RepositoryFixture[] allFixtures = new RepositoryFixture[] { new JackrabbitRepositoryFixture(base.value(options), cacheSize), OakRepositoryFixture.getMemory(cacheSize * MB), - OakRepositoryFixture.getMemoryNS(cacheSize * MB), - OakRepositoryFixture.getMemoryMK(cacheSize * MB), - OakRepositoryFixture.getH2MK(base.value(options), cacheSize * MB), OakRepositoryFixture.getMongo( host.value(options), port.value(options), dbName.value(options), dropDBAfterTest.value(options), Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/model/MutableNode.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/model/MutableNode.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/model/MutableNode.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,74 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.model; - -import org.apache.jackrabbit.mk.store.PersistHook; -import org.apache.jackrabbit.mk.store.RevisionProvider; -import org.apache.jackrabbit.mk.store.RevisionStore; - -import java.util.Iterator; - -/** - * - */ -public class MutableNode extends AbstractNode implements PersistHook { - - public MutableNode(RevisionProvider provider) { - super(provider); - } - - public MutableNode(Node other, RevisionProvider provider) { - super(other, provider); - } - - public ChildNodeEntry add(ChildNodeEntry newEntry) { - ChildNodeEntry existing = childEntries.add(newEntry); - if (childEntries.getCount() > ChildNodeEntries.CAPACITY_THRESHOLD - && childEntries.inlined()) { - ChildNodeEntries entries = new ChildNodeEntriesTree(provider); - Iterator iter = childEntries.getEntries(0, -1); - while (iter.hasNext()) { - entries.add(iter.next()); - } - childEntries = entries; - } - return existing; - } - - public ChildNodeEntry remove(String name) { - return childEntries.remove(name); - } - - public ChildNodeEntry rename(String oldName, String newName) { - return childEntries.rename(oldName, newName); - } - - //----------------------------------------------------------< PersistHook > - - @Override - public void prePersist(RevisionStore store, RevisionStore.PutToken token) throws Exception { - if (!childEntries.inlined()) { - // persist dirty buckets - ((ChildNodeEntriesTree) childEntries).persistDirtyBuckets(store, token); - } - } - - @Override - public void postPersist(RevisionStore store, RevisionStore.PutToken token) throws Exception { - // there's nothing to do - } -} Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/core/package-info.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/core/package-info.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/core/package-info.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,22 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -@Version("1.0") -@Export(optional = "provide:=true") -package org.apache.jackrabbit.mk.core; - -import aQute.bnd.annotation.Version; -import aQute.bnd.annotation.Export; \ No newline at end of file Index: oak-it/mk/pom.xml IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-it/mk/pom.xml (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-it/mk/pom.xml (revision ) @@ -70,11 +70,6 @@ org.apache.jackrabbit - oak-mk - ${project.version} - - - org.apache.jackrabbit oak-core ${project.version} Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/model/ChildNodeEntriesMap.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/model/ChildNodeEntriesMap.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/model/ChildNodeEntriesMap.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,233 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.model; - -import org.apache.jackrabbit.mk.store.Binding; -import org.apache.jackrabbit.mk.store.CacheObject; -import org.apache.jackrabbit.mk.util.AbstractFilteringIterator; -import org.apache.jackrabbit.mk.util.RangeIterator; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -/** - * - */ -public class ChildNodeEntriesMap implements ChildNodeEntries, CacheObject { - - protected static final List EMPTY = Collections.emptyList(); - - protected HashMap entries = new HashMap(); - - public ChildNodeEntriesMap() { - } - - public ChildNodeEntriesMap(ChildNodeEntriesMap other) { - entries = (HashMap) other.entries.clone(); - } - - //------------------------------------------------------------< overrides > - - @Override - public boolean equals(Object obj) { - if (obj instanceof ChildNodeEntriesMap) { - return entries.equals(((ChildNodeEntriesMap) obj).entries); - } - return false; - } - - @Override - public Object clone() { - ChildNodeEntriesMap clone = null; - try { - clone = (ChildNodeEntriesMap) super.clone(); - } catch (CloneNotSupportedException e) { - // can't possibly get here - } - clone.entries = (HashMap) entries.clone(); - return clone; - } - - @Override - public boolean inlined() { - return true; - } - - //-------------------------------------------------------------< read ops > - - @Override - public int getCount() { - return entries.size(); - } - - @Override - public ChildNodeEntry get(String name) { - return entries.get(name); - } - - @Override - public Iterator getNames(int offset, int count) { - if (offset < 0 || count < -1) { - throw new IllegalArgumentException(); - } - - if (offset == 0 && count == -1) { - return entries.keySet().iterator(); - } else { - if (offset >= entries.size() || count == 0) { - List empty = Collections.emptyList(); - return empty.iterator(); - } - if (count == -1 || (offset + count) > entries.size()) { - count = entries.size() - offset; - } - return new RangeIterator(entries.keySet().iterator(), offset, count); - } - } - - @Override - public Iterator getEntries(int offset, int count) { - if (offset < 0 || count < -1) { - throw new IllegalArgumentException(); - } - if (offset == 0 && count == -1) { - return entries.values().iterator(); - } else { - if (offset >= entries.size() || count == 0) { - return EMPTY.iterator(); - } - if (count == -1 || (offset + count) > entries.size()) { - count = entries.size() - offset; - } - return new RangeIterator(entries.values().iterator(), offset, count); - } - } - - //------------------------------------------------------------< write ops > - - @Override - public ChildNodeEntry add(ChildNodeEntry entry) { - return entries.put(entry.getName(), entry); - } - - @Override - public ChildNodeEntry remove(String name) { - return entries.remove(name); - } - - @Override - public ChildNodeEntry rename(String oldName, String newName) { - if (oldName.equals(newName)) { - return entries.get(oldName); - } - if (entries.get(oldName) == null) { - return null; - } - HashMap clone = - (HashMap) entries.clone(); - entries.clear(); - ChildNodeEntry oldCNE = null; - for (Map.Entry entry : clone.entrySet()) { - if (entry.getKey().equals(oldName)) { - oldCNE = entry.getValue(); - entries.put(newName, new ChildNodeEntry(newName, oldCNE.getId())); - } else { - entries.put(entry.getKey(), entry.getValue()); - } - } - return oldCNE; - } - - //-------------------------------------------------------------< diff ops > - - @Override - public Iterator getAdded(final ChildNodeEntries other) { - return new AbstractFilteringIterator(other.getEntries(0, -1)) { - @Override - protected boolean include(ChildNodeEntry entry) { - return !entries.containsKey(entry.getName()); - } - }; - } - - @Override - public Iterator getRemoved(final ChildNodeEntries other) { - return new AbstractFilteringIterator(entries.values().iterator()) { - @Override - protected boolean include(ChildNodeEntry entry) { - return other.get(entry.getName()) == null; - } - }; - } - - @Override - public Iterator getModified(final ChildNodeEntries other) { - return new AbstractFilteringIterator(getEntries(0, -1)) { - @Override - protected boolean include(ChildNodeEntry entry) { - ChildNodeEntry namesake = other.get(entry.getName()); - return (namesake != null && !namesake.getId().equals(entry.getId())); - } - }; - } - - //------------------------------------------------< serialization support > - - @Override - public void serialize(Binding binding) throws Exception { - final Iterator iter = getEntries(0, -1); - binding.writeMap(":children", getCount(), - new Binding.BytesEntryIterator() { - @Override - public boolean hasNext() { - return iter.hasNext(); - } - @Override - public Binding.BytesEntry next() { - ChildNodeEntry cne = iter.next(); - return new Binding.BytesEntry(cne.getName(), cne.getId().getBytes()); - } - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - }); - } - - public static ChildNodeEntriesMap deserialize(Binding binding) throws Exception { - ChildNodeEntriesMap newInstance = new ChildNodeEntriesMap(); - Binding.BytesEntryIterator iter = binding.readBytesMap(":children"); - while (iter.hasNext()) { - Binding.BytesEntry entry = iter.next(); - newInstance.add(new ChildNodeEntry(entry.getKey(), new Id(entry.getValue()))); - } - return newInstance; - } - - @Override - public int getMemory() { - int memory = 100; - for (String e : entries.keySet()) { - memory += e.length() * 2 + 100; - } - return memory; - } - -} Index: oak-mk-remote/pom.xml IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-mk-remote/pom.xml (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk-remote/pom.xml (revision ) @@ -74,14 +74,7 @@ org.apache.felix.scr.annotations provided - + - - - org.apache.jackrabbit - oak-mk - ${project.version} - - org.apache.jackrabbit Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/osgi/MicroKernelService.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/osgi/MicroKernelService.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/osgi/MicroKernelService.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.osgi; - -import org.apache.felix.scr.annotations.Activate; -import org.apache.felix.scr.annotations.Component; -import org.apache.felix.scr.annotations.ConfigurationPolicy; -import org.apache.felix.scr.annotations.Deactivate; -import org.apache.felix.scr.annotations.Property; -import org.apache.felix.scr.annotations.Service; -import org.apache.jackrabbit.mk.api.MicroKernel; -import org.apache.jackrabbit.mk.core.MicroKernelImpl; -import org.osgi.service.component.ComponentContext; - -@Component(policy = ConfigurationPolicy.REQUIRE) -@Service(MicroKernel.class) -public class MicroKernelService extends MicroKernelImpl { - - @Property(description="The unique name of this instance") - public static final String NAME = "name"; - - @Property(description="The home directory (in-memory if not set)") - public static final String HOME_DIR = "repository.home"; - - private String name; - - @Override - public String toString() { - return name; - } - - @Activate - public void activate(ComponentContext context) { - name = "" + context.getProperties().get(NAME); - String homeDir = readDirectory(context); - if (homeDir != null) { - init(homeDir); - } - } - - private static String readDirectory(ComponentContext context) { - if (context.getProperties().get(HOME_DIR) != null) { - return context.getProperties().get(HOME_DIR).toString(); - } - if (context.getBundleContext().getProperty(HOME_DIR) != null) { - return context.getBundleContext().getProperty(HOME_DIR).toString(); - } - return null; - } - - @Deactivate - public void deactivate() { - dispose(); - } - -} Index: oak-it/osgi/test-bundles.xml IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-it/osgi/test-bundles.xml (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-it/osgi/test-bundles.xml (revision ) @@ -36,7 +36,6 @@ org.apache.jackrabbit:jackrabbit-jcr-commons org.apache.jackrabbit:oak-commons org.apache.jackrabbit:oak-mk-api - org.apache.jackrabbit:oak-mk org.apache.jackrabbit:oak-mk-remote org.apache.jackrabbit:oak-core org.apache.jackrabbit:oak-jcr Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/store/CacheObject.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/store/CacheObject.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/store/CacheObject.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,31 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.store; - -/** - * An entry that can be put in a cache. - */ -public interface CacheObject { - - /** - * The estimated amount of memory used, in bytes. - * - * @return the memory used - */ - int getMemory(); - -} Index: oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/BenchmarkRunner.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/BenchmarkRunner.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/BenchmarkRunner.java (revision ) @@ -16,6 +16,8 @@ */ package org.apache.jackrabbit.oak.benchmark; +import static java.util.Arrays.asList; + import java.io.File; import java.io.PrintStream; import java.util.ArrayList; @@ -26,19 +28,15 @@ import com.google.common.collect.Lists; import com.google.common.collect.Sets; - import joptsimple.OptionParser; import joptsimple.OptionSet; import joptsimple.OptionSpec; - import org.apache.commons.io.FileUtils; import org.apache.jackrabbit.oak.benchmark.wikipedia.WikipediaImport; import org.apache.jackrabbit.oak.fixture.JackrabbitRepositoryFixture; import org.apache.jackrabbit.oak.fixture.OakRepositoryFixture; import org.apache.jackrabbit.oak.fixture.RepositoryFixture; -import static java.util.Arrays.asList; - public class BenchmarkRunner { private static final int MB = 1024 * 1024; @@ -112,9 +110,6 @@ RepositoryFixture[] allFixtures = new RepositoryFixture[] { new JackrabbitRepositoryFixture(base.value(options), cacheSize), OakRepositoryFixture.getMemory(cacheSize * MB), - OakRepositoryFixture.getMemoryNS(cacheSize * MB), - OakRepositoryFixture.getMemoryMK(cacheSize * MB), - OakRepositoryFixture.getH2MK(base.value(options), cacheSize * MB), OakRepositoryFixture.getMongo( host.value(options), port.value(options), dbName.value(options), dropDBAfterTest.value(options), Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/model/NodeDiffHandler.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/model/NodeDiffHandler.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/model/NodeDiffHandler.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.model; - -/** - * - */ -public interface NodeDiffHandler { - - void propAdded(String propName, String value); - - void propChanged(String propName, String oldValue, String newValue); - - void propDeleted(String propName, String value); - - void childNodeAdded(ChildNodeEntry added); - - void childNodeDeleted(ChildNodeEntry deleted); - - void childNodeChanged(ChildNodeEntry changed, Id newId); -} Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/util/package-info.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/util/package-info.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/util/package-info.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,26 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -@Version("1.0") -@Export(optional = "provide:=true") -package org.apache.jackrabbit.mk.util; - -import aQute.bnd.annotation.Export; -import aQute.bnd.annotation.Version; - Index: README.md IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- README.md (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ README.md (revision ) @@ -51,7 +51,6 @@ - oak-doc - Oak documentation - oak-commons - shared utility code - oak-mk-api - MicroKernel API - - oak-mk - default MicroKernel implementation - oak-mk-remote - MicroKernel remoting - [oak-core][1] - Oak repository API and implementation - oak-jcr - JCR binding for the Oak repository Index: oak-mk/src/test/java/org/apache/jackrabbit/mk/concurrent/ConcurrentTest.java =================================================================== --- oak-mk/src/test/java/org/apache/jackrabbit/mk/concurrent/ConcurrentTest.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/test/java/org/apache/jackrabbit/mk/concurrent/ConcurrentTest.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,113 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with this - * work for additional information regarding copyright ownership. The ASF - * licenses this file to You under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.apache.jackrabbit.mk.concurrent; - -import java.util.concurrent.atomic.AtomicInteger; - -import junit.framework.Assert; -import org.apache.jackrabbit.mk.api.MicroKernel; -import org.apache.jackrabbit.mk.api.MicroKernelException; -import org.apache.jackrabbit.mk.core.MicroKernelImpl; -import org.apache.jackrabbit.oak.commons.concurrent.Concurrent; -import org.junit.Ignore; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; - -/** - * Test concurrent access to nodes, the journal, and revision. - */ -public class ConcurrentTest { - - final MicroKernel mk = new MicroKernelImpl(); - - @Test - public void test() throws Exception { - final AtomicInteger id = new AtomicInteger(); - Concurrent.run("MicroKernel", new Concurrent.Task() { - @Override - public void call() throws Exception { - long start = System.currentTimeMillis(); - String rev = mk.getHeadRevision(); - int i = id.getAndIncrement(); - String newRev = mk.commit("/", "+\"" + i + "\":{\"x\": " + i + "}", rev, ""); - Assert.assertTrue(!newRev.equals(rev)); - mk.getJournal(rev, newRev, null); - mk.getRevisionHistory(start, 100, null); - mk.getNodes("/" + i, newRev, 1, 0, -1, null); - mk.getNodes("/" + i, newRev, 0, 0, 0, null); - Assert.assertFalse(mk.nodeExists("/" + i, rev)); - Assert.assertTrue(mk.nodeExists("/" + i, newRev)); - rev = newRev; - newRev = mk.commit("/", "-\"" + i + "\"", rev, ""); - Assert.assertTrue(mk.nodeExists("/" + i, rev)); - Assert.assertFalse(mk.nodeExists("/" + i, newRev)); - } - }); - } - - @Test - @Ignore("OAK-532") // FIXME OAK-532 - public void journalConsistency() throws Exception { - while (true) { - final MicroKernel mk1 = new MicroKernelImpl(); - final String rev = mk1.commit("", "+\"/a\":{}", null, null); - - Thread t1 = new Thread("t1") { - @Override - public void run() { - try { - String r2 = mk1.commit("", "-\"/a\"+\"/c\":{}", rev, null); - } - catch (MicroKernelException ignore) { } - } - }; - Thread t2 = new Thread("t2") { - @Override - public void run() { - try { - String r2 = mk1.commit("", "-\"/a\"+\"/b\":{}", rev, null); - } - catch (MicroKernelException ignore) { } - } - }; - - t1.start(); - t2.start(); - - t1.join(); - t2.join(); - - String journal = mk1.getJournal(rev, null, null); - int c = count("-\\\"/a\\", journal); - assertEquals(1, c); - } - } - - private static int count(String subStr, String str) { - int lastIndex = 0; - int count =0; - - while(lastIndex != -1){ - lastIndex = str.indexOf(subStr, lastIndex); - - if( lastIndex != -1) { - count ++; - lastIndex += subStr.length(); - } - } - return count; - } - -} Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/model/StagedNodeTree.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/model/StagedNodeTree.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/model/StagedNodeTree.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,810 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.model; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import org.apache.jackrabbit.mk.api.MicroKernel; -import org.apache.jackrabbit.oak.commons.json.JsonObject; -import org.apache.jackrabbit.mk.store.NotFoundException; -import org.apache.jackrabbit.mk.store.RevisionStore; -import org.apache.jackrabbit.mk.store.RevisionStore.PutToken; -import org.apache.jackrabbit.oak.commons.PathUtils; - -/** - * A {@code StagedNodeTree} provides methods to manipulate a specific revision - * of the tree. The changes are recorded and can be persisted by calling - * {@link #persist(RevisionStore.PutToken)}. - */ -public class StagedNodeTree { - - private final RevisionStore store; - - private StagedNode root; - private Id baseRevisionId; - - /** - * Creates a new {@code StagedNodeTree} instance. - * - * @param store revision store used to read from and persist changes - * @param baseRevisionId id of revision the changes should be based upon - */ - public StagedNodeTree(RevisionStore store, Id baseRevisionId) { - this.store = store; - this.baseRevisionId = baseRevisionId; - } - - /** - * Discards all staged changes and resets the base revision to the - * specified new revision id. - * - * @param newBaseRevisionId id of revision the changes should be based upon - */ - public void reset(Id newBaseRevisionId) { - root = null; - baseRevisionId = newBaseRevisionId; - } - - /** - * Returns {@code true} if there are no staged changes, otherwise returns {@code false}. - * - * @return {@code true} if there are no staged changes, otherwise returns {@code false}. - */ - public boolean isEmpty() { - return root == null; - } - - /** - * Persists the staged nodes and returns the {@code Id} of the new root node. - * - * @param token - * @return {@code Id} of new root node or {@code null} if there are no changes to persist. - * @throws Exception if an error occurs - */ - public Id /* new id of root node */ persist(RevisionStore.PutToken token) throws Exception { - return root != null ? root.persist(token) : null; - } - - public Id rebase(Id baseId, Id fromId, Id toId, PutToken token) throws Exception { - // reset staging area to new base revision - reset(baseId); - - StoredNode baseRoot = store.getRootNode(baseId); - StoredNode fromRoot = store.getRootNode(fromId); - StoredNode toRoot = store.getRootNode(toId); - - // recursively apply changes from 'fromRoot' to 'toRoot' onto 'baseRoot' - rebaseNode(baseRoot, fromRoot, toRoot, "/"); - - // persist staged nodes - return persist(token); - } - - /** - * Performs a three-way merge merging our tree (rooted at {@code ourRoot}) - * and their tree (identified by {@code newBaseRevisionId}), - * using the common ancestor revision {@code commonAncestorRevisionId} as - * base reference. - *

- * This instance will be initially reset to {@code newBaseRevisionId}, discarding - * all currently staged changes. - * - * @param ourRoot - * @param newBaseRevisionId - * @param commonAncestorRevisionId - * @param token - * @return {@code Id} of new root node - * @throws Exception - */ - public Id merge(StoredNode ourRoot, - Id newBaseRevisionId, - Id commonAncestorRevisionId, - RevisionStore.PutToken token) throws Exception { - // reset staging area to new base revision - reset(newBaseRevisionId); - - StoredNode baseRoot = store.getRootNode(commonAncestorRevisionId); - StoredNode theirRoot = store.getRootNode(newBaseRevisionId); - - // recursively merge 'our' changes with 'their' changes... - mergeNode(baseRoot, ourRoot, theirRoot, "/"); - - // persist staged nodes - return persist(token); - } - - //-----------------------------------------< tree manipulation operations > - - /** - * Creates a new node named {@code nodeName} at {@code parentNodePath}. - * - * @param parentNodePath parent node path - * @param nodeName name of new node - * @param nodeData {@code JsonObject} representation of the node to be added - * @throws NotFoundException if there's no node at {@code parentNodePath} - * @throws Exception if a node named {@code nodeName} already exists at {@code parentNodePath} - * or if another error occurs - */ - public void add(String parentNodePath, String nodeName, JsonObject nodeData) throws Exception { - if (nodeName.isEmpty()) { - throw new Exception("cannot add a node with an empty name"); - } - StagedNode parent = getStagedNode(parentNodePath, true); - if (parent.getChildNodeEntry(nodeName) != null) { - throw new Exception("there's already a child node with name '" + nodeName + "'"); - } - parent.add(nodeName, nodeData); - } - - /** - * Removes the node at {@code nodePath}. - * - * @param nodePath node path - * @throws Exception - */ - public void remove(String nodePath) throws Exception { - String parentPath = PathUtils.getParentPath(nodePath); - String nodeName = PathUtils.getName(nodePath); - - StagedNode parent = getStagedNode(parentPath, true); - if (parent.remove(nodeName) == null) { - throw new NotFoundException(nodePath); - } - - // discard any staged changes at nodePath - unstageNode(nodePath); - } - - /** - * Creates or updates the property named {@code propName} of the specified node. - *

- * if {@code propValue == null} the specified property will be removed. - * - * @param nodePath node path - * @param propName property name - * @param propValue property value - * @throws NotFoundException if there's no node at {@code nodePath} - * @throws Exception if another error occurs - */ - public void setProperty(String nodePath, String propName, String propValue) throws Exception { - if (propName.isEmpty()) { - throw new Exception("cannot set a property with an empty name"); - } - StagedNode node = getStagedNode(nodePath, true); - - Map properties = node.getProperties(); - if (propValue == null) { - properties.remove(propName); - } else { - properties.put(propName, propValue); - } - } - - /** - * Moves the subtree rooted at {@code srcPath} to {@code destPath}. - * - * @param srcPath path of node to be moved - * @param destPath destination path - * @throws NotFoundException if either the node at {@code srcPath} or the parent - * node of {@code destPath} doesn't exist - * @throws Exception if a node already exists at {@code destPath}, - * if {@code srcPath} denotes an ancestor of {@code destPath} - * or if another error occurs - */ - public void move(String srcPath, String destPath) throws Exception { - if (PathUtils.isAncestor(srcPath, destPath)) { - throw new Exception("target path cannot be descendant of source path: " + destPath); - } - - String srcParentPath = PathUtils.getParentPath(srcPath); - String srcNodeName = PathUtils.getName(srcPath); - - String destParentPath = PathUtils.getParentPath(destPath); - String destNodeName = PathUtils.getName(destPath); - - StagedNode srcParent = getStagedNode(srcParentPath, true); - if (srcParent.getChildNodeEntry(srcNodeName) == null) { - throw new NotFoundException(srcPath); - } - StagedNode destParent = getStagedNode(destParentPath, true); - if (destParent.getChildNodeEntry(destNodeName) != null) { - throw new Exception("node already exists at move destination path: " + destPath); - } - - if (srcParentPath.equals(destParentPath)) { - // rename - srcParent.rename(srcNodeName, destNodeName); - } else { - // move - srcParent.move(srcNodeName, destPath); - } - } - - /** - * Copies the subtree rooted at {@code srcPath} to {@code destPath}. - * - * @param srcPath path of node to be copied - * @param destPath destination path - * @throws NotFoundException if either the node at {@code srcPath} or the parent - * node of {@code destPath} doesn't exist - * @throws Exception if a node already exists at {@code destPath} - * or if another error occurs - */ - public void copy(String srcPath, String destPath) throws Exception { - String srcParentPath = PathUtils.getParentPath(srcPath); - String srcNodeName = PathUtils.getName(srcPath); - - String destParentPath = PathUtils.getParentPath(destPath); - String destNodeName = PathUtils.getName(destPath); - - StagedNode srcParent = getStagedNode(srcParentPath, false); - if (srcParent == null) { - // the subtree to be copied has not been modified - ChildNodeEntry entry = getStoredNode(srcParentPath).getChildNodeEntry(srcNodeName); - if (entry == null) { - throw new NotFoundException(srcPath); - } - StagedNode destParent = getStagedNode(destParentPath, true); - if (destParent.getChildNodeEntry(destNodeName) != null) { - throw new Exception("node already exists at copy destination path: " + destPath); - } - destParent.add(new ChildNodeEntry(destNodeName, entry.getId())); - return; - } - - ChildNodeEntry srcEntry = srcParent.getChildNodeEntry(srcNodeName); - if (srcEntry == null) { - throw new NotFoundException(srcPath); - } - - StagedNode destParent = getStagedNode(destParentPath, true); - StagedNode srcNode = getStagedNode(srcPath, false); - if (srcNode != null) { - // copy the modified subtree - destParent.add(destNodeName, srcNode.copy()); - } else { - destParent.add(new ChildNodeEntry(destNodeName, srcEntry.getId())); - } - } - - //-------------------------------------------------------< implementation > - - /** - * Returns a {@code StagedNode} representation of the specified node. - * If a {@code StagedNode} representation doesn't exist yet a new - * {@code StagedNode} instance will be returned if {@code createIfNotStaged == true}, - * otherwise {@code null} will be returned. - *

- * A {@code NotFoundException} will be thrown if there's no node at {@code path}. - * - * @param path node path - * @param createIfNotStaged flag controlling whether a new {@code StagedNode} - * instance should be created on demand - * @return a {@code StagedNode} instance or {@code null} if there's no {@code StagedNode} - * representation of the specified node and {@code createIfNotStaged == false} - * @throws NotFoundException if there's no child node with the given name - * @throws Exception if another error occurs - */ - private StagedNode getStagedNode(String path, boolean createIfNotStaged) throws Exception { - assert PathUtils.isAbsolute(path); - - if (root == null) { - if (!createIfNotStaged) { - return null; - } - root = new StagedNode(store.getRootNode(baseRevisionId), store); - } - - if (PathUtils.denotesRoot(path)) { - return root; - } - - StagedNode parent = root, node = null; - for (String name : PathUtils.elements(path)) { - node = parent.getStagedChildNode(name, createIfNotStaged); - if (node == null) { - return null; - } - parent = node; - } - return node; - } - - /** - * Discards all staged changes affecting the subtree rooted at {@code path}. - * - * @param path node path - * @return the discarded {@code StagedNode} representation or {@code null} if there wasn't any - * @throws NotFoundException if there's no node at the specified {@code path} - * @throws Exception if another error occurs - */ - private StagedNode unstageNode(String path) throws Exception { - assert PathUtils.isAbsolute(path); - - if (PathUtils.denotesRoot(path)) { - StagedNode unstaged = root; - root = null; - return unstaged; - } - - String parentPath = PathUtils.getParentPath(path); - String name = PathUtils.getName(path); - - StagedNode parent = getStagedNode(parentPath, false); - if (parent == null) { - return null; - } - - return parent.unstageChildNode(name); - } - - /** - * Returns the {@code StoredNode} at {@code path}. - * - * @param path node path - * @return the {@code StoredNode} at {@code path} - * @throws NotFoundException if there's no node at the specified {@code path} - * @throws Exception if another error occurs - */ - private StoredNode getStoredNode(String path) throws Exception { - assert PathUtils.isAbsolute(path); - - if (PathUtils.denotesRoot(path)) { - return store.getRootNode(baseRevisionId); - } - - StoredNode parent = store.getRootNode(baseRevisionId), node = null; - for (String name : PathUtils.elements(path)) { - ChildNodeEntry entry = parent.getChildNodeEntry(name); - if (entry == null) { - throw new NotFoundException(path); - } - node = store.getNode(entry.getId()); - if (node == null) { - throw new NotFoundException(path); - } - parent = node; - } - return node; - } - - private void rebaseNode(StoredNode base, StoredNode from, StoredNode to, String path) - throws Exception { - assert from != null; - assert to != null; - assert base != null; - - NodeDelta theirDelta = new NodeDelta(from, base); - NodeDelta ourDelta = new NodeDelta(from, to); - - // apply the changes - StagedNode stagedNode = getStagedNode(path, true); - - for (Entry added : ourDelta.getAddedProperties().entrySet()) { - String name = added.getKey(); - String ourValue = added.getValue(); - String theirValue = theirDelta.getAddedProperties().get(name); - - if (theirValue != null && !theirValue.equals(ourValue)) { - markConflict(stagedNode, "addExistingProperty", name, ourValue); - } else { - stagedNode.getProperties().put(name, ourValue); - } - } - - for (Entry removed : ourDelta.getRemovedProperties().entrySet()) { - String name = removed.getKey(); - String ourValue = removed.getValue(); - - if (theirDelta.getRemovedProperties().containsKey(name)) { - markConflict(stagedNode, "deleteDeletedProperty", name, ourValue); - } else if (theirDelta.getChangedProperties().containsKey(name)) { - markConflict(stagedNode, "deleteChangedProperty", name, ourValue); - } else { - stagedNode.getProperties().remove(name); - } - } - - for (Entry changed : ourDelta.getChangedProperties().entrySet()) { - String name = changed.getKey(); - String ourValue = changed.getValue(); - String theirValue = theirDelta.getChangedProperties().get(name); - - if (theirDelta.getRemovedProperties().containsKey(name)) { - markConflict(stagedNode, "changeDeletedProperty", name, ourValue); - } else if (theirValue != null && !theirValue.equals(ourValue)) { - markConflict(stagedNode, "changeChangedProperty", name, ourValue); - } else { - stagedNode.getProperties().put(name, ourValue); - } - } - - for (Entry added : ourDelta.getAddedChildNodes().entrySet()) { - String name = added.getKey(); - Id ourId = added.getValue(); - Id theirId = theirDelta.getAddedChildNodes().get(name); - - if (theirId != null && !theirId.equals(ourId)) { - // added nodes with same name but different content - try { - // try to merge the added nodes - StagedNode child = stagedNode.getStagedChildNode(name, true); - StoredNode addedTo = getStoredChildNode(to, name); - child.merge(addedTo, true); - } catch (Exception e) { - // should never happen (conflicts are marked in content) - throw new IllegalStateException(e); - } - } else { - stagedNode.add(new ChildNodeEntry(name, ourId)); - } - } - - for (Entry removed : ourDelta.getRemovedChildNodes().entrySet()) { - String name = removed.getKey(); - Id ourId = removed.getValue(); - - if (theirDelta.getRemovedChildNodes().containsKey(name)) { - markConflict(stagedNode, "deleteDeletedNode", name, ourId); - } else if (theirDelta.getChangedChildNodes().containsKey(name)) { - markConflict(stagedNode, "deleteChangedNode", name, ourId); - } else { - stagedNode.remove(name); - } - } - - for (Entry changed : ourDelta.getChangedChildNodes().entrySet()) { - String name = changed.getKey(); - Id ourId = changed.getValue(); - - StoredNode changedBase = getStoredChildNode(base, name); - if (changedBase == null) { - markConflict(stagedNode, "changeDeletedNode", name, ourId); - continue; - } - - StoredNode changedFrom = getStoredChildNode(from, name); - StoredNode changedTo = getStoredChildNode(to, name); - String changedPath = PathUtils.concat(path, name); - rebaseNode(changedBase, changedFrom, changedTo, changedPath); - } - } - - private void markConflict(StagedNode parent, String conflictType, String name, String ourValue) { - StagedNode marker = getOrAddConflictMarker(parent, conflictType); - marker.getProperties().put(name, ourValue); - } - - private void markConflict(StagedNode parent, String conflictType, String name, Id ourId) { - StagedNode marker = getOrAddConflictMarker(parent, conflictType); - marker.add(new ChildNodeEntry(name, ourId)); - } - - private StagedNode getOrAddConflictMarker(StagedNode parent, String name) { - StagedNode conflict = getOrAddNode(parent, MicroKernel.CONFLICT); - return getOrAddNode(conflict, name); - } - - private StagedNode getOrAddNode(StagedNode parent, String name) { - ChildNodeEntry cne = parent.getChildNodeEntry(name); - if (cne == null) { - return parent.add(name, new StagedNode(store)); - } else { - try { - return parent.getStagedChildNode(name, true); - } catch (Exception e) { - // should never happen - throw new IllegalStateException(e); - } - } - } - - private StoredNode getStoredChildNode(StoredNode parent, String name) throws Exception { - ChildNodeEntry cne = parent.getChildNodeEntry(name); - return cne == null ? null : store.getNode(cne.getId()); - } - - /** - * Performs a three-way merge of the trees rooted at {@code ourRoot}, - * {@code theirRoot}, using the tree at {@code baseRoot} as reference. - */ - private void mergeNode(StoredNode baseNode, StoredNode ourNode, StoredNode theirNode, String path) throws Exception { - NodeDelta theirChanges = new NodeDelta(baseNode, theirNode); - NodeDelta ourChanges = new NodeDelta(baseNode, ourNode); - - StagedNode stagedNode = getStagedNode(path, true); - - // apply our changes - stagedNode.getProperties().putAll(ourChanges.getAddedProperties()); - stagedNode.getProperties().putAll(ourChanges.getChangedProperties()); - for (String name : ourChanges.getRemovedProperties().keySet()) { - stagedNode.getProperties().remove(name); - } - - for (Map.Entry entry : ourChanges.getAddedChildNodes().entrySet()) { - stagedNode.add(new ChildNodeEntry(entry.getKey(), entry.getValue())); - } - for (Map.Entry entry : ourChanges.getChangedChildNodes().entrySet()) { - if (!theirChanges.getChangedChildNodes().containsKey(entry.getKey())) { - stagedNode.add(new ChildNodeEntry(entry.getKey(), entry.getValue())); - } - } - for (String name : ourChanges.getRemovedChildNodes().keySet()) { - stagedNode.remove(name); - } - - List conflicts = theirChanges.listConflicts(ourChanges); - // resolve/report merge conflicts - for (NodeDelta.Conflict conflict : conflicts) { - String conflictName = conflict.getName(); - String conflictPath = PathUtils.concat(path, conflictName); - switch (conflict.getType()) { - case PROPERTY_VALUE_CONFLICT: - throw new Exception( - "concurrent modification of property " + conflictPath - + " with conflicting values: \"" - + ourNode.getProperties().get(conflictName) - + "\", \"" - + theirNode.getProperties().get(conflictName)); - - case NODE_CONTENT_CONFLICT: { - if (ourChanges.getChangedChildNodes().containsKey(conflictName)) { - // modified subtrees - StoredNode baseChild = getStoredChildNode(baseNode, conflictName); - StoredNode ourChild = getStoredChildNode(ourNode, conflictName); - StoredNode theirChild = getStoredChildNode(theirNode, conflictName); - // merge the dirty subtrees recursively - mergeNode(baseChild, ourChild, theirChild, PathUtils.concat(path, conflictName)); - } else { - // added nodes with same name but different content - try { - // try to merge the added nodes - StagedNode child = stagedNode.getStagedChildNode(conflictName, true); - StoredNode theirChild = getStoredChildNode(theirNode, conflictName); - child.merge(theirChild, false); - } catch (Exception e) { - throw new Exception(String.format("colliding concurrent node creation: '%s'\n%s", conflictPath, e.getMessage())); - } - - } - break; - } - - case REMOVED_DIRTY_PROPERTY_CONFLICT: - stagedNode.getProperties().remove(conflictName); - break; - - case REMOVED_DIRTY_NODE_CONFLICT: - stagedNode.remove(conflictName); - break; - } - - } - } - - //--------------------------------------------------------< inner classes > - - private class StagedNode extends MutableNode { - - private final Map stagedChildNodes = new HashMap(); - - private StagedNode(RevisionStore store) { - super(store); - } - - private StagedNode(Node base, RevisionStore store) { - super(base, store); - } - - /** - * Returns a {@code StagedNode} representation of the specified child node. - * If a {@code StagedNode} representation doesn't exist yet a new - * {@code StagedNode} instance will be returned if {@code createIfNotStaged == true}, - * otherwise {@code null} will be returned. - *

- * A {@code NotFoundException} will be thrown if there's no child node - * with the given name. - * - * @param name child node name - * @param createIfNotStaged flag controlling whether a new {@code StagedNode} - * instance should be created on demand - * @return a {@code StagedNode} instance or {@code null} if there's no {@code StagedNode} - * representation of the specified child node and {@code createIfNotStaged == false} - * @throws NotFoundException if there's no child node with the given name - * @throws Exception if another error occurs - */ - StagedNode getStagedChildNode(String name, boolean createIfNotStaged) throws Exception { - StagedNode child = stagedChildNodes.get(name); - if (child == null) { - ChildNodeEntry entry = getChildNodeEntry(name); - if (entry != null) { - if (createIfNotStaged) { - child = new StagedNode(store.getNode(entry.getId()), store); - stagedChildNodes.put(name, child); - } - } else { - throw new NotFoundException(name); - } - } - return child; - } - - /** - * Removes the {@code StagedNode} representation of the specified child node if there is one. - * - * @param name child node name - * @return the removed {@code StagedNode} representation or {@code null} if there wasn't any - */ - StagedNode unstageChildNode(String name) { - return stagedChildNodes.remove(name); - } - - StagedNode add(String name, StagedNode node) { - stagedChildNodes.put(name, node); - // child id will be computed on persist - add(new ChildNodeEntry(name, null)); - return node; - } - - StagedNode copy() { - StagedNode copy = new StagedNode(this, store); - // recursively copy staged child nodes - for (Map.Entry entry : stagedChildNodes.entrySet()) { - copy.add(entry.getKey(), entry.getValue().copy()); - } - return copy; - } - - StagedNode add(String name, JsonObject obj) { - StagedNode node = new StagedNode(store); - node.getProperties().putAll(obj.getProperties()); - for (Map.Entry entry : obj.getChildren().entrySet()) { - node.add(entry.getKey(), entry.getValue()); - } - stagedChildNodes.put(name, node); - // child id will be computed on persist - add(new ChildNodeEntry(name, null)); - return node; - } - - /** - * Merge the properties and nodes of another node with this node. - * - * @param other other node to be merged with this node. - * @param markConflicts if true, conflicts are marked in content; otherwise an exception is thrown on conflict. - * @throws Exception - */ - void merge(final StoredNode other, final boolean markConflicts) throws Exception { - final List conflicts = new ArrayList(); - final StagedNode thisNode = this; - this.diff(other, new NodeDiffHandler() { - @Override - public void propAdded(String propName, String value) { - thisNode.getProperties().put(propName, value); - } - - @Override - public void propChanged(String propName, String oldValue, String newValue) { - if ((oldValue != null && !oldValue.equals(newValue)) || (oldValue != newValue)) { - if (markConflicts) { - markConflict(thisNode, "addExistingProperty", propName, newValue); - } else { - conflicts.add(String.format("property '%s': conflictying values '%s' and '%s'", propName, oldValue, newValue)); - } - } - } - - @Override - public void propDeleted(String propName, String value) { - // irrelevant - } - - @Override - public void childNodeAdded(ChildNodeEntry added) { - thisNode.add(added); - } - - @Override - public void childNodeDeleted(ChildNodeEntry deleted) { - // irrelevant - } - - @Override - public void childNodeChanged(ChildNodeEntry changed, Id newId) { - // check if there's already been a conflict - if ((markConflicts && thisNode.getChildNodeEntry(MicroKernel.CONFLICT) == null) - || (!markConflicts && conflicts.isEmpty())) { - // recurse - try { - StagedNode child = getStagedChildNode(changed.getName(), true); - StoredNode otherChild = getStoredChildNode(other, changed.getName()); - child.merge(otherChild, markConflicts); - } catch (Exception e) { - // should never happen - throw new IllegalStateException(e); - } - } - } - }); - - if (!markConflicts && !conflicts.isEmpty()) { - // report exceptions - StringBuffer sb = new StringBuffer(); - for (String conflict : conflicts) { - if (sb.length() > 0) { - sb.append('\n'); - } - sb.append(conflict); - } - throw new Exception(sb.toString()); - } - } - - void move(String name, String destPath) throws Exception { - ChildNodeEntry srcEntry = getChildNodeEntry(name); - assert srcEntry != null; - - String destParentPath = PathUtils.getParentPath(destPath); - String destName = PathUtils.getName(destPath); - - StagedNode destParent = getStagedNode(destParentPath, true); - - StagedNode target = stagedChildNodes.get(name); - - remove(name); - destParent.add(new ChildNodeEntry(destName, srcEntry.getId())); - - if (target != null) { - // move staged child node - destParent.add(destName, target); - } - } - - @Override - public ChildNodeEntry remove(String name) { - stagedChildNodes.remove(name); - return super.remove(name); - } - - @Override - public ChildNodeEntry rename(String oldName, String newName) { - StagedNode child = stagedChildNodes.remove(oldName); - if (child != null) { - stagedChildNodes.put(newName, child); - } - return super.rename(oldName, newName); - } - - Id persist(RevisionStore.PutToken token) throws Exception { - // recursively persist staged nodes - for (Map.Entry entry : stagedChildNodes.entrySet()) { - String name = entry.getKey(); - StagedNode childNode = entry.getValue(); - // todo decide whether to inline/store child node separately based on some filter criteria - Id id = childNode.persist(token); - // update child node entry - add(new ChildNodeEntry(name, id)); - } - // persist this node - return store.putNode(token, this); - } - } -} Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/model/MutableCommit.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/model/MutableCommit.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/model/MutableCommit.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,79 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.model; - -/** - * - */ -public class MutableCommit extends AbstractCommit { - - /** - * Commit id. - */ - private Id id; - - public MutableCommit() { - } - - /** - * Copy constructor. - * - * @param other other commit - */ - public MutableCommit(StoredCommit other) { - setParentId(other.getParentId()); - setRootNodeId(other.getRootNodeId()); - setCommitTS(other.getCommitTS()); - setMsg(other.getMsg()); - setChanges(other.getChanges()); - setBranchRootId(other.getBranchRootId()); - this.id = other.getId(); - } - - public void setParentId(Id parentId) { - this.parentId = parentId; - } - - public void setRootNodeId(Id rootNodeId) { - this.rootNodeId = rootNodeId; - } - - public void setCommitTS(long commitTS) { - this.commitTS = commitTS; - } - - public void setMsg(String msg) { - this.msg = msg; - } - - public void setChanges(String changes) { - this.changes = changes; - } - - public void setBranchRootId(Id branchRootId) { - this.branchRootId = branchRootId; - } - - /** - * Return the commit id. - * - * @return commit id - */ - public Id getId() { - return id; - } -} Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/model/NodeDelta.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/model/NodeDelta.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/model/NodeDelta.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,226 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.model; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * - */ -public class NodeDelta implements NodeDiffHandler { - - public static enum ConflictType { - /** - * same property has been added or set, but with differing values - */ - PROPERTY_VALUE_CONFLICT, - /** - * child nodes with identical name have been added or modified, but - * with differing id's; the corresponding node subtrees are hence differing - * and potentially conflicting. - */ - NODE_CONTENT_CONFLICT, - /** - * a modified property has been deleted - */ - REMOVED_DIRTY_PROPERTY_CONFLICT, - /** - * a child node entry pointing to a modified subtree has been deleted - */ - REMOVED_DIRTY_NODE_CONFLICT - } - - private final StoredNode node1; - private final StoredNode node2; - - Map addedProperties = new HashMap(); - Map removedProperties = new HashMap(); - Map changedProperties = new HashMap(); - - Map addedChildNodes = new HashMap(); - Map removedChildNodes = new HashMap(); - Map changedChildNodes = new HashMap(); - - public NodeDelta(StoredNode node1, StoredNode node2) { - this.node1 = node1; - this.node2 = node2; - node1.diff(node2, this); - } - - public Map getAddedProperties() { - return addedProperties; - } - - public Map getRemovedProperties() { - return removedProperties; - } - - public Map getChangedProperties() { - return changedProperties; - } - - public Map getAddedChildNodes() { - return addedChildNodes; - } - - public Map getRemovedChildNodes() { - return removedChildNodes; - } - - public Map getChangedChildNodes() { - return changedChildNodes; - } - - public boolean conflictsWith(NodeDelta other) { - return !listConflicts(other).isEmpty(); - } - - public List listConflicts(NodeDelta other) { - // assume that both delta's were built using the *same* base node revision - if (!node1.getId().equals(other.node1.getId())) { - throw new IllegalArgumentException("other and this NodeDelta object are expected to share common node1 instance"); - } - - List conflicts = new ArrayList(); - - // properties - - Map otherAddedProps = other.getAddedProperties(); - for (Map.Entry added : addedProperties.entrySet()) { - String otherValue = otherAddedProps.get(added.getKey()); - if (otherValue != null && !added.getValue().equals(otherValue)) { - // same property added with conflicting values - conflicts.add(new Conflict(ConflictType.PROPERTY_VALUE_CONFLICT, added.getKey())); - } - } - - Map otherChangedProps = other.getChangedProperties(); - Map otherRemovedProps = other.getRemovedProperties(); - for (Map.Entry changed : changedProperties.entrySet()) { - String otherValue = otherChangedProps.get(changed.getKey()); - if (otherValue != null && !changed.getValue().equals(otherValue)) { - // same property changed with conflicting values - conflicts.add(new Conflict(ConflictType.PROPERTY_VALUE_CONFLICT, changed.getKey())); - } - if (otherRemovedProps.containsKey(changed.getKey())) { - // changed property has been removed - conflicts.add(new Conflict(ConflictType.REMOVED_DIRTY_PROPERTY_CONFLICT, changed.getKey())); - } - } - - for (Map.Entry removed : removedProperties.entrySet()) { - if (otherChangedProps.containsKey(removed.getKey())) { - // removed property has been changed - conflicts.add(new Conflict(ConflictType.REMOVED_DIRTY_PROPERTY_CONFLICT, removed.getKey())); - } - } - - // child node entries - - Map otherAddedChildNodes = other.getAddedChildNodes(); - for (Map.Entry added : addedChildNodes.entrySet()) { - Id otherValue = otherAddedChildNodes.get(added.getKey()); - if (otherValue != null && !added.getValue().equals(otherValue)) { - // same child node entry added with different target id's - conflicts.add(new Conflict(ConflictType.NODE_CONTENT_CONFLICT, added.getKey())); - } - } - - Map otherChangedChildNodes = other.getChangedChildNodes(); - Map otherRemovedChildNodes = other.getRemovedChildNodes(); - for (Map.Entry changed : changedChildNodes.entrySet()) { - Id otherValue = otherChangedChildNodes.get(changed.getKey()); - if (otherValue != null && !changed.getValue().equals(otherValue)) { - // same child node entry changed with different target id's - conflicts.add(new Conflict(ConflictType.NODE_CONTENT_CONFLICT, changed.getKey())); - } - if (otherRemovedChildNodes.containsKey(changed.getKey())) { - // changed child node entry has been removed - conflicts.add(new Conflict(ConflictType.REMOVED_DIRTY_NODE_CONFLICT, changed.getKey())); - } - } - - for (Map.Entry removed : removedChildNodes.entrySet()) { - if (otherChangedChildNodes.containsKey(removed.getKey())) { - // removed child node entry has been changed - conflicts.add(new Conflict(ConflictType.REMOVED_DIRTY_NODE_CONFLICT, removed.getKey())); - } - } - - return conflicts; - } - - //--------------------------------------------------------< NodeDiffHandler > - - @Override - public void propAdded(String propName, String value) { - addedProperties.put(propName, value); - } - - @Override - public void propChanged(String propName, String oldValue, String newValue) { - changedProperties.put(propName, newValue); - } - - @Override - public void propDeleted(String propName, String value) { - removedProperties.put(propName, value); - } - - @Override - public void childNodeAdded(ChildNodeEntry added) { - addedChildNodes.put(added.getName(), added.getId()); - } - - @Override - public void childNodeDeleted(ChildNodeEntry deleted) { - removedChildNodes.put(deleted.getName(), deleted.getId()); - } - - @Override - public void childNodeChanged(ChildNodeEntry changed, Id newId) { - changedChildNodes.put(changed.getName(), newId); - } - - //--------------------------------------------------------< inner classes > - - public static class Conflict { - - final ConflictType type; - final String name; - - /** - * @param type conflict type - * @param name name of conflicting property or child node - */ - Conflict(ConflictType type, String name) { - this.type = type; - this.name = name; - } - - public ConflictType getType() { - return type; - } - - public String getName() { - return name; - } - } -} Index: pom.xml IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- pom.xml (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ pom.xml (revision ) @@ -40,7 +40,6 @@ oak-commons oak-blob oak-mk-api - oak-mk oak-mk-remote oak-core oak-jcr Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/model/ChildNodeEntriesTree.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/model/ChildNodeEntriesTree.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/model/ChildNodeEntriesTree.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,700 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.model; - -import org.apache.jackrabbit.mk.store.Binding; -import org.apache.jackrabbit.mk.store.CacheObject; -import org.apache.jackrabbit.mk.store.RevisionProvider; -import org.apache.jackrabbit.mk.store.RevisionStore; -import org.apache.jackrabbit.mk.util.AbstractFilteringIterator; -import org.apache.jackrabbit.mk.util.AbstractRangeIterator; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.NoSuchElementException; - -/** - * - */ -public class ChildNodeEntriesTree implements ChildNodeEntries, CacheObject { - - protected static final List EMPTY = Collections.emptyList(); - - protected int count; - - protected RevisionProvider revProvider; - - // array of *immutable* IndexEntry objects - protected IndexEntry[] index = new IndexEntry[1024]; // 2^10 - - ChildNodeEntriesTree(RevisionProvider revProvider) { - this.revProvider = revProvider; - } - - @Override - public boolean inlined() { - return false; - } - - //------------------------------------------------------------< overrides > - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof ChildNodeEntriesTree) { - ChildNodeEntriesTree other = (ChildNodeEntriesTree) obj; - return Arrays.equals(index, other.index); - } - return false; - } - - @Override - public Object clone() { - ChildNodeEntriesTree clone = null; - try { - clone = (ChildNodeEntriesTree) super.clone(); - } catch (CloneNotSupportedException e) { - // can't possibly get here - } - // shallow clone of array of immutable IndexEntry objects - clone.index = index.clone(); - return clone; - } - - //-------------------------------------------------------------< read ops > - - @Override - public int getCount() { - return count; - } - - @Override - public ChildNodeEntry get(String name) { - IndexEntry entry = index[keyToIndex(name)]; - if (entry == null) { - return null; - } - if (entry instanceof ChildNodeEntry) { - ChildNodeEntry cne = (ChildNodeEntry) entry; - return cne.getName().equals(name) ? cne : null; - } else if (entry instanceof BucketInfo) { - BucketInfo bi = (BucketInfo) entry; - ChildNodeEntries entries = retrieveBucket(bi.getId()); - return entries == null ? null : entries.get(name); - } else { - // dirty bucket - Bucket bucket = (Bucket) entry; - return bucket.get(name); - } - } - - @Override - public Iterator getNames(int offset, int cnt) { - if (offset < 0 || cnt < -1) { - throw new IllegalArgumentException(); - } - - if (offset >= count || cnt == 0) { - List empty = Collections.emptyList(); - return empty.iterator(); - } - - if (cnt == -1 || (offset + cnt) > count) { - cnt = count - offset; - } - - return new AbstractRangeIterator(getEntries(offset, cnt), 0, -1) { - @Override - protected String doNext() { - ChildNodeEntry cne = (ChildNodeEntry) it.next(); - return cne.getName(); - } - }; - } - - @Override - public Iterator getEntries(int offset, int cnt) { - if (offset < 0 || cnt < -1) { - throw new IllegalArgumentException(); - } - - if (offset >= count || cnt == 0) { - return EMPTY.iterator(); - } - - int skipped = 0; - if (cnt == -1 || (offset + cnt) > count) { - cnt = count - offset; - } - ArrayList list = new ArrayList(cnt); - for (IndexEntry e : index) { - if (e != null) { - if (skipped + e.getSize() <= offset) { - skipped += e.getSize(); - } else { - if (e instanceof NodeInfo) { - list.add((NodeInfo) e); - } else if (e instanceof BucketInfo) { - BucketInfo bi = (BucketInfo) e; - ChildNodeEntries bucket = retrieveBucket(bi.getId()); - for (Iterator it = - bucket.getEntries(offset - skipped, cnt - list.size()); - it.hasNext(); ) { - list.add(it.next()); - } - skipped = offset; - } else { - // dirty bucket - Bucket bucket = (Bucket) e; - for (Iterator it = - bucket.getEntries(offset - skipped, cnt - list.size()); - it.hasNext(); ) { - list.add(it.next()); - } - skipped = offset; - } - if (list.size() == cnt) { - break; - } - } - } - } - - return list.iterator(); - } - - //------------------------------------------------------------< write ops > - - @Override - public ChildNodeEntry add(ChildNodeEntry entry) { - int idx = keyToIndex(entry.getName()); - IndexEntry ie = index[idx]; - if (ie == null) { - index[idx] = new NodeInfo(entry.getName(), entry.getId()); - count++; - return null; - } - if (ie instanceof ChildNodeEntry) { - ChildNodeEntry existing = (ChildNodeEntry) ie; - if (existing.getName().equals(entry.getName())) { - index[idx] = new NodeInfo(entry.getName(), entry.getId()); - return existing; - } else { - Bucket bucket = new Bucket(); - bucket.add(existing); - bucket.add(entry); - index[idx] = bucket; - count++; - return null; - } - } - - Bucket bucket; - if (ie instanceof BucketInfo) { - BucketInfo bi = (BucketInfo) ie; - bucket = new Bucket(retrieveBucket(bi.getId())); - } else { - // dirty bucket - bucket = (Bucket) ie; - } - - ChildNodeEntry existing = bucket.add(entry); - if (entry.equals(existing)) { - // no-op - return existing; - } - index[idx] = bucket; - if (existing == null) { - // new entry - count++; - } - return existing; - } - - @Override - public ChildNodeEntry remove(String name) { - int idx = keyToIndex(name); - IndexEntry ie = index[idx]; - if (ie == null) { - return null; - } - if (ie instanceof ChildNodeEntry) { - ChildNodeEntry existing = (ChildNodeEntry) ie; - if (existing.getName().equals(name)) { - index[idx] = null; - count--; - return existing; - } else { - return null; - } - } - - Bucket bucket; - if (ie instanceof BucketInfo) { - BucketInfo bi = (BucketInfo) ie; - bucket = new Bucket(retrieveBucket(bi.getId())); - } else { - // dirty bucket - bucket = (Bucket) ie; - } - - ChildNodeEntry existing = bucket.remove(name); - if (existing == null) { - return null; - } - if (bucket.getCount() == 0) { - index[idx] = null; - } else if (bucket.getCount() == 1) { - // inline single remaining entry - ChildNodeEntry remaining = bucket.getEntries(0, 1).next(); - index[idx] = new NodeInfo(remaining.getName(), remaining.getId()); - } else { - index[idx] = bucket; - } - count--; - return existing; - } - - @Override - public ChildNodeEntry rename(String oldName, String newName) { - if (oldName.equals(newName)) { - return get(oldName); - } - ChildNodeEntry old = remove(oldName); - if (old == null) { - return null; - } - add(new ChildNodeEntry(newName, old.getId())); - return old; - } - - //-------------------------------------------------------------< diff ops > - - @Override - public Iterator getAdded(final ChildNodeEntries other) { - if (other instanceof ChildNodeEntriesTree) { - List added = new ArrayList(); - ChildNodeEntriesTree otherEntries = (ChildNodeEntriesTree) other; - for (int i = 0; i < index.length; i++) { - IndexEntry ie1 = index[i]; - IndexEntry ie2 = otherEntries.index[i]; - if (! (ie1 == null ? ie2 == null : ie1.equals(ie2))) { - // index entries aren't equal - if (ie1 == null) { - // this index entry in null => other must be non-null - if (ie2 instanceof NodeInfo) { - added.add((ChildNodeEntry) ie2); - } else if (ie2 instanceof BucketInfo) { - BucketInfo bi = (BucketInfo) ie2; - ChildNodeEntries bucket = retrieveBucket(bi.getId()); - for (Iterator it = bucket.getEntries(0, -1); - it.hasNext(); ) { - added.add(it.next()); - } - } else { - // dirty bucket - Bucket bucket = (Bucket) ie2; - for (Iterator it = bucket.getEntries(0, -1); - it.hasNext(); ) { - added.add(it.next()); - } - } - } else if (ie2 != null) { - // both this and other index entry are non-null - ChildNodeEntriesMap bucket1; - if (ie1 instanceof NodeInfo) { - bucket1 = new ChildNodeEntriesMap(); - bucket1.add((ChildNodeEntry) ie1); - } else if (ie1 instanceof BucketInfo) { - BucketInfo bi = (BucketInfo) ie1; - bucket1 = retrieveBucket(bi.getId()); - } else { - // dirty bucket - bucket1 = (Bucket) ie1; - } - ChildNodeEntriesMap bucket2; - if (ie2 instanceof NodeInfo) { - bucket2 = new ChildNodeEntriesMap(); - bucket2.add((ChildNodeEntry) ie2); - } else if (ie2 instanceof BucketInfo) { - BucketInfo bi = (BucketInfo) ie2; - bucket2 = retrieveBucket(bi.getId()); - } else { - // dirty bucket - bucket2 = (Bucket) ie2; - } - - for (Iterator it = bucket1.getAdded(bucket2); - it.hasNext(); ) { - added.add(it.next()); - } - } - } - } - return added.iterator(); - } else { - // todo optimize - return new AbstractFilteringIterator(other.getEntries(0, -1)) { - @Override - protected boolean include(ChildNodeEntry entry) { - return get(entry.getName()) == null; - } - }; - } - } - - @Override - public Iterator getRemoved(final ChildNodeEntries other) { - if (other instanceof ChildNodeEntriesTree) { - List removed = new ArrayList(); - ChildNodeEntriesTree otherEntries = (ChildNodeEntriesTree) other; - for (int i = 0; i < index.length; i++) { - IndexEntry ie1 = index[i]; - IndexEntry ie2 = otherEntries.index[i]; - if (! (ie1 == null ? ie2 == null : ie1.equals(ie2))) { - // index entries aren't equal - if (ie2 == null) { - // other index entry is null => this must be non-null - if (ie1 instanceof NodeInfo) { - removed.add((ChildNodeEntry) ie1); - } else if (ie1 instanceof BucketInfo) { - BucketInfo bi = (BucketInfo) ie1; - ChildNodeEntries bucket = retrieveBucket(bi.getId()); - for (Iterator it = bucket.getEntries(0, -1); - it.hasNext(); ) { - removed.add(it.next()); - } - } else { - // dirty bucket - Bucket bucket = (Bucket) ie1; - for (Iterator it = bucket.getEntries(0, -1); - it.hasNext(); ) { - removed.add(it.next()); - } - } - } else if (ie1 != null) { - // both this and other index entry are non-null - ChildNodeEntriesMap bucket1; - if (ie1 instanceof NodeInfo) { - bucket1 = new ChildNodeEntriesMap(); - bucket1.add((ChildNodeEntry) ie1); - } else if (ie1 instanceof BucketInfo) { - BucketInfo bi = (BucketInfo) ie1; - bucket1 = retrieveBucket(bi.getId()); - } else { - // dirty bucket - bucket1 = (Bucket) ie1; - } - ChildNodeEntriesMap bucket2; - if (ie2 instanceof NodeInfo) { - bucket2 = new ChildNodeEntriesMap(); - bucket2.add((ChildNodeEntry) ie2); - } else if (ie2 instanceof BucketInfo) { - BucketInfo bi = (BucketInfo) ie2; - bucket2 = retrieveBucket(bi.getId()); - } else { - // dirty bucket - bucket2 = (Bucket) ie2; - } - - for (Iterator it = bucket1.getRemoved(bucket2); - it.hasNext(); ) { - removed.add(it.next()); - } - } - } - } - return removed.iterator(); - } else { - // todo optimize - return new AbstractFilteringIterator(getEntries(0, -1)) { - @Override - protected boolean include(ChildNodeEntry entry) { - return other.get(entry.getName()) == null; - } - }; - } - } - - @Override - public Iterator getModified(final ChildNodeEntries other) { - if (other instanceof ChildNodeEntriesTree) { - List modified = new ArrayList(); - ChildNodeEntriesTree otherEntries = (ChildNodeEntriesTree) other; - for (int i = 0; i < index.length; i++) { - IndexEntry ie1 = index[i]; - IndexEntry ie2 = otherEntries.index[i]; - if (ie1 != null && ie2 != null && !ie1.equals(ie2)) { - // index entries are non-null and not equal - if (ie1 instanceof NodeInfo - && ie2 instanceof NodeInfo) { - NodeInfo ni1 = (NodeInfo) ie1; - NodeInfo ni2 = (NodeInfo) ie2; - if (ni1.getName().equals(ni2.getName()) - && !ni1.getId().equals(ni2.getId())) { - modified.add(ni1); - continue; - } - } - - ChildNodeEntriesMap bucket1; - if (ie1 instanceof NodeInfo) { - bucket1 = new ChildNodeEntriesMap(); - bucket1.add((ChildNodeEntry) ie1); - } else if (ie1 instanceof BucketInfo) { - BucketInfo bi = (BucketInfo) ie1; - bucket1 = retrieveBucket(bi.getId()); - } else { - // dirty bucket - bucket1 = (Bucket) ie1; - } - ChildNodeEntriesMap bucket2; - if (ie2 instanceof NodeInfo) { - bucket2 = new ChildNodeEntriesMap(); - bucket2.add((ChildNodeEntry) ie2); - } else if (ie2 instanceof BucketInfo) { - BucketInfo bi = (BucketInfo) ie2; - bucket2 = retrieveBucket(bi.getId()); - } else { - // dirty bucket - bucket2 = (Bucket) ie2; - } - - for (Iterator it = bucket1.getModified(bucket2); - it.hasNext(); ) { - modified.add(it.next()); - } - } - } - - return modified.iterator(); - } else { - return new AbstractFilteringIterator(getEntries(0, -1)) { - @Override - protected boolean include(ChildNodeEntry entry) { - ChildNodeEntry namesake = other.get(entry.getName()); - return (namesake != null && !namesake.getId().equals(entry.getId())); - } - }; - } - } - - //-------------------------------------------------------< implementation > - - protected void persistDirtyBuckets(RevisionStore store, RevisionStore.PutToken token) throws Exception { - for (int i = 0; i < index.length; i++) { - if (index[i] instanceof Bucket) { - // dirty bucket - Bucket bucket = (Bucket) index[i]; - Id id = store.putCNEMap(token, bucket); - index[i] = new BucketInfo(id, bucket.getSize()); - } - } - } - - protected int keyToIndex(String key) { - int hash = key.hashCode(); - // todo rehash? ensure optimal distribution of hash WRT to index.length - return (hash & 0x7FFFFFFF) % index.length; - } - - protected ChildNodeEntriesMap retrieveBucket(Id id) { - try { - return revProvider.getCNEMap(id); - } catch (Exception e) { - // todo log error and gracefully handle exception - return new ChildNodeEntriesMap(); - } - } - - //------------------------------------------------< serialization support > - - public void serialize(Binding binding) throws Exception { - // TODO use binary instead of string serialization - binding.write(":count", count); - binding.writeMap(":index", index.length, new Binding.StringEntryIterator() { - int pos = -1; - - @Override - public boolean hasNext() { - return pos < index.length - 1; - } - - @Override - public Binding.StringEntry next() { - pos++; - if (pos >= index.length) { - throw new NoSuchElementException(); - } - // serialize index array entry - IndexEntry entry = index[pos]; - if (entry == null) { - // null entry: "" - return new Binding.StringEntry(Integer.toString(pos), ""); - } else if (entry instanceof NodeInfo) { - NodeInfo ni = (NodeInfo) entry; - // "n:" - return new Binding.StringEntry(Integer.toString(pos), "n" + ni.getId() + ":" + ni.getName()); - } else { - BucketInfo bi = (BucketInfo) entry; - // "b:" - return new Binding.StringEntry(Integer.toString(pos), "b" + bi.getId() + ":" + bi.getSize()); - } - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - }); - } - - static ChildNodeEntriesTree deserialize(RevisionProvider provider, Binding binding) throws Exception { - // TODO use binary instead of string serialization - ChildNodeEntriesTree newInstance = new ChildNodeEntriesTree(provider); - newInstance.count = binding.readIntValue(":count"); - Binding.StringEntryIterator iter = binding.readStringMap(":index"); - int pos = -1; - while (iter.hasNext()) { - Binding.StringEntry entry = iter.next(); - ++pos; - // deserialize index array entry - assert(pos == Integer.parseInt(entry.getKey())); - if (entry.getValue().length() == 0) { - // "" - newInstance.index[pos] = null; - } else if (entry.getValue().charAt(0) == 'n') { - // "n:" - String value = entry.getValue().substring(1); - int i = value.indexOf(':'); - String id = value.substring(0, i); - String name = value.substring(i + 1); - newInstance.index[pos] = new NodeInfo(name, Id.fromString(id)); - } else { - // "b:" - String value = entry.getValue().substring(1); - int i = value.indexOf(':'); - String id = value.substring(0, i); - int count = Integer.parseInt(value.substring(i + 1)); - newInstance.index[pos] = new BucketInfo(Id.fromString(id), count); - } - } - return newInstance; - } - - //--------------------------------------------------------< inner classes > - - protected static interface IndexEntry { - // number of entries - int getSize(); - } - - protected static class BucketInfo implements IndexEntry { - - // bucket id - private final Id id; - - // number of bucket entries - private final int size; - - protected BucketInfo(Id id, int size) { - this.id = id; - this.size = size; - } - - public Id getId() { - return id; - } - - public int getSize() { - return size; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof BucketInfo) { - BucketInfo other = (BucketInfo) obj; - return (size == other.size && id == null ? other.id == null : id.equals(other.id)); - } - return false; - } - } - - protected static class Bucket extends ChildNodeEntriesMap implements IndexEntry { - - protected Bucket() { - } - - protected Bucket(ChildNodeEntriesMap other) { - super(other); - } - - @Override - public int getSize() { - return getCount(); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof Bucket) { - return super.equals(obj); - } - return false; - } - } - - protected static class NodeInfo extends ChildNodeEntry implements IndexEntry { - - public NodeInfo(String name, Id id) { - super(name, id); - } - - public int getSize() { - return 1; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof NodeInfo) { - return super.equals(obj); - } - return false; - } - } - - @Override - public int getMemory() { - // assuming a fixed size of 1000 entries, each with 100 bytes, plus 100 bytes overhead - int memory = 100 + 1000 * 100; - return memory; - } - -} Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/store/IdFactory.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/store/IdFactory.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/store/IdFactory.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,60 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.store; - -import java.security.MessageDigest; - -/** - * Create new internal content object ids based on serialized data. - */ -public abstract class IdFactory { - - /** - * Creates a new id based on the specified serialized data. - *

- * The general contract of {@code createContentId} is: - *

- * {@code createId(data1).equals(createId(data2)) == Arrays.equals(data1, data2)} - * - * @param serialized serialized data - * @return raw node id as byte array - * @throws Exception if an error occurs - */ - public byte[] createContentId(byte[] serialized) throws Exception { - return digest(serialized); - } - - /** - * Return a digest for some data. - * - * @param data data - * @return digest - */ - protected byte[] digest(byte[] data) throws Exception { - return MessageDigest.getInstance("SHA-1").digest(data); - } - - /** - * Return the default factory that will create node and revision ids based - * on their content. - * - * @return factory - */ - public static IdFactory getDigestFactory() { - return new IdFactory() {}; - } -} Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/model/AbstractCommit.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/model/AbstractCommit.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/model/AbstractCommit.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,116 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.model; - -import org.apache.jackrabbit.mk.store.Binding; -import org.apache.jackrabbit.mk.store.CacheObject; - -/** - * - */ -public abstract class AbstractCommit implements Commit, CacheObject { - - // id of root node associated with this commit - protected Id rootNodeId; - - // commit timestamp - protected long commitTS; - - // commit message - protected String msg; - - // changes - protected String changes; - - // id of parent commit - protected Id parentId; - - // id of branch root commit - protected Id branchRootId; - - protected AbstractCommit() { - } - - protected AbstractCommit(Commit other) { - this.parentId = other.getParentId(); - this.rootNodeId = other.getRootNodeId(); - this.msg = other.getMsg(); - this.changes = other.getChanges(); - this.commitTS = other.getCommitTS(); - this.branchRootId = other.getBranchRootId(); - } - - public Id getParentId() { - return parentId; - } - - public Id getRootNodeId() { - return rootNodeId; - } - - public long getCommitTS() { - return commitTS; - } - - public String getMsg() { - return msg; - } - - public String getChanges() { - return changes; - } - - public Id getBranchRootId() { - return branchRootId; - } - - public void serialize(Binding binding) throws Exception { - binding.write("rootNodeId", rootNodeId.getBytes()); - binding.write("commitTS", commitTS); - binding.write("msg", msg == null ? "" : msg); - binding.write("changes", changes == null ? "" : changes); - binding.write("parentId", parentId == null ? "" : parentId.toString()); - binding.write("branchRootId", branchRootId == null ? "" : branchRootId.toString()); - } - - //-----------------------------------------------------< Object overrides > - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("rootNodeId: '").append(rootNodeId.toString()).append("', "); - sb.append("commitTS: ").append(commitTS).append(", "); - sb.append("msg: '").append(msg == null ? "" : msg).append("', "); - sb.append("changes: '").append(changes == null ? "" : changes).append("', "); - sb.append("parentId: '").append(parentId == null ? "" : parentId.toString()).append("', "); - sb.append("branchRootId: '").append(branchRootId == null ? "" : branchRootId.toString()).append("'"); - return sb.toString(); - } - - @Override - public int getMemory() { - int memory = 100; - if (msg != null) { - memory += 2 * msg.length(); - } - if (changes != null) { - memory += 2 * changes.length(); - } - return memory; - } - -} Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/model/ChildNodeEntry.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/model/ChildNodeEntry.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/model/ChildNodeEntry.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.model; - -/** - * - */ -public class ChildNodeEntry { - - private final String name; - private final Id id; - - public ChildNodeEntry(String name, Id id) { - this.name = name; - this.id = id; - } - - public String getName() { - return name; - } - - public Id getId() { - return id; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof ChildNodeEntry) { - ChildNodeEntry other = (ChildNodeEntry) obj; - return (name == null ? other.name == null : name.equals(other.name) - && id == null ? other.id == null : id.equals(other.id)); - } - return false; - } -} Index: oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/blob/DocumentMKWriteTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/blob/DocumentMKWriteTest.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/blob/DocumentMKWriteTest.java (revision ) @@ -22,7 +22,7 @@ import java.io.ByteArrayInputStream; import java.util.Arrays; -import org.apache.jackrabbit.mk.util.MicroKernelInputStream; +import org.apache.jackrabbit.oak.commons.mk.MicroKernelInputStream; import org.apache.jackrabbit.oak.plugins.document.AbstractMongoConnectionTest; import org.junit.Test; \ No newline at end of file Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/InMemPersistence.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/InMemPersistence.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/InMemPersistence.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,215 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.persistence; - -import org.apache.jackrabbit.mk.model.ChildNodeEntries; -import org.apache.jackrabbit.mk.model.ChildNodeEntriesMap; -import org.apache.jackrabbit.mk.model.Commit; -import org.apache.jackrabbit.mk.model.Id; -import org.apache.jackrabbit.mk.model.Node; -import org.apache.jackrabbit.mk.model.StoredCommit; -import org.apache.jackrabbit.mk.model.StoredNode; -import org.apache.jackrabbit.mk.store.BinaryBinding; -import org.apache.jackrabbit.mk.store.IdFactory; -import org.apache.jackrabbit.mk.store.NotFoundException; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -/** - * - */ -public class InMemPersistence implements GCPersistence { - - private final Map objects = Collections.synchronizedMap(new HashMap()); - private final Map marked = Collections.synchronizedMap(new HashMap()); - - private long gcStart; - - /** - * Read-write lock for objects collection. - */ - private final ReentrantReadWriteLock objectsLock = new ReentrantReadWriteLock(); - - // TODO: make this configurable - private IdFactory idFactory = IdFactory.getDigestFactory(); - - @Override - public void initialize(File homeDir) { - // nothing to initialize - } - - @Override - public Id[] readIds() throws Exception { - return new Id[2]; - } - - public void writeHead(Id id) { - - } - - private byte[] get(Id id) { - objectsLock.readLock().lock(); - try { - return objects.get(id); - } finally { - objectsLock.readLock().unlock(); - } - } - - private byte[] put(Id id, byte[] bytes) { - objectsLock.writeLock().lock(); - try { - return objects.put(id, bytes); - } finally { - objectsLock.writeLock().unlock(); - } - } - - public void readNode(StoredNode node) throws NotFoundException, Exception { - Id id = node.getId(); - byte[] bytes = get(id); - if (bytes != null) { - node.deserialize(new BinaryBinding(new ByteArrayInputStream(bytes))); - return; - } - throw new NotFoundException(id.toString()); - } - - public Id writeNode(Node node) throws Exception { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - node.serialize(new BinaryBinding(out)); - byte[] bytes = out.toByteArray(); - Id id = new Id(idFactory.createContentId(bytes)); - - put(id, bytes); - - if (gcStart != 0) { - marked.put(id, bytes); - } - return id; - } - - public StoredCommit readCommit(Id id) throws NotFoundException, Exception { - byte[] bytes = get(id); - if (bytes != null) { - return StoredCommit.deserialize(id, new BinaryBinding(new ByteArrayInputStream(bytes))); - } - throw new NotFoundException(id.toString()); - } - - public void writeCommit(Id id, Commit commit) throws Exception { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - commit.serialize(new BinaryBinding(out)); - byte[] bytes = out.toByteArray(); - - put(id, bytes); - - if (gcStart != 0) { - marked.put(id, bytes); - } - } - - public ChildNodeEntriesMap readCNEMap(Id id) throws NotFoundException, Exception { - byte[] bytes = get(id); - if (bytes != null) { - return ChildNodeEntriesMap.deserialize(new BinaryBinding(new ByteArrayInputStream(bytes))); - } - throw new NotFoundException(id.toString()); - } - - public Id writeCNEMap(ChildNodeEntries map) throws Exception { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - map.serialize(new BinaryBinding(out)); - byte[] bytes = out.toByteArray(); - Id id = new Id(idFactory.createContentId(bytes)); - - put(id, bytes); - - if (gcStart != 0) { - marked.put(id, bytes); - } - return id; - } - - @Override - public void close() { - // nothing to do here - } - - @Override - public void start() { - gcStart = System.currentTimeMillis(); - marked.clear(); - } - - @Override - public boolean markCommit(Id id) throws NotFoundException { - return markObject(id); - } - - @Override - public boolean markNode(Id id) throws NotFoundException { - return markObject(id); - } - - @Override - public boolean markCNEMap(Id id) throws NotFoundException { - return markObject(id); - } - - @Override - public void replaceCommit(Id id, Commit commit) throws Exception { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - commit.serialize(new BinaryBinding(out)); - byte[] bytes = out.toByteArray(); - - put(id, bytes); - marked.put(id, bytes); - } - - private boolean markObject(Id id) throws NotFoundException { - byte[] data = get(id); - if (data != null) { - return marked.put(id, data) == null; - } - throw new NotFoundException(id.toString()); - } - - @Override - public int sweep() { - objectsLock.writeLock().lock(); - - int count = objects.size(); - - try { - objects.clear(); - objects.putAll(marked); - - gcStart = 0; - - return count - objects.size(); - } finally { - objectsLock.writeLock().unlock(); - } - } -} Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/store/BinaryBinding.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/store/BinaryBinding.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/store/BinaryBinding.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,198 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.store; - -import org.apache.jackrabbit.oak.commons.IOUtils; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.NoSuchElementException; - -/** - * Implementation note: the 'key' parameter is ignored - * since it's not required for binary serialization. - */ -public class BinaryBinding implements Binding { - - protected InputStream in; - protected OutputStream out; - - public BinaryBinding(InputStream in) { - this.in = in; - out = null; - } - - public BinaryBinding(OutputStream out) { - this.out = out; - in = null; - } - - @Override - public void write(String key, String value) throws Exception { - if (out == null) { - throw new IllegalStateException("no OutputStream provided"); - } - IOUtils.writeString(out, value); - } - - @Override - public void write(String key, byte[] value) throws Exception { - if (out == null) { - throw new IllegalStateException("no OutputStream provided"); - } - IOUtils.writeBytes(out, value); - } - - @Override - public void write(String key, long value) throws Exception { - if (out == null) { - throw new IllegalStateException("no OutputStream provided"); - } - IOUtils.writeVarLong(out, value); - } - - @Override - public void write(String key, int value) throws Exception { - if (out == null) { - throw new IllegalStateException("no OutputStream provided"); - } - IOUtils.writeVarInt(out, value); - } - - @Override - public void writeMap(String key, int count, StringEntryIterator iterator) throws Exception { - if (out == null) { - throw new IllegalStateException("no OutputStream provided"); - } - IOUtils.writeVarInt(out, count); - while (iterator.hasNext()) { - StringEntry entry = iterator.next(); - IOUtils.writeString(out, entry.getKey()); - IOUtils.writeString(out, entry.getValue()); - } - } - - @Override - public void writeMap(String key, int count, BytesEntryIterator iterator) throws Exception { - if (out == null) { - throw new IllegalStateException("no OutputStream provided"); - } - IOUtils.writeVarInt(out, count); - while (iterator.hasNext()) { - BytesEntry entry = iterator.next(); - IOUtils.writeString(out, entry.getKey()); - IOUtils.writeBytes(out, entry.getValue()); - } - } - - @Override - public String readStringValue(String key) throws Exception { - if (in == null) { - throw new IllegalStateException("no InputStream provided"); - } - return IOUtils.readString(in); - } - - @Override - public byte[] readBytesValue(String key) throws Exception { - if (in == null) { - throw new IllegalStateException("no InputStream provided"); - } - return IOUtils.readBytes(in); - } - - @Override - public long readLongValue(String key) throws Exception { - if (in == null) { - throw new IllegalStateException("no InputStream provided"); - } - return IOUtils.readVarLong(in); - } - - @Override - public int readIntValue(String key) throws Exception { - if (in == null) { - throw new IllegalStateException("no InputStream provided"); - } - return IOUtils.readVarInt(in); - } - - @Override - public StringEntryIterator readStringMap(String key) throws Exception { - if (in == null) { - throw new IllegalStateException("no InputStream provided"); - } - final int size = IOUtils.readVarInt(in); - return new StringEntryIterator() { - int count = size; - - public boolean hasNext() { - return count > 0; - } - - public StringEntry next() { - if (count-- > 0) { - try { - String key = IOUtils.readString(in); - String value = IOUtils.readString(in); - return new StringEntry(key, value); - } catch (IOException e) { - throw new RuntimeException("deserialization failed", e); - } - } - throw new NoSuchElementException(); - } - - public void remove() { - throw new UnsupportedOperationException(); - } - }; - } - - @Override - public BytesEntryIterator readBytesMap(String key) throws Exception { - if (in == null) { - throw new IllegalStateException("no InputStream provided"); - } - final int size = IOUtils.readVarInt(in); - return new BytesEntryIterator() { - int count = size; - - public boolean hasNext() { - return count > 0; - } - - public BytesEntry next() { - if (count-- > 0) { - try { - String key = IOUtils.readString(in); - byte[] value = IOUtils.readBytes(in); - return new BytesEntry(key, value); - } catch (IOException e) { - throw new RuntimeException("deserialization failed", e); - } - } - throw new NoSuchElementException(); - } - - public void remove() { - throw new UnsupportedOperationException(); - } - }; - } -} Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/util/AbstractFilteringIterator.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/util/AbstractFilteringIterator.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/util/AbstractFilteringIterator.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,62 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.util; - -import java.util.Iterator; -import java.util.NoSuchElementException; - -/** - * - */ -public abstract class AbstractFilteringIterator implements Iterator { - - protected final Iterator it; - protected int count; - - protected T next = null; - - public AbstractFilteringIterator(Iterator it) { - this.it = it; - } - - public boolean hasNext() { - while (next == null && it.hasNext()) { - T entry = it.next(); - if (include(entry)) { - next = entry; - } - } - - return next != null; - } - - abstract protected boolean include(T entry); - - public T next() { - if (hasNext()) { - T entry = next; - next = null; - return entry; - } else { - throw new NoSuchElementException(); - } - } - - public void remove() { - throw new UnsupportedOperationException(); - } -} Index: oak-run/src/main/java/org/apache/jackrabbit/oak/fixture/OakRepositoryFixture.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-run/src/main/java/org/apache/jackrabbit/oak/fixture/OakRepositoryFixture.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-run/src/main/java/org/apache/jackrabbit/oak/fixture/OakRepositoryFixture.java (revision ) @@ -26,23 +26,11 @@ public class OakRepositoryFixture implements RepositoryFixture { public static RepositoryFixture getMemory(long cacheSize) { - return getMemory(OakFixture.OAK_MEMORY, false, cacheSize); + return getMemory(OakFixture.OAK_MEMORY, cacheSize); } - public static RepositoryFixture getMemoryNS(long cacheSize) { - return getMemory(OakFixture.OAK_MEMORY_NS, false, cacheSize); - } - - public static RepositoryFixture getMemoryMK(long cacheSize) { - return getMemory(OakFixture.OAK_MEMORY_MK, true, cacheSize); - } - - private static RepositoryFixture getMemory(String name, boolean useMK, long cacheSize) { - return new OakRepositoryFixture(OakFixture.getMemory(name, useMK, cacheSize)); - } - - public static RepositoryFixture getH2MK(File base, long cacheSize) { - return new OakRepositoryFixture(OakFixture.getH2MK(base, cacheSize)); + private static RepositoryFixture getMemory(String name, long cacheSize) { + return new OakRepositoryFixture(OakFixture.getMemory(name, cacheSize)); } public static RepositoryFixture getMongo(String host, int port, String database, Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/model/ChildNodeEntries.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/model/ChildNodeEntries.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/model/ChildNodeEntries.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,82 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.model; - -import org.apache.jackrabbit.mk.store.Binding; -import org.apache.jackrabbit.mk.store.CacheObject; - -import java.util.Iterator; - -/** - * - */ -public interface ChildNodeEntries extends Cloneable, CacheObject { - - static final int CAPACITY_THRESHOLD = 1000; - - Object clone(); - - boolean inlined(); - - //-------------------------------------------------------------< read ops > - - int getCount(); - - ChildNodeEntry get(String name); - - Iterator getNames(int offset, int count); - - Iterator getEntries(int offset, int count); - - //------------------------------------------------------------< write ops > - - ChildNodeEntry add(ChildNodeEntry entry); - - ChildNodeEntry remove(String name); - - ChildNodeEntry rename(String oldName, String newName); - - //-------------------------------------------------------------< diff ops > - - /** - * Returns those entries that exist in {@code other} but not in - * {@code this}. - * - * @param other - */ - Iterator getAdded(final ChildNodeEntries other); - - /** - * Returns those entries that exist in {@code this} but not in - * {@code other}. - * - * @param other - */ - Iterator getRemoved(final ChildNodeEntries other); - - /** - * Returns {@code this} instance's entries that have namesakes in - * {@code other} but with different {@code id}s. - * - * @param other - */ - Iterator getModified(final ChildNodeEntries other); - - //------------------------------------------------< serialization support > - - void serialize(Binding binding) throws Exception; -} Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/htree/HashBucket.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/htree/HashBucket.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/htree/HashBucket.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.htree; - -import org.apache.jackrabbit.mk.model.ChildNodeEntriesMap; - -/** - * Leaf node structure in an HTree. - */ -class HashBucket extends ChildNodeEntriesMap { - - public HashBucket() { - } - - public HashBucket(ChildNodeEntriesMap other) { - super(other); - } -} Index: oak-doc/src/site/markdown/dev_getting_started.md IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-doc/src/site/markdown/dev_getting_started.md (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-doc/src/site/markdown/dev_getting_started.md (revision ) @@ -63,7 +63,6 @@ - oak-doc - Oak documentation - oak-commons - shared utility code - oak-mk-api - MicroKernel API - - oak-mk - default MicroKernel implementation - oak-mk-remote - MicroKernel remoting - [oak-core][1] - Oak repository API and implementation - oak-jcr - JCR binding for the Oak repository Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/store/PersistHook.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/store/PersistHook.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/store/PersistHook.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,26 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.store; - -/** - * - */ -public interface PersistHook { - - void prePersist(RevisionStore store, RevisionStore.PutToken token) throws Exception; - void postPersist(RevisionStore store, RevisionStore.PutToken token) throws Exception; -} Index: oak-it/osgi/pom.xml IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-it/osgi/pom.xml (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-it/osgi/pom.xml (revision ) @@ -83,12 +83,6 @@ org.apache.jackrabbit - oak-mk - ${project.version} - test - - - org.apache.jackrabbit oak-mk-remote ${project.version} test Index: oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelBlob.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelBlob.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelBlob.java (revision ) @@ -16,11 +16,12 @@ */ package org.apache.jackrabbit.oak.kernel; -import java.io.IOException; import java.io.InputStream; + import javax.annotation.Nonnull; import org.apache.jackrabbit.mk.api.MicroKernel; +import org.apache.jackrabbit.oak.commons.mk.MicroKernelInputStream; import org.apache.jackrabbit.oak.plugins.memory.AbstractBlob; /** @@ -89,54 +90,5 @@ } return super.equals(other); - } - - private static class MicroKernelInputStream extends InputStream { - - private final MicroKernel mk; - private final String id; - private long pos; - private long length = -1; - private byte[] oneByteBuff; - - public MicroKernelInputStream(MicroKernel mk, String id) { - this.mk = mk; - this.id = id; - } - - @Override - public long skip(long n) { - if (n < 0) { - return 0; - } - if (length == -1) { - length = mk.getLength(id); - } - n = Math.min(n, length - pos); - pos += n; - return n; - } - - @Override - public int read(byte[] b, int off, int len) { - int l = mk.read(id, pos, b, off, len); - if (l < 0) { - return l; - } - pos += l; - return l; - } - - @Override - public int read() throws IOException { - if (oneByteBuff == null) { - oneByteBuff = new byte[1]; - } - int len = read(oneByteBuff, 0, 1); - if (len < 0) { - return len; - } - return oneByteBuff[0] & 0xff; - } } } Index: oak-run/src/main/java/org/apache/jackrabbit/oak/run/MicroKernelServer.java =================================================================== --- oak-run/src/main/java/org/apache/jackrabbit/oak/run/MicroKernelServer.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-run/src/main/java/org/apache/jackrabbit/oak/run/MicroKernelServer.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.oak.run; - -import java.net.InetAddress; - -import org.apache.jackrabbit.mk.core.MicroKernelImpl; -import org.apache.jackrabbit.mk.server.Server; - -public class MicroKernelServer { - - public static void main(String[] args) throws Exception { - if (args.length == 0) { - System.out.format("usage: %s /path/to/mk [port] [bindaddr]%n", - MicroKernelServer.class.getName()); - return; - } - - final MicroKernelImpl mk = new MicroKernelImpl(args[0]); - - final Server server = new Server(mk); - if (args.length >= 2) { - server.setPort(Integer.parseInt(args[1])); - } else { - server.setPort(28080); - } - if (args.length >= 3) { - server.setBindAddress(InetAddress.getByName(args[2])); - } - server.start(); - - Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { - @Override - public void run() { - server.stop(); - mk.dispose(); - } - }, "ShutdownHook")); - } - -} Index: oak-mk/src/test/resources/logback-test.xml =================================================================== --- oak-mk/src/test/resources/logback-test.xml (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/test/resources/logback-test.xml (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,39 +0,0 @@ - - - - - - %date{HH:mm:ss.SSS} %-5level %-40([%thread] %F:%L) %msg%n - - - - - target/unit-tests.log - - %date{HH:mm:ss.SSS} %-5level %-40([%thread] %F:%L) %msg%n - - - - - - - - - Index: oak-mk/src/test/java/org/apache/jackrabbit/mk/util/CommitGateIT.java =================================================================== --- oak-mk/src/test/java/org/apache/jackrabbit/mk/util/CommitGateIT.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/test/java/org/apache/jackrabbit/mk/util/CommitGateIT.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,80 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.util; - -import junit.framework.TestCase; - -import java.util.concurrent.atomic.AtomicLong; - -/** - * Test the commit gate. - */ -public class CommitGateIT extends TestCase { - - public void test() throws InterruptedException { - final CommitGate gate = new CommitGate(); - gate.commit("start"); - final AtomicLong tick = new AtomicLong(); - final AtomicLong spurious = new AtomicLong(); - final int waitMillis = 10; - int threadCount = 10; - Thread[] threads = new Thread[threadCount]; - for (int i = 0; i < 10; i++) { - Thread t = threads[i] = new Thread() { - public void run() { - String head = null; - while (true) { - String nh; - try { - nh = gate.waitForCommit(head, waitMillis); - if (nh.equals(head)) { - spurious.incrementAndGet(); - } else { - tick.incrementAndGet(); - } - head = nh; - if (head.equals("end")) { - break; - } - } catch (InterruptedException e) { - // ignore - } - } - } - }; - t.start(); - } - Thread.sleep(waitMillis * 10); - // assertTrue(threadCount < spurious.get()); <- depends on timing - assertEquals(10, tick.get()); - tick.set(0); - spurious.set(0); - int commitCount = 100; - for (int i = 0; i < commitCount; i++) { - gate.commit(Integer.toString(i)); - Thread.sleep(1); - } - gate.commit("end"); - for (Thread j : threads) { - j.join(); - } - // disabled: depends on timing - // assertTrue("ticks: " + tick.get() + " min: " + threadCount * commitCount + " spurious: " + spurious.get(), - // tick.get() >= threadCount * commitCount * 0.2 && tick.get() <= threadCount * commitCount * 1.2); - } - -} Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/util/NameFilter.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/util/NameFilter.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/util/NameFilter.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,192 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.util; - -import java.util.ArrayList; -import java.util.List; - -/** - * Simple name filter utility class. - *

- * Examples: - *

- * {@code ["foo*", "-foo99"]} matches {@code "foo"} and {@code "foo bar"} - * but not {@code "foo99"}. - *

- * {@code ["foo\*"]} matches {@code "foo*"} but not {@code "foo99"}. - *

- * {@code ["\-blah"]} matches {@code "-blah"}. - */ -public class NameFilter { - - public static final char WILDCARD = '*'; - public static final char EXCLUDE_PREFIX = '-'; - public static final char ESCAPE = '\\'; - - // list of ORed inclusion patterns - private final List inclPatterns = new ArrayList(); - - // list of ORed exclusion patterns - private final List exclPatterns = new ArrayList(); - - private boolean containsWildcard; - - public NameFilter(String[] patterns) { - containsWildcard = false; - for (String pattern : patterns) { - if (pattern.isEmpty()) { - continue; - } else if (pattern.charAt(0) == EXCLUDE_PREFIX) { - pattern = pattern.substring(1); - exclPatterns.add(pattern); - } else { - inclPatterns.add(pattern); - } - if (!containsWildcard) { - containsWildcard = containsWildCard(pattern); - } - } - } - - public boolean matches(String name) { - boolean matched = false; - // check inclusion patterns - for (String pattern : inclPatterns) { - if (internalMatches(name, pattern, 0, 0)) { - matched = true; - break; - } - } - if (matched) { - // check exclusion patterns - for (String pattern : exclPatterns) { - if (internalMatches(name, pattern, 0, 0)) { - matched = false; - break; - } - } - } - return matched; - } - - public boolean containsWildcard() { - return containsWildcard; - } - - public List getExclusionPatterns() { - return exclPatterns; - } - - public List getInclusionPatterns() { - return inclPatterns; - } - - private static boolean containsWildCard(String pattern) { - int len = pattern.length(); - int pos = 0; - while (pos < len) { - if (pattern.charAt(pos) == ESCAPE - && pos < (len - 1) - && pattern.charAt(pos + 1) == WILDCARD) { - pos += 2; - continue; - } - if (pattern.charAt(pos) == WILDCARD) { - return true; - } - pos++; - } - return false; - } - - /** - * Internal helper used to recursively match the pattern - * - * @param s The string to be tested - * @param pattern The pattern - * @param sOff offset within s - * @param pOff offset within pattern. - * @return true if s matched pattern, else false. - */ - private static boolean internalMatches(String s, String pattern, - int sOff, int pOff) { - int pLen = pattern.length(); - int sLen = s.length(); - - while (true) { - if (pOff >= pLen) { - return sOff >= sLen ? true : false; - } - if (sOff >= sLen && pattern.charAt(pOff) != WILDCARD) { - return false; - } - - // check for a WILDCARD as the next pattern; - // this is handled by a recursive call for - // each postfix of the name. - if (pattern.charAt(pOff) == WILDCARD) { - ++pOff; - if (pOff >= pLen) { - return true; - } - - while (true) { - if (internalMatches(s, pattern, sOff, pOff)) { - return true; - } - if (sOff >= sLen) { - return false; - } - sOff++; - } - } - - if (pOff < pLen && sOff < sLen) { - // check for escape sequences - if (pattern.charAt(pOff) == ESCAPE) { - // * to be interpreted as literal - if (pOff < pLen - 1 - && pattern.charAt(pOff + 1) == WILDCARD) { - ++pOff; - } - // leading - to be interpreted as literal - if (pOff == 0 && pLen > 1 - && pattern.charAt(pOff + 1) == EXCLUDE_PREFIX) { - ++pOff; - } - } - if (pattern.charAt(pOff) != s.charAt(sOff)) { - return false; - } - } - pOff++; - sOff++; - } - } -} Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/model/StoredNode.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/model/StoredNode.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/model/StoredNode.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,73 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.model; - -import org.apache.jackrabbit.mk.store.Binding; -import org.apache.jackrabbit.mk.store.RevisionProvider; -import org.apache.jackrabbit.mk.util.UnmodifiableIterator; - -import java.util.Collections; -import java.util.Iterator; -import java.util.Map; - -/** - * - */ -public class StoredNode extends AbstractNode { - - private final Id id; - - public StoredNode(Id id, RevisionProvider provider) { - super(provider); - this.id = id; - } - - public StoredNode(Id id, Node node, RevisionProvider provider) { - super(node, provider); - this.id = id; - } - - public Id getId() { - return id; - } - - public Map getProperties() { - return Collections.unmodifiableMap(properties); - } - - public Iterator getChildNodeEntries(int offset, int count) { - return new UnmodifiableIterator(super.getChildNodeEntries(offset, count)); - } - - public Iterator getChildNodeNames(int offset, int count) { - return new UnmodifiableIterator(super.getChildNodeNames(offset, count)); - } - - public void deserialize(Binding binding) throws Exception { - Binding.StringEntryIterator iter = binding.readStringMap(":props"); - while (iter.hasNext()) { - Binding.StringEntry entry = iter.next(); - properties.put(entry.getKey(), entry.getValue()); - } - boolean inlined = binding.readIntValue(":inlined") != 0; - if (inlined) { - childEntries = ChildNodeEntriesMap.deserialize(binding); - } else { - childEntries = ChildNodeEntriesTree.deserialize(provider, binding); - } - } -} Index: oak-core/pom.xml IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/pom.xml (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-core/pom.xml (revision ) @@ -332,12 +332,6 @@ test - org.apache.jackrabbit - oak-mk - ${project.version} - test - - com.h2database h2 ${h2.version} Index: oak-run/src/main/java/org/apache/jackrabbit/oak/run/Main.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-run/src/main/java/org/apache/jackrabbit/oak/run/Main.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-run/src/main/java/org/apache/jackrabbit/oak/run/Main.java (revision ) @@ -16,6 +16,9 @@ */ package org.apache.jackrabbit.oak.run; +import static com.google.common.collect.Sets.newHashSet; +import static java.util.Arrays.asList; + import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -38,11 +41,9 @@ import com.google.common.collect.Queues; import com.mongodb.MongoClient; import com.mongodb.MongoClientURI; - import joptsimple.OptionParser; import joptsimple.OptionSet; import joptsimple.OptionSpec; - import org.apache.jackrabbit.core.RepositoryContext; import org.apache.jackrabbit.core.config.RepositoryConfig; import org.apache.jackrabbit.oak.Oak; @@ -80,9 +81,6 @@ import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; -import static com.google.common.collect.Sets.newHashSet; -import static java.util.Arrays.asList; - public class Main { public static final int PORT = 8080; @@ -452,13 +450,7 @@ int cacheSize = cache.value(options); List cIds = Collections.emptyList(); if (fix.startsWith(OakFixture.OAK_MEMORY)) { - if (OakFixture.OAK_MEMORY_NS.equals(fix)) { - oakFixture = OakFixture.getMemoryNS(cacheSize * MB); - } else if (OakFixture.OAK_MEMORY_MK.equals(fix)) { - oakFixture = OakFixture.getMemoryMK(cacheSize * MB); - } else { - oakFixture = OakFixture.getMemory(cacheSize * MB); + oakFixture = OakFixture.getMemory(cacheSize * MB); - } } else if (fix.startsWith(OakFixture.OAK_MONGO)) { cIds = clusterIds.values(options); String db = dbName.value(options); @@ -486,12 +478,6 @@ throw new IllegalArgumentException("Required argument base missing."); } oakFixture = OakFixture.getTar(OakFixture.OAK_TAR, baseFile, 256, cacheSize, mmap.value(options), false); - } else if (fix.equals(OakFixture.OAK_H2)) { - File baseFile = base.value(options); - if (baseFile == null) { - throw new IllegalArgumentException("Required argument base missing."); - } - oakFixture = OakFixture.getH2MK(baseFile, cacheSize * MB); } else { throw new IllegalArgumentException("Unsupported repository setup " + fix); } Index: oak-mk/src/test/java/org/apache/jackrabbit/mk/model/IdTest.java =================================================================== --- oak-mk/src/test/java/org/apache/jackrabbit/mk/model/IdTest.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/test/java/org/apache/jackrabbit/mk/model/IdTest.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.model; - -import org.junit.Test; - -import static org.junit.Assert.assertTrue; - -public class IdTest { - - @Test - public void idCompareToEqualsTest() { - final Id id1 = Id.fromString("00000000000002cc"); - final Id id2 = Id.fromString("00000000000002cc"); - - assertTrue(id1 + " should be equals to " + id2, id1.compareTo(id2) == 0); - } - - @Test - public void idCompareToGreaterThanOneDigitTest() { - final Id id1 = Id.fromString("0000000000000007"); - final Id id2 = Id.fromString("000000000000000c"); - - assertTrue(id1 + " should be less than " + id2, id1.compareTo(id2) < 0); - } - - @Test - public void idCompareToGreaterThanOneByteTest() { - final Id id1 = Id.fromString("0000000000000070"); - final Id id2 = Id.fromString("00000000000000c0"); - - assertTrue(id1 + " should be less than " + id2, id1.compareTo(id2) < 0); - } - - @Test - public void idCompareToGreaterThanTwoBytesTest() { - final Id id1 = Id.fromString("0000000000000270"); - final Id id2 = Id.fromString("00000000000002c0"); - - assertTrue(id1 + " should be less than " + id2, id1.compareTo(id2) < 0); - } -} \ No newline at end of file Index: oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/blob/DocumentMKReadTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/blob/DocumentMKReadTest.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/blob/DocumentMKReadTest.java (revision ) @@ -21,7 +21,7 @@ import junit.framework.Assert; -import org.apache.jackrabbit.mk.util.MicroKernelInputStream; +import org.apache.jackrabbit.oak.commons.mk.MicroKernelInputStream; import org.apache.jackrabbit.oak.plugins.document.AbstractMongoConnectionTest; import org.junit.Test; \ No newline at end of file Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/util/AbstractRangeIterator.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/util/AbstractRangeIterator.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/util/AbstractRangeIterator.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.util; - -import java.util.Iterator; -import java.util.NoSuchElementException; - -/** - * - */ -public abstract class AbstractRangeIterator implements Iterator { - - protected final Iterator it; - protected int maxCount; - - public AbstractRangeIterator(Iterator it, int offset, int count) { - while (offset-- > 0 && it.hasNext()) { - it.next(); - } - maxCount = count < 0 ? Integer.MAX_VALUE : count; - this.it = it; - } - - public boolean hasNext() { - return (maxCount > 0 && it.hasNext()); - } - - public T next() { - if (maxCount-- > 0) { - return doNext(); - } - throw new NoSuchElementException(); - } - - public void remove() { - throw new UnsupportedOperationException(); - } - - protected abstract T doNext(); -} Index: oak-it/mk/src/main/java/org/apache/jackrabbit/mk/test/MicroKernelIT.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-it/mk/src/main/java/org/apache/jackrabbit/mk/test/MicroKernelIT.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-it/mk/src/main/java/org/apache/jackrabbit/mk/test/MicroKernelIT.java (revision ) @@ -34,7 +34,7 @@ import org.apache.jackrabbit.mk.api.MicroKernelException; import org.apache.jackrabbit.mk.test.util.TestInputStream; -import org.apache.jackrabbit.mk.util.MicroKernelInputStream; +import org.apache.jackrabbit.oak.commons.mk.MicroKernelInputStream; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.junit.Test; Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/model/Node.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/model/Node.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/model/Node.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.model; - -import org.apache.jackrabbit.mk.store.Binding; - -import java.util.Iterator; -import java.util.Map; - -/** - * - */ -public interface Node { - - Map getProperties(); - - ChildNodeEntry getChildNodeEntry(String name); - - Iterator getChildNodeNames(int offset, int count); - int getChildNodeCount(); - - Iterator getChildNodeEntries(int offset, int count); - - void diff(Node other, NodeDiffHandler handler); - - void serialize(Binding binding) throws Exception; -} Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/H2Persistence.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/H2Persistence.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/H2Persistence.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,381 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.persistence; - -import org.apache.jackrabbit.mk.model.ChildNodeEntries; -import org.apache.jackrabbit.mk.model.ChildNodeEntriesMap; -import org.apache.jackrabbit.mk.model.Commit; -import org.apache.jackrabbit.mk.model.Id; -import org.apache.jackrabbit.mk.model.Node; -import org.apache.jackrabbit.mk.model.StoredCommit; -import org.apache.jackrabbit.mk.model.StoredNode; -import org.apache.jackrabbit.mk.store.BinaryBinding; -import org.apache.jackrabbit.mk.store.IdFactory; -import org.apache.jackrabbit.mk.store.NotFoundException; -import org.h2.Driver; -import org.h2.jdbcx.JdbcConnectionPool; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.Statement; -import java.sql.Timestamp; - -/** - * - */ -public class H2Persistence implements GCPersistence { - - private static final boolean FAST = Boolean.getBoolean("mk.fastDb"); - - private JdbcConnectionPool cp; - private long gcStart; - - // TODO: make this configurable - private IdFactory idFactory = IdFactory.getDigestFactory(); - - //---------------------------------------------------< Persistence > - - public void initialize(File homeDir) throws Exception { - File dbDir = new File(homeDir, "db"); - if (!dbDir.exists()) { - dbDir.mkdirs(); - } - - Driver.load(); - String url = "jdbc:h2:" + dbDir.getCanonicalPath() + "/revs"; - if (FAST) { - url += ";log=0;undo_log=0"; - } - cp = JdbcConnectionPool.create(url, "sa", ""); - cp.setMaxConnections(40); - Connection con = cp.getConnection(); - try { - Statement stmt = con.createStatement(); - stmt.execute("create table if not exists REVS(ID binary primary key, DATA binary, TIME timestamp)"); - stmt.execute("create table if not exists NODES(ID binary primary key, DATA binary, TIME timestamp)"); - stmt.execute("create table if not exists HEAD(ID binary) as select null"); - stmt.execute("create sequence if not exists DATASTORE_ID"); -/* - DbBlobStore store = new DbBlobStore(); - store.setConnectionPool(cp); - blobStore = store; -*/ - } finally { - con.close(); - } - } - - public void close() { - cp.dispose(); - } - - public Id[] readIds() throws Exception { - Id lastCommitId = null; - Id headId = readHead(); - if (headId != null) { - lastCommitId = readLastCommitId(); - } - return new Id[] { headId, lastCommitId }; - } - - private Id readHead() throws Exception { - Connection con = cp.getConnection(); - try { - PreparedStatement stmt = con.prepareStatement("select * from HEAD"); - ResultSet rs = stmt.executeQuery(); - byte[] rawId = null; - if (rs.next()) { - rawId = rs.getBytes(1); - } - stmt.close(); - return rawId == null ? null : new Id(rawId); - } finally { - con.close(); - } - } - - private Id readLastCommitId() throws Exception { - Connection con = cp.getConnection(); - try { - PreparedStatement stmt = con.prepareStatement("select MAX(ID) from REVS"); - ResultSet rs = stmt.executeQuery(); - byte[] rawId = null; - if (rs.next()) { - rawId = rs.getBytes(1); - } - stmt.close(); - return rawId == null ? null : new Id(rawId); - } finally { - con.close(); - } - } - - public void writeHead(Id id) throws Exception { - Connection con = cp.getConnection(); - try { - PreparedStatement stmt = con.prepareStatement("update HEAD set ID=?"); - stmt.setBytes(1, id.getBytes()); - stmt.execute(); - stmt.close(); - } finally { - con.close(); - } - } - - public void readNode(StoredNode node) throws NotFoundException, Exception { - Id id = node.getId(); - Connection con = cp.getConnection(); - try { - PreparedStatement stmt = con.prepareStatement("select DATA from NODES where ID = ?"); - try { - stmt.setBytes(1, id.getBytes()); - ResultSet rs = stmt.executeQuery(); - if (rs.next()) { - ByteArrayInputStream in = new ByteArrayInputStream(rs.getBytes(1)); - node.deserialize(new BinaryBinding(in)); - } else { - throw new NotFoundException(id.toString()); - } - } finally { - stmt.close(); - } - } finally { - con.close(); - } - } - - public Id writeNode(Node node) throws Exception { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - node.serialize(new BinaryBinding(out)); - byte[] bytes = out.toByteArray(); - byte[] rawId = idFactory.createContentId(bytes); - Timestamp ts = new Timestamp(System.currentTimeMillis()); - //String id = StringUtils.convertBytesToHex(rawId); - - Connection con = cp.getConnection(); - try { - PreparedStatement stmt = con - .prepareStatement( - "insert into NODES (ID, DATA, TIME) select ?, ?, ? where not exists (select 1 from NODES where ID = ?)"); - try { - stmt.setBytes(1, rawId); - stmt.setBytes(2, bytes); - stmt.setTimestamp(3, ts); - stmt.setBytes(4, rawId); - stmt.executeUpdate(); - } finally { - stmt.close(); - } - } finally { - con.close(); - } - return new Id(rawId); - } - - public StoredCommit readCommit(Id id) throws NotFoundException, Exception { - Connection con = cp.getConnection(); - try { - PreparedStatement stmt = con.prepareStatement("select DATA from REVS where ID = ?"); - try { - stmt.setBytes(1, id.getBytes()); - ResultSet rs = stmt.executeQuery(); - if (rs.next()) { - ByteArrayInputStream in = new ByteArrayInputStream(rs.getBytes(1)); - return StoredCommit.deserialize(id, new BinaryBinding(in)); - } else { - throw new NotFoundException(id.toString()); - } - } finally { - stmt.close(); - } - } finally { - con.close(); - } - } - - public void writeCommit(Id id, Commit commit) throws Exception { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - commit.serialize(new BinaryBinding(out)); - byte[] bytes = out.toByteArray(); - Timestamp ts = new Timestamp(System.currentTimeMillis()); - - Connection con = cp.getConnection(); - try { - PreparedStatement stmt = con - .prepareStatement( - "insert into REVS (ID, DATA, TIME) select ?, ?, ?"); - try { - stmt.setBytes(1, id.getBytes()); - stmt.setBytes(2, bytes); - stmt.setTimestamp(3, ts); - stmt.executeUpdate(); - } finally { - stmt.close(); - } - } finally { - con.close(); - } - } - - private static final NotFoundException NFE = new NotFoundException(); - - public ChildNodeEntriesMap readCNEMap(Id id) throws NotFoundException, Exception { - Connection con = cp.getConnection(); - try { - PreparedStatement stmt = con.prepareStatement("select DATA from NODES where ID = ?"); - try { - stmt.setBytes(1, id.getBytes()); - ResultSet rs = stmt.executeQuery(); - if (rs.next()) { - ByteArrayInputStream in = new ByteArrayInputStream(rs.getBytes(1)); - return ChildNodeEntriesMap.deserialize(new BinaryBinding(in)); - } else { - throw NFE; // new NotFoundException(id.toString()); - } - } finally { - stmt.close(); - } - } finally { - con.close(); - } - } - - public Id writeCNEMap(ChildNodeEntries map) throws Exception { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - map.serialize(new BinaryBinding(out)); - byte[] bytes = out.toByteArray(); - byte[] rawId = idFactory.createContentId(bytes); - Timestamp ts = new Timestamp(System.currentTimeMillis()); - - Connection con = cp.getConnection(); - try { - PreparedStatement stmt = con - .prepareStatement( - "insert into NODES (ID, DATA, TIME) select ?, ?, ? where not exists (select 1 from NODES where ID = ?)"); - try { - stmt.setBytes(1, rawId); - stmt.setBytes(2, bytes); - stmt.setTimestamp(3, ts); - stmt.setBytes(4, rawId); - stmt.executeUpdate(); - } finally { - stmt.close(); - } - } finally { - con.close(); - } - return new Id(rawId); - } - - @Override - public void start() { - gcStart = System.currentTimeMillis(); - } - - @Override - public boolean markCommit(Id id) throws Exception { - return touch("REVS", id, gcStart); - } - - @Override - public void replaceCommit(Id id, Commit commit) throws Exception { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - commit.serialize(new BinaryBinding(out)); - byte[] bytes = out.toByteArray(); - - Connection con = cp.getConnection(); - try { - PreparedStatement stmt = con - .prepareStatement( - "update REVS set DATA = ?, TIME = CURRENT_TIMESTAMP() where ID = ?"); - try { - stmt.setBytes(1, bytes); - stmt.setBytes(2, id.getBytes()); - stmt.executeUpdate(); - } finally { - stmt.close(); - } - } finally { - con.close(); - } - } - - @Override - public boolean markNode(Id id) throws Exception { - return touch("NODES", id, gcStart); - } - - @Override - public boolean markCNEMap(Id id) throws Exception { - return touch("NODES", id, gcStart); - } - - private boolean touch(String table, Id id, long timeMillis) throws Exception { - Timestamp ts = new Timestamp(timeMillis); - - Connection con = cp.getConnection(); - try { - PreparedStatement stmt = con.prepareStatement( - String.format("update %s set TIME = ? where ID = ? and TIME < ?", - table)); - - try { - stmt.setTimestamp(1, ts); - stmt.setBytes(2, id.getBytes()); - stmt.setTimestamp(3, ts); - return stmt.executeUpdate() == 1; - } finally { - stmt.close(); - } - } finally { - con.close(); - } - } - - @Override - public int sweep() throws Exception { - Timestamp ts = new Timestamp(gcStart); - int swept = 0; - - Connection con = cp.getConnection(); - try { - PreparedStatement stmt = con.prepareStatement("delete REVS where TIME < ?"); - try { - stmt.setTimestamp(1, ts); - swept += stmt.executeUpdate(); - } finally { - stmt.close(); - } - - stmt = con.prepareStatement("delete NODES where TIME < ?"); - - try { - stmt.setTimestamp(1, ts); - swept += stmt.executeUpdate(); - } finally { - stmt.close(); - } - } finally { - con.close(); - } - return swept; - } -} \ No newline at end of file Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/GCPersistence.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/GCPersistence.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/GCPersistence.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,90 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.persistence; - -import org.apache.jackrabbit.mk.model.Commit; -import org.apache.jackrabbit.mk.model.Id; - -/** - * Advanced persistence implementation offering GC support. - *

- * The persistence implementation must ensure that objects written between {@link #start()} - * and {@link #sweep()} are not swept, in other words, they must be marked implicitely. - */ -public interface GCPersistence extends Persistence { - - /** - * Start a GC cycle. All objects written to the persistence in subsequent calls are - * marked implicitely, i.e. they must be retained on {@link #sweep()}. - */ - void start(); - - /** - * Mark a commit. - * - * @param id - * commit id - * @return {@code true} if the commit was not marked before; - * {@code false} otherwise - * - * @throws Exception if an error occurs - */ - boolean markCommit(Id id) throws Exception; - - /** - * Replace a commit. Introduced to replace dangling parent commits where - * a parent commit might be collected. - * - * @param id commit id - * @param commit the commit - * - * @throws Exception if an error occurs - */ - void replaceCommit(Id id, Commit commit) throws Exception; - - /** - * Mark a node. - * - * @param id - * node id - * @return {@code true} if the node was not marked before; - * {@code false} otherwise - * - * @throws Exception if an error occurs - */ - boolean markNode(Id id) throws Exception; - - /** - * Mark a child node entry map. - * - * @param id - * child node entry map id - * @return {@code true} if the child node entry map was not marked before; - * {@code false} otherwise - * - * @throws Exception if an error occurs - */ - boolean markCNEMap(Id id) throws Exception; - - /** - * Sweep all objects that are not marked and were written before the GC started. - * - * @return number of swept items or -1 if number is unknown - * @throws Exception if an error occurs - */ - int sweep() throws Exception; -} Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/util/RangeIterator.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/util/RangeIterator.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/util/RangeIterator.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.util; - -import java.util.Iterator; - -/** - * - */ -public class RangeIterator extends AbstractRangeIterator { - - public RangeIterator(Iterator it, int offset, int count) { - super(it, offset, count); - } - - @Override - protected T doNext() { - return (T) it.next(); - } -} \ No newline at end of file Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/store/RevisionProvider.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/store/RevisionProvider.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/store/RevisionProvider.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.store; - -import org.apache.jackrabbit.mk.model.ChildNodeEntriesMap; -import org.apache.jackrabbit.mk.model.Id; -import org.apache.jackrabbit.mk.model.StoredCommit; -import org.apache.jackrabbit.mk.model.StoredNode; - -/** - * Read operations. - */ -public interface RevisionProvider { - StoredNode getNode(Id id) throws NotFoundException, Exception; - StoredCommit getCommit(Id id) throws NotFoundException, Exception; - ChildNodeEntriesMap getCNEMap(Id id) throws NotFoundException, Exception; - StoredNode getRootNode(Id commitId) throws NotFoundException, Exception; - StoredCommit getHeadCommit() throws Exception; - Id getHeadCommitId() throws Exception; -} Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/model/Commit.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/model/Commit.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/model/Commit.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.model; - -import org.apache.jackrabbit.mk.store.Binding; - -/** - * - */ -public interface Commit { - - Id getRootNodeId(); - - Id getParentId(); - - long getCommitTS(); - - String getMsg(); - - String getChanges(); - - /** - * Returns {@code null} if this commit does not represent a branch. - *

- * Otherwise, returns the id of the branch root commit - * (i.e. the public commit that this private branch is based upon). - * - * - * @return the id of the branch root commit or {@code null} if this commit - * does not represent a branch. - */ - Id getBranchRootId(); - - void serialize(Binding binding) throws Exception; -} Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/htree/HashDirectory.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/htree/HashDirectory.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/htree/HashDirectory.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,663 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.htree; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.NoSuchElementException; - -import org.apache.jackrabbit.mk.model.ChildNodeEntries; -import org.apache.jackrabbit.mk.model.ChildNodeEntry; -import org.apache.jackrabbit.mk.model.Id; -import org.apache.jackrabbit.mk.store.Binding; -import org.apache.jackrabbit.mk.store.RevisionProvider; -import org.apache.jackrabbit.mk.store.RevisionStore; -import org.apache.jackrabbit.mk.store.RevisionStore.PutToken; - -/** - * Directory structure in an HTree. - */ -class HashDirectory implements ChildNodeEntries { - - private static final List EMPTY = Collections.emptyList(); - private static final int MAX_CHILDREN = 256; - private static final int BIT_SIZE = 8; - private static final int MAX_DEPTH = 3; - - private final RevisionProvider provider; - private final int depth; - private int count; - private IndexEntry[] index = new IndexEntry[MAX_CHILDREN]; - - public HashDirectory(RevisionProvider provider, int depth) { - this.provider = provider; - this.depth = depth; - } - - public HashDirectory(HashDirectory other) { - provider = other.provider; - depth = other.depth; - count = other.count; - index = other.index.clone(); - } - - @Override - public Object clone() { - HashDirectory clone = null; - try { - clone = (HashDirectory) super.clone(); - } catch (CloneNotSupportedException e) { - // can't possibly get here - } - // shallow clone of array of immutable IndexEntry objects - clone.index = index.clone(); - return clone; - } - - public int getCount() { - return count; - } - - public ChildNodeEntry get(String name) { - int hash = hashCode(name); - - IndexEntry ie = index[hash]; - if (ie == null) { - return null; - } - if (ie instanceof ChildNodeEntry) { - ChildNodeEntry cne = (ChildNodeEntry) ie; - return cne.getName().equals(name) ? cne : null; - } - ChildNodeEntries container = ((ContainerEntry) ie).getContainer(); - if (container != null) { - return container.get(name); - } - return null; - } - - public Iterator getEntries(int offset, int count) { - if (offset < 0 || count < -1) { - throw new IllegalArgumentException(); - } - - if (offset >= this.count || count == 0) { - return EMPTY.iterator(); - } - - int skipped = 0; - if (count == -1 || (offset + count) > this.count) { - count = this.count - offset; - } - ArrayList list = new ArrayList(count); - for (IndexEntry ie : index) { - if (ie == null) { - continue; - } - if (skipped + ie.getSize() <= offset) { - skipped += ie.getSize(); - continue; - } - if (ie instanceof ChildNodeEntry) { - list.add((ChildNodeEntry) ie); - } else { - ChildNodeEntries container = ((ContainerEntry) ie).getContainer(); - if (container != null) { - for (Iterator it = container.getEntries(offset - skipped, count - list.size()); - it.hasNext(); ) { - list.add(it.next()); - } - skipped = offset; - } - if (list.size() == count) { - break; - } - } - } - return list.iterator(); - } - - public ChildNodeEntry add(ChildNodeEntry entry) { - int hash = hashCode(entry.getName()); - IndexEntry ie = index[hash]; - if (ie == null) { - index[hash] = new NodeEntry(entry.getName(), entry.getId()); - count++; - return null; - } - if (ie instanceof ChildNodeEntry) { - ChildNodeEntry existing = (ChildNodeEntry) ie; - if (existing.getName().equals(entry.getName())) { - index[hash] = new NodeEntry(entry.getName(), entry.getId()); - return existing; - } else { - ContainerEntry ce = createContainerEntry(); - ce.getContainer().add(existing); - ce.getContainer().add(entry); - index[hash] = ce; - count++; - return null; - } - } - ContainerEntry ce = (ContainerEntry) ie; - ChildNodeEntries container = ce.getContainer(); - ChildNodeEntry existing = container.add(entry); - if (entry.equals(existing)) { - // no-op - return existing; - } - ce.setDirty(container); - if (existing == null) { - // new entry - count++; - } - return existing; - } - - public ChildNodeEntry remove(String name) { - int hash = hashCode(name); - IndexEntry ie = index[hash]; - if (ie == null) { - return null; - } - if (ie instanceof ChildNodeEntry) { - ChildNodeEntry existing = (ChildNodeEntry) ie; - if (existing.getName().equals(name)) { - index[hash] = null; - count--; - return existing; - } else { - return null; - } - } - ContainerEntry ce = (ContainerEntry) ie; - ChildNodeEntries container = ce.getContainer(); - ChildNodeEntry existing = container.remove(name); - if (existing == null) { - return null; - } - if (container.getCount() == 0) { - index[hash] = null; - } else if (container.getCount() == 1) { - // inline single remaining entry - ChildNodeEntry remaining = container.getEntries(0, 1).next(); - index[hash] = new NodeEntry(remaining.getName(), remaining.getId()); - } else { - ce.setDirty(container); - } - count--; - return existing; - } - - public Iterator getAdded(ChildNodeEntries otherContainer) { - if (!(otherContainer instanceof HashDirectory)) { - // needs no implementation - return null; - } - - HashDirectory other = (HashDirectory) otherContainer; - List added = new ArrayList(); - for (int i = 0; i < index.length; i++) { - IndexEntry ie1 = index[i]; - IndexEntry ie2 = other.index[i]; - - if (ie1 == null && ie2 == null || (ie1 != null && ie1.equals(ie2))) { - continue; - } - - // index entries aren't equal - if (ie1 == null) { - // this index entry in null => other must be non-null, add all its entries - if (ie2 instanceof ChildNodeEntry) { - added.add((ChildNodeEntry) ie2); - } else { - ChildNodeEntries container = ((ContainerEntry) ie2).getContainer(); - for (Iterator it = container.getEntries(0, -1); it.hasNext(); ) { - added.add(it.next()); - } - } - continue; - } - - // optimization for simple child node entries - if (ie1 instanceof ChildNodeEntry && ie2 instanceof ChildNodeEntry) { - ChildNodeEntry cne1 = (ChildNodeEntry) ie1; - ChildNodeEntry cne2 = (ChildNodeEntry) ie2; - - if (cne2.getName().equals(cne1.getName())) { - added.add(cne2); - } - continue; - } - - // all other cases - for (Iterator it = ie1.getAdded(ie2); it.hasNext(); ) { - added.add(it.next()); - } - } - return added.iterator(); - } - - public Iterator getModified(ChildNodeEntries otherContainer) { - if (!(otherContainer instanceof HashDirectory)) { - // needs no implementation - return null; - } - - HashDirectory other = (HashDirectory) otherContainer; - List modified = new ArrayList(); - for (int i = 0; i < index.length; i++) { - IndexEntry ie1 = index[i]; - IndexEntry ie2 = other.index[i]; - - if (ie1 == null || ie2 == null || ie1.equals(ie2)) { - continue; - } - - // optimization for simple child node entries - if (ie1 instanceof ChildNodeEntry && ie2 instanceof ChildNodeEntry) { - ChildNodeEntry cne1 = (ChildNodeEntry) ie1; - ChildNodeEntry cne2 = (ChildNodeEntry) ie2; - - if (cne1.getName().equals(cne2.getName()) && !cne1.getId().equals(cne2.getId())) { - modified.add(cne1); - continue; - } - } - - // all other cases - for (Iterator it = ie1.getModified(ie2); it.hasNext();) { - modified.add(it.next()); - } - } - return modified.iterator(); - } - - private ContainerEntry createContainerEntry() { - return depth < MAX_DEPTH - 1 ? new DirectoryEntry(depth + 1) : new BucketEntry(); - } - - private int hashCode(String name) { - int hashMask = hashMask(); - int hash = name.hashCode(); - hash = hash & hashMask; - hash = hash >>> ((MAX_DEPTH - depth) * BIT_SIZE); - hash = hash % MAX_CHILDREN; - return hash; - } - - int hashMask() { - int bits = MAX_CHILDREN-1; - int hashMask = bits << ((MAX_DEPTH - depth) * BIT_SIZE); - return hashMask; - } - - public void deserialize(Binding binding) throws Exception { - count = binding.readIntValue(":count"); - - Binding.StringEntryIterator iter = binding.readStringMap(":index"); - int pos = -1; - while (iter.hasNext()) { - Binding.StringEntry entry = iter.next(); - ++pos; - // deserialize index array entry - assert(pos == Integer.parseInt(entry.getKey())); - if (entry.getValue().length() == 0) { - // "" - index[pos] = null; - } else { - switch (entry.getValue().charAt(0)) { - case 'n': - String value = entry.getValue().substring(1); - int i = value.indexOf(':'); - String id = value.substring(0, i); - String name = value.substring(i + 1); - index[pos] = new NodeEntry(name, Id.fromString(id)); - break; - case 'b': - value = entry.getValue().substring(1); - i = value.indexOf(':'); - id = value.substring(0, i); - int count = Integer.parseInt(value.substring(i + 1)); - index[pos] = new BucketEntry(provider, Id.fromString(id), count); - break; - case 'd': - value = entry.getValue().substring(1); - i = value.indexOf(':'); - id = value.substring(0, i); - count = Integer.parseInt(value.substring(i + 1)); - index[pos] = new DirectoryEntry(provider, Id.fromString(id), count, depth + 1); - break; - } - } - } - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof HashDirectory) { - HashDirectory other = (HashDirectory) obj; - return Arrays.equals(index, other.index); - } - return false; - } - - public void prePersist(RevisionStore store, PutToken token) - throws Exception { - - for (int i = 0; i < index.length; i++) { - if (index[i] instanceof ContainerEntry) { - ContainerEntry ce = (ContainerEntry) index[i]; - if (ce.isDirty()) { - ce.store(store, token); - } - } - } - } - - public void serialize(Binding binding) throws Exception { - final IndexEntry[] index = this.index; - binding.write(":count", count); - binding.writeMap(":index", index.length, new Binding.StringEntryIterator() { - int pos = -1; - - @Override - public boolean hasNext() { - return pos < index.length - 1; - } - - @Override - public Binding.StringEntry next() { - pos++; - if (pos >= index.length) { - throw new NoSuchElementException(); - } - // serialize index array entry - IndexEntry entry = index[pos]; - if (entry == null) { - // null entry: "" - return new Binding.StringEntry(Integer.toString(pos), ""); - } else { - return new Binding.StringEntry(Integer.toString(pos), entry.toString()); - } - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - }); - } - - /** - * Entry inside this directory's index. - */ - static interface IndexEntry { - - public int getSize(); - - public Iterator getAdded(IndexEntry other); - - public Iterator getModified(IndexEntry other); - } - - /** - * Direct entry inside this directory's index, pointing to a child node. - */ - static class NodeEntry extends ChildNodeEntry implements IndexEntry { - - public NodeEntry(String name, Id id) { - super(name, id); - } - - public int getSize() { - return 1; - } - - public Iterator getAdded(IndexEntry other) { - if (other == null) { - return null; - } - ChildNodeEntries container = ((ContainerEntry) other).createCompatibleContainer(); - container.add(this); - return container.getAdded(((ContainerEntry) other).getContainer()); - } - - public Iterator getModified(IndexEntry other) { - if (other == null) { - return null; - } - ChildNodeEntries container = ((ContainerEntry) other).createCompatibleContainer(); - container.add(this); - return container.getModified(((ContainerEntry) other).getContainer()); - } - - @Override - public String toString() { - return "n" + getId() + ":" + getName(); - } - } - - /** - * Container entry inside this directory's index, pointing to either a - * directory or a bucket. - */ - static abstract class ContainerEntry implements IndexEntry { - - protected RevisionProvider provider; - protected Id id; - protected int count; - - protected ChildNodeEntries container; - - public ContainerEntry(RevisionProvider provider, Id id, int count) { - this.provider = provider; - this.id = id; - this.count = count; - } - - public ContainerEntry() { - } - - public abstract ChildNodeEntries getContainer(); - - public abstract ChildNodeEntries createCompatibleContainer(); - - public boolean isDirty() { - return container != null; - } - - public void setDirty(ChildNodeEntries container) { - this.container = container; - } - - public Id getId() { - return id; - } - - public int getSize() { - if (container != null) { - return container.getCount(); - } - return count; - } - - @Override - public boolean equals(Object other) { - if (this == other) { - return true; - } - if (other instanceof ContainerEntry) { - ContainerEntry ce = (ContainerEntry) other; - if (container != null && ce.container != null) { - return container.equals(ce.container); - } - if (container == null && ce.container == null) { - return (count == ce.count && id == null ? ce.id == null : id.equals(ce.id)); - } - } - return false; - } - - public Iterator getAdded(IndexEntry other) { - if (other == null) { - return null; - } - if (other instanceof ChildNodeEntry) { - ChildNodeEntries container = createCompatibleContainer(); - container.add((ChildNodeEntry) other); - return getContainer().getAdded(container); - } - return getContainer().getAdded(((ContainerEntry) other).getContainer()); - } - - public Iterator getModified(IndexEntry other) { - if (other == null) { - return null; - } - if (other instanceof ChildNodeEntry) { - ChildNodeEntries container = createCompatibleContainer(); - container.add((ChildNodeEntry) other); - return getContainer().getModified(container); - } - return getContainer().getModified(((ContainerEntry) other).getContainer()); - } - - public void store(RevisionStore store, PutToken token) throws Exception { - store.putCNEMap(token, container); - } - } - - /** - * Directory entry inside this directory's index, pointing to a directory on the - * next level. - */ - static class DirectoryEntry extends ContainerEntry { - - private final int depth; - - public DirectoryEntry(RevisionProvider provider, Id id, int count, int depth) { - super(provider, id, count); - - this.depth = depth; - } - - public DirectoryEntry(int depth) { - this.depth = depth; - } - - public ChildNodeEntries getContainer() { - if (container != null) { - return container; - } - - try { - // TODO return provider.getCNEMap(id); - return new HashDirectory(provider, depth); - } catch (Exception e) { - // todo log error and gracefully handle exception - return null; - } - } - - public ChildNodeEntries createCompatibleContainer() { - return new HashDirectory(provider, depth); - } - - @Override - public String toString() { - return "d" + getId() + ":" + getSize(); - } - - public void store(RevisionStore store, PutToken token) throws Exception { - ((HashDirectory) container).prePersist(store, token); - super.store(store, token); - } - } - - /** - * Bucket entry inside this directory's index, pointing to a bucket or leaf node. - */ - static class BucketEntry extends ContainerEntry { - - public BucketEntry(RevisionProvider provider, Id id, int count) { - super(provider, id, count); - } - - public BucketEntry() { - } - - public HashBucket getContainer() { - if (container != null) { - return (HashBucket) container; - } - - try { - return new HashBucket(provider.getCNEMap(id)); - } catch (Exception e) { - // todo log error and gracefully handle exception - return null; - } - } - - public ChildNodeEntries createCompatibleContainer() { - return new HashBucket(); - } - - @Override - public String toString() { - return "b" + getId() + ":" + getSize(); - } - } - - // ------------------------------------------------------------------------------------------- unimplemented methods - - @Override - public boolean inlined() { - throw new NoSuchMethodError(); - } - - @Override - public Iterator getNames(int offset, int count) { - throw new NoSuchMethodError(); - } - - @Override - public ChildNodeEntry rename(String oldName, String newName) { - throw new NoSuchMethodError(); - } - - @Override - public Iterator getRemoved(ChildNodeEntries other) { - throw new NoSuchMethodError(); - } - - @Override - public int getMemory() { - // assuming a fixed size of 1000 entries, each with 100 bytes, plus 100 - // bytes overhead - int memory = 100 + 1000 * 100; - return memory; - } - -} Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/core/Repository.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/core/Repository.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/core/Repository.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,210 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.core; - -import java.io.Closeable; -import java.io.File; - -import org.apache.jackrabbit.oak.spi.blob.BlobStore; -import org.apache.jackrabbit.oak.spi.blob.FileBlobStore; -import org.apache.jackrabbit.oak.spi.blob.MemoryBlobStore; -import org.apache.jackrabbit.mk.model.ChildNodeEntry; -import org.apache.jackrabbit.mk.model.CommitBuilder; -import org.apache.jackrabbit.mk.model.Id; -import org.apache.jackrabbit.mk.model.StoredCommit; -import org.apache.jackrabbit.mk.model.StoredNode; -import org.apache.jackrabbit.mk.persistence.H2Persistence; -import org.apache.jackrabbit.mk.persistence.InMemPersistence; -import org.apache.jackrabbit.mk.store.DefaultRevisionStore; -import org.apache.jackrabbit.mk.store.NotFoundException; -import org.apache.jackrabbit.mk.store.RevisionStore; -import org.apache.jackrabbit.oak.commons.IOUtils; -import org.apache.jackrabbit.oak.commons.PathUtils; - -/** - * - */ -public class Repository { - - private final File homeDir; - private boolean initialized; - private RevisionStore rs; - private BlobStore bs; - private boolean blobStoreNeedsClose; - - public Repository(String homeDir) throws Exception { - File home = new File(homeDir == null ? "." : homeDir, ".mk"); - this.homeDir = home.getCanonicalFile(); - } - - /** - * Alternate constructor, used for testing. - * - * @param rs revision store - * @param bs blob store - */ - public Repository(RevisionStore rs, BlobStore bs) { - this.homeDir = null; - this.rs = rs; - this.bs = bs; - - initialized = true; - } - - /** - * Argument-less constructor, used for in-memory kernel. - */ - protected Repository() { - this.homeDir = null; - - DefaultRevisionStore rs = - new DefaultRevisionStore(new InMemPersistence(), null); - - try { - rs.initialize(); - } catch (Exception e) { - /* Not plausible for in-memory operation */ - throw new InternalError("Unable to initialize in-memory store"); - } - this.rs = rs; - this.bs = new MemoryBlobStore(); - - initialized = true; - } - - public void init() throws Exception { - if (initialized) { - return; - } - - H2Persistence pm = new H2Persistence(); - pm.initialize(homeDir); - - DefaultRevisionStore rs = new DefaultRevisionStore(pm); - rs.initialize(); - - this.rs = rs; - - if (pm instanceof BlobStore) { - bs = (BlobStore) pm; - } else { - bs = new FileBlobStore(new File(homeDir, "blobs").getCanonicalPath()); - blobStoreNeedsClose = true; - } - - initialized = true; - } - - public void shutDown() throws Exception { - if (!initialized) { - return; - } - if (blobStoreNeedsClose && bs instanceof Closeable) { - IOUtils.closeQuietly((Closeable) bs); - } - if (rs instanceof Closeable) { - IOUtils.closeQuietly((Closeable) rs); - } - initialized = false; - } - - public RevisionStore getRevisionStore() { - if (!initialized) { - throw new IllegalStateException("not initialized"); - } - - return rs; - } - - public BlobStore getBlobStore() { - if (!initialized) { - throw new IllegalStateException("not initialized"); - } - - return bs; - } - - public Id getHeadRevision() throws Exception { - if (!initialized) { - throw new IllegalStateException("not initialized"); - } - return rs.getHeadCommitId(); - } - - public Id getBaseRevision(Id branchRevision) throws Exception { - if (!initialized) { - throw new IllegalStateException("not initialized"); - } - StoredCommit commit = rs.getCommit(branchRevision); - return commit == null ? null : commit.getBranchRootId(); - } - - public StoredCommit getHeadCommit() throws Exception { - if (!initialized) { - throw new IllegalStateException("not initialized"); - } - return rs.getHeadCommit(); - } - - public StoredCommit getCommit(Id id) throws NotFoundException, Exception { - if (!initialized) { - throw new IllegalStateException("not initialized"); - } - return rs.getCommit(id); - } - - public StoredNode getNode(Id revId, String path) throws NotFoundException, Exception { - if (!initialized) { - throw new IllegalStateException("not initialized"); - } else if (!PathUtils.isAbsolute(path)) { - throw new IllegalArgumentException("illegal path"); - } - - StoredNode node = rs.getRootNode(revId); - for (String name : PathUtils.elements(path)) { - ChildNodeEntry cne = node.getChildNodeEntry(name); - if (cne == null) { - throw new NotFoundException(); - } - node = rs.getNode(cne.getId()) ; - } - return node; - } - - public boolean nodeExists(Id revId, String path) throws Exception { - if (!initialized) { - throw new IllegalStateException("not initialized"); - } else if (!PathUtils.isAbsolute(path)) { - throw new IllegalArgumentException("illegal path"); - } - - StoredNode node = rs.getRootNode(revId); - for (String name : PathUtils.elements(path)) { - ChildNodeEntry cne = node.getChildNodeEntry(name); - if (cne == null) { - return false; - } - node = rs.getNode(cne.getId()) ; - } - return true; - } - - public CommitBuilder getCommitBuilder(Id revId, String msg) throws Exception { - return new CommitBuilder(revId, msg, rs); - } - -} Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/model/AbstractNode.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/model/AbstractNode.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/model/AbstractNode.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,188 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.model; - -import org.apache.jackrabbit.mk.store.Binding; -import org.apache.jackrabbit.mk.store.CacheObject; -import org.apache.jackrabbit.mk.store.RevisionProvider; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Map.Entry; -import java.util.TreeMap; - -/** - * - */ -public abstract class AbstractNode implements Node, CacheObject { - - protected RevisionProvider provider; - - protected HashMap properties; - - protected ChildNodeEntries childEntries; - - protected AbstractNode(RevisionProvider provider) { - this.provider = provider; - this.properties = new HashMap(); - this.childEntries = new ChildNodeEntriesMap(); - } - - protected AbstractNode(Node other, RevisionProvider provider) { - this.provider = provider; - if (other instanceof AbstractNode) { - AbstractNode srcNode = (AbstractNode) other; - this.properties = (HashMap) srcNode.properties.clone(); - this.childEntries = (ChildNodeEntries) srcNode.childEntries.clone(); - } else { - this.properties = new HashMap(other.getProperties()); - if (other.getChildNodeCount() <= ChildNodeEntries.CAPACITY_THRESHOLD) { - this.childEntries = new ChildNodeEntriesMap(); - } else { - this.childEntries = new ChildNodeEntriesTree(provider); - } - for (Iterator it = other.getChildNodeEntries(0, -1); it.hasNext(); ) { - ChildNodeEntry cne = it.next(); - this.childEntries.add(cne); - } - } - } - - public Map getProperties() { - return properties; - } - - public ChildNodeEntry getChildNodeEntry(String name) { - return childEntries.get(name); - } - - public Iterator getChildNodeNames(int offset, int count) { - return childEntries.getNames(offset, count); - } - - public int getChildNodeCount() { - return childEntries.getCount(); - } - - public Iterator getChildNodeEntries(int offset, int count) { - return childEntries.getEntries(offset, count); - } - - public void diff(Node other, NodeDiffHandler handler) { - // compare properties - - Map oldProps = getProperties(); - Map newProps = other.getProperties(); - - for (Map.Entry entry : oldProps.entrySet()) { - String name = entry.getKey(); - String val = oldProps.get(name); - String newVal = newProps.get(name); - if (newVal == null) { - handler.propDeleted(name, val); - } else { - if (!val.equals(newVal)) { - handler.propChanged(name, val, newVal); - } - } - } - for (Map.Entry entry : newProps.entrySet()) { - String name = entry.getKey(); - if (!oldProps.containsKey(name)) { - handler.propAdded(name, entry.getValue()); - } - } - - // compare child node entries - - if (other instanceof AbstractNode) { - // OAK-46: Efficient diffing of large child node lists - - // delegate to ChildNodeEntries implementation - ChildNodeEntries otherEntries = ((AbstractNode) other).childEntries; - for (Iterator it = childEntries.getAdded(otherEntries); it.hasNext(); ) { - handler.childNodeAdded(it.next()); - } - for (Iterator it = childEntries.getRemoved(otherEntries); it.hasNext(); ) { - handler.childNodeDeleted(it.next()); - } - for (Iterator it = childEntries.getModified(otherEntries); it.hasNext(); ) { - ChildNodeEntry old = it.next(); - ChildNodeEntry modified = otherEntries.get(old.getName()); - handler.childNodeChanged(old, modified.getId()); - } - return; - } - - for (Iterator it = getChildNodeEntries(0, -1); it.hasNext(); ) { - ChildNodeEntry child = it.next(); - ChildNodeEntry newChild = other.getChildNodeEntry(child.getName()); - if (newChild == null) { - handler.childNodeDeleted(child); - } else { - if (!child.getId().equals(newChild.getId())) { - handler.childNodeChanged(child, newChild.getId()); - } - } - } - for (Iterator it = other.getChildNodeEntries(0, -1); it.hasNext(); ) { - ChildNodeEntry child = it.next(); - if (getChildNodeEntry(child.getName()) == null) { - handler.childNodeAdded(child); - } - } - } - - public void serialize(Binding binding) throws Exception { - final Iterator> iter = - new TreeMap(properties).entrySet().iterator(); - binding.writeMap(":props", properties.size(), - new Binding.StringEntryIterator() { - @Override - public boolean hasNext() { - return iter.hasNext(); - } - @Override - public Binding.StringEntry next() { - Map.Entry entry = iter.next(); - return new Binding.StringEntry(entry.getKey(), entry.getValue()); - } - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - }); - binding.write(":inlined", childEntries.inlined() ? 1 : 0); - childEntries.serialize(binding); - } - - @Override - public int getMemory() { - int memory = 100; - for (Entry e : properties.entrySet()) { - memory += 2 * e.getKey().length(); - memory += 2 * e.getValue().length(); - } - if (childEntries.inlined()) { - memory += childEntries.getMemory(); - } - - return memory; - } - -} Index: oak-mk/src/test/java/org/apache/jackrabbit/mk/persistence/GCPersistenceTest.java =================================================================== --- oak-mk/src/test/java/org/apache/jackrabbit/mk/persistence/GCPersistenceTest.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/test/java/org/apache/jackrabbit/mk/persistence/GCPersistenceTest.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,147 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.persistence; - -import org.apache.jackrabbit.mk.model.Id; -import org.apache.jackrabbit.mk.model.MutableCommit; -import org.apache.jackrabbit.mk.model.MutableNode; -import org.apache.jackrabbit.mk.model.StoredNode; -import org.apache.jackrabbit.mk.store.NotFoundException; -import org.apache.jackrabbit.oak.commons.IOUtils; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; - -import java.io.File; -import java.util.Arrays; -import java.util.Collection; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -/** - * Tests verifying the contract provided by {@link GCPersistence}. - */ -@RunWith(value = Parameterized.class) -public class GCPersistenceTest { - - private Class pmClass; - private GCPersistence pm; - - public GCPersistenceTest(Class pmClass) { - this.pmClass = pmClass; - } - - @Before - public void setup() throws Exception { - pm = pmClass.newInstance(); - pm.initialize(new File("target/mk")); - - // start with empty repository - pm.start(); - pm.sweep(); - } - - @SuppressWarnings("rawtypes") - @Parameters - public static Collection classes() { - Class[][] pmClasses = new Class[][] { - { H2Persistence.class }, - { InMemPersistence.class } - }; - return Arrays.asList(pmClasses); - } - - @After - public void tearDown() throws Exception { - IOUtils.closeQuietly(pm); - } - - @Test - public void testOldNodeIsSwept() throws Exception { - MutableNode node = new MutableNode(null); - Id id = pm.writeNode(node); - - Thread.sleep(1); - pm.start(); - pm.sweep(); - - try { - pm.readNode(new StoredNode(id, null)); - fail(); - } catch (NotFoundException e) { - /* expected */ - } - } - - @Test - public void testMarkedNodeIsNotSwept() throws Exception { - MutableNode node = new MutableNode(null); - Id id = pm.writeNode(node); - - // small delay needed - Thread.sleep(100); - - pm.start(); - - // old node must not be marked - assertTrue(pm.markNode(id)); - - pm.sweep(); - pm.readNode(new StoredNode(id, null)); - } - - @Test - public void testNewNodeIsNotSwept() throws Exception { - pm.start(); - - MutableNode node = new MutableNode(null); - Id id = pm.writeNode(node); - - // new node must already be marked - assertFalse(pm.markNode(id)); - - pm.sweep(); - pm.readNode(new StoredNode(id, null)); - } - - @Test - public void testReplaceCommit() throws Exception { - MutableCommit c1 = new MutableCommit(); - c1.setRootNodeId(Id.fromLong(0)); - pm.writeCommit(Id.fromLong(1), c1); - - MutableCommit c2 = new MutableCommit(); - c2.setParentId(c1.getId()); - c2.setRootNodeId(Id.fromLong(0)); - pm.writeCommit(Id.fromLong(2), c2); - - pm.start(); - c2 = new MutableCommit(); - c2.setRootNodeId(Id.fromLong(0)); - pm.replaceCommit(Id.fromLong(2), c2); - pm.sweep(); - - assertEquals(null, pm.readCommit(Id.fromLong(2)).getParentId()); - } -} - Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/Persistence.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/Persistence.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/persistence/Persistence.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,80 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.persistence; - -import org.apache.jackrabbit.mk.model.ChildNodeEntries; -import org.apache.jackrabbit.mk.model.ChildNodeEntriesMap; -import org.apache.jackrabbit.mk.model.Commit; -import org.apache.jackrabbit.mk.model.Id; -import org.apache.jackrabbit.mk.model.Node; -import org.apache.jackrabbit.mk.model.StoredCommit; -import org.apache.jackrabbit.mk.model.StoredNode; -import org.apache.jackrabbit.mk.store.NotFoundException; - -import java.io.Closeable; -import java.io.File; - -/** - * Defines the methods exposed by a persistence manager, that stores head - * revision id, nodes, child node entries and blobs. - */ -public interface Persistence extends Closeable { - - public void initialize(File homeDir) throws Exception; - - /** - * Return an array of ids, where the first is the head id (as stored - * with {@link #writeHead(Id)}) and the second is the highest commit - * id found or {@code null}. - *

- * This method is not guaranteed to deliver "live" results, after - * something is written to the storage, so it should better be used - * once after initialization. - * - * @return array of ids - * @throws Exception if an error occurs - */ - Id[] readIds() throws Exception; - - void writeHead(Id id) throws Exception; - - /** - * Read a node from storage. - * - * @param node node to read, with id given in {@link StoredNode#getId()} - * @throws NotFoundException if no such node is found - * @throws Exception if some other error occurs - */ - void readNode(StoredNode node) throws NotFoundException, Exception; - - Id writeNode(Node node) throws Exception; - - ChildNodeEntriesMap readCNEMap(Id id) throws NotFoundException, Exception; - - Id writeCNEMap(ChildNodeEntries map) throws Exception; - - StoredCommit readCommit(Id id) throws NotFoundException, Exception; - - /** - * Persist a commit with an id provided by the caller. - * - * @param id commit id - * @param commit commit - * @throws Exception if an error occurs - */ - void writeCommit(Id id, Commit commit) throws Exception; -} Index: oak-commons/pom.xml IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-commons/pom.xml (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-commons/pom.xml (revision ) @@ -100,5 +100,16 @@ logback-classic test + + org.apache.jackrabbit + oak-mk-api + ${project.version} + + + org.apache.jackrabbit + oak-core + 1.0.0 + test + Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/store/NotFoundException.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/store/NotFoundException.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/store/NotFoundException.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.store; - -/** - * - */ -public class NotFoundException extends Exception { - - private static final long serialVersionUID = 267748774351258035L; - - public NotFoundException() { - super(); - } - - public NotFoundException(String message) { - super(message); - } - - public NotFoundException(String message, Throwable cause) { - super(message, cause); - } - - public NotFoundException(Throwable cause) { - super(cause); - } -} Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/store/DefaultRevisionStore.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/store/DefaultRevisionStore.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/store/DefaultRevisionStore.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,673 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.store; - -import org.apache.jackrabbit.mk.model.ChildNodeEntries; -import org.apache.jackrabbit.mk.model.ChildNodeEntriesMap; -import org.apache.jackrabbit.mk.model.ChildNodeEntry; -import org.apache.jackrabbit.mk.model.Id; -import org.apache.jackrabbit.mk.model.MutableCommit; -import org.apache.jackrabbit.mk.model.MutableNode; -import org.apache.jackrabbit.mk.model.StoredCommit; -import org.apache.jackrabbit.mk.model.StoredNode; -import org.apache.jackrabbit.mk.persistence.GCPersistence; -import org.apache.jackrabbit.mk.persistence.Persistence; -import org.apache.jackrabbit.oak.commons.IOUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.Weigher; - -import java.io.Closeable; -import java.util.Collections; -import java.util.Iterator; -import java.util.Map; -import java.util.Map.Entry; -import java.util.TreeMap; -import java.util.WeakHashMap; -import java.util.concurrent.Callable; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -/** - * Default revision store implementation, passing calls to a {@code Persistence} - * and a {@code BlobStore}, respectively and providing caching. - */ -public class DefaultRevisionStore implements RevisionStore, Closeable { - - private static final Logger LOG = LoggerFactory.getLogger(DefaultRevisionStore.class); - - public static final String CACHE_SIZE = "mk.cacheSize"; - - // default cache size is 32 MB - public static final int DEFAULT_CACHE_SIZE = 32 * 1024 * 1024; - - private boolean initialized; - private Id head; - - private final AtomicLong commitCounter = new AtomicLong(); - - private final ReentrantReadWriteLock headLock = new ReentrantReadWriteLock(); - private final Persistence pm; - protected final GCPersistence gcpm; - - /* avoid synthetic accessor */ int initialCacheSize; - /* avoid synthetic accessor */ Cache cache; - - /** - * GC run state constants. - */ - private static final int NOT_ACTIVE = 0; - private static final int STARTING = 1; - private static final int MARKING = 2; - private static final int SWEEPING = 3; - - /** - * GC run state. - */ - private final AtomicInteger gcState = new AtomicInteger(); - - private int markedNodes, markedCommits; - - /** - * GC executor. - */ - private ScheduledExecutorService gcExecutor; - - /** - * Active put tokens (Key: token, Value: null). - */ - private final Map putTokens = Collections.synchronizedMap(new WeakHashMap()); - - /** - * Read-write lock for put tokens. - */ - private final ReentrantReadWriteLock tokensLock = new ReentrantReadWriteLock(); - - /** - * Active branches (Key: current branch head, Value: branch root id). - */ - private final TreeMap branches = new TreeMap(); - - public DefaultRevisionStore(Persistence pm) { - this(pm, (pm instanceof GCPersistence) ? (GCPersistence) pm : null); - } - - /** - * Alternative constructor that allows disabling of garbage collection - * for an in-memory test repository. - * - * @param pm persistence manager - * @param gcpm the same persistence manager, or {@code null} for no GC - */ - public DefaultRevisionStore(Persistence pm, GCPersistence gcpm) { - this.pm = pm; - this.gcpm = gcpm; - } - - public void initialize() throws Exception { - if (initialized) { - throw new IllegalStateException("already initialized"); - } - - initialCacheSize = determineInitialCacheSize(); - - cache = CacheBuilder.newBuilder() - .maximumWeight(initialCacheSize) - .weigher(new Weigher() { - public int weigh(Id id, CacheObject obj) { - return obj.getMemory(); - } - }) - .build(); - - // make sure we've got a HEAD commit - Id[] ids = pm.readIds(); - head = ids[0]; - if (head == null || head.getBytes().length == 0) { - // assume virgin repository - byte[] rawHead = Id.fromLong(commitCounter.incrementAndGet()) - .getBytes(); - head = new Id(rawHead); - - Id rootNodeId = pm.writeNode(new MutableNode(this)); - MutableCommit initialCommit = new MutableCommit(); - initialCommit.setCommitTS(System.currentTimeMillis()); - initialCommit.setRootNodeId(rootNodeId); - pm.writeCommit(head, initialCommit); - pm.writeHead(head); - } else { - Id lastCommitId = head; - if (ids[1] != null && ids[1].compareTo(lastCommitId) > 0) { - lastCommitId = ids[1]; - } - commitCounter.set(Long.parseLong(lastCommitId.toString(), 16)); - } - - if (gcpm != null) { - gcExecutor = Executors.newScheduledThreadPool(1, - new ThreadFactory() { - @Override - public Thread newThread(Runnable r) { - Thread t = new Thread(r, "RevisionStore-GC"); - t.setDaemon(true); - return t; - } - }); - gcExecutor.scheduleWithFixedDelay(new Runnable() { - @Override - public void run() { - if (cache.size() >= initialCacheSize) { - gc(); - } - } - }, 60, 1, TimeUnit.MINUTES); // TODO: Should start earlier - } - - initialized = true; - } - - public void close() { - verifyInitialized(); - - if (gcExecutor != null) { - gcExecutor.shutdown(); - } - - cache.invalidateAll(); - - IOUtils.closeQuietly(pm); - - initialized = false; - } - - protected void verifyInitialized() { - if (!initialized) { - throw new IllegalStateException("not initialized"); - } - } - - protected static int determineInitialCacheSize() { - String val = System.getProperty(CACHE_SIZE); - return (val != null) ? Integer.parseInt(val) : DEFAULT_CACHE_SIZE; - } - - // --------------------------------------------------------< RevisionStore > - - /** - * Put token implementation. - */ - static class PutTokenImpl extends PutToken { - - private static final AtomicInteger ID_COUNTER = new AtomicInteger(); - private int id; - private StoredNode lastModifiedNode; - - public PutTokenImpl() { - this.id = ID_COUNTER.incrementAndGet(); - } - - @Override - public int hashCode() { - return id; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof PutTokenImpl) { - return ((PutTokenImpl) obj).id == id; - } - return super.equals(obj); - } - - public void updateLastModifed(StoredNode lastModifiedNode) { - this.lastModifiedNode = lastModifiedNode; - } - - public StoredNode getLastModified() { - return lastModifiedNode; - } - } - - public RevisionStore.PutToken createPutToken() { - return new PutTokenImpl(); - } - - public Id putNode(PutToken token, MutableNode node) throws Exception { - verifyInitialized(); - - PersistHook callback = null; - if (node instanceof PersistHook) { - callback = (PersistHook) node; - callback.prePersist(this, token); - } - - /* - * Make sure that a GC cycle can not sweep this newly persisted node - * before we have updated our token - */ - tokensLock.writeLock().lock(); - - try { - Id id = pm.writeNode(node); - - if (callback != null) { - callback.postPersist(this, token); - } - - StoredNode snode = new StoredNode(id, node, this); - cache.put(id, snode); - - PutTokenImpl pti = (PutTokenImpl) token; - pti.updateLastModifed(snode); - putTokens.put(pti, null); - return id; - - } finally { - tokensLock.writeLock().unlock(); - } - } - - public Id putCNEMap(PutToken token, ChildNodeEntries map) - throws Exception { - verifyInitialized(); - - PersistHook callback = null; - if (map instanceof PersistHook) { - callback = (PersistHook) map; - callback.prePersist(this, token); - } - - Id id = pm.writeCNEMap(map); - - if (callback != null) { - callback.postPersist(this, token); - } - - cache.put(id, map); - - return id; - } - - public void lockHead() { - headLock.writeLock().lock(); - } - - public Id putHeadCommit(PutToken token, MutableCommit commit, Id branchRootId, Id branchRevId) - throws Exception { - verifyInitialized(); - if (!headLock.writeLock().isHeldByCurrentThread()) { - throw new IllegalStateException( - "putHeadCommit called without holding write lock."); - } - - if (commit.getBranchRootId() != null) { - // OAK-267 - throw new IllegalStateException("private branch commit [" + commit + "] cannot become HEAD"); - } - - Id id = writeCommit(token, commit); - setHeadCommitId(id); - - tokensLock.writeLock().lock(); - - try { - putTokens.remove(token); - } finally { - tokensLock.writeLock().unlock(); - } - - if (branchRevId != null) { - synchronized (branches) { - branches.remove(branchRevId); - } - } - return id; - } - - public Id putCommit(PutToken token, MutableCommit commit) throws Exception { - verifyInitialized(); - - Id commitId = writeCommit(token, commit); - - tokensLock.writeLock().lock(); - - try { - putTokens.remove(token); - } finally { - tokensLock.writeLock().unlock(); - } - - Id branchRootId = commit.getBranchRootId(); - if (branchRootId != null) { - synchronized (branches) { - Id parentId = commit.getParentId(); - if (!parentId.equals(branchRootId)) { - /* not the first branch commit, replace its head */ - branches.remove(parentId); - } - branches.put(commitId, branchRootId); - } - } - return commitId; - } - - public void unlockHead() { - headLock.writeLock().unlock(); - } - - // -----------------------------------------------------< RevisionProvider > - - public StoredNode getNode(final Id id) throws NotFoundException, Exception { - verifyInitialized(); - - StoredNode node = (StoredNode) cache.get(id, - new Callable() { - @Override - public StoredNode call() throws Exception { - StoredNode node = new StoredNode(id, - DefaultRevisionStore.this); - pm.readNode(node); - return node; - } - }); - return node; - } - - public ChildNodeEntriesMap getCNEMap(final Id id) throws NotFoundException, - Exception { - verifyInitialized(); - - ChildNodeEntriesMap map = (ChildNodeEntriesMap) cache.get(id, - new Callable() { - @Override - public ChildNodeEntriesMap call() throws Exception { - return pm.readCNEMap(id); - } - }); - return map; - } - - public StoredCommit getCommit(final Id id) throws NotFoundException, - Exception { - verifyInitialized(); - - StoredCommit commit = (StoredCommit) cache.get(id, - new Callable() { - @Override - public StoredCommit call() throws Exception { - return pm.readCommit(id); - } - }); - return commit; - } - - public StoredNode getRootNode(Id commitId) throws NotFoundException, - Exception { - return getNode(getCommit(commitId).getRootNodeId()); - } - - public StoredCommit getHeadCommit() throws Exception { - return getCommit(getHeadCommitId()); - } - - public Id getHeadCommitId() throws Exception { - verifyInitialized(); - - headLock.readLock().lock(); - try { - return head; - } finally { - headLock.readLock().unlock(); - } - } - - // -------------------------------------------------------< implementation > - - private Id writeCommit(RevisionStore.PutToken token, MutableCommit commit) - throws Exception { - PersistHook callback = null; - if (commit instanceof PersistHook) { - callback = (PersistHook) commit; - callback.prePersist(this, token); - } - - Id id = commit.getId(); - if (id == null) { - id = Id.fromLong(commitCounter.incrementAndGet()); - } - pm.writeCommit(id, commit); - - if (callback != null) { - callback.postPersist(this, token); - } - cache.put(id, new StoredCommit(id, commit)); - return id; - } - - private void setHeadCommitId(Id id) throws Exception { - // non-synchronized since we're called from putHeadCommit - // which requires a write lock - pm.writeHead(id); - head = id; - - long counter = Long.parseLong(id.toString(), 16); - if (counter > commitCounter.get()) { - commitCounter.set(counter); - } - } - - // ----------------------------------------------------------------------- - // GC - - /** - * Perform a garbage collection. If a garbage collection cycle is already - * running, this method returns immediately. - */ - public void gc() { - if (gcpm == null || !gcState.compareAndSet(NOT_ACTIVE, STARTING)) { - // already running - return; - } - - LOG.debug("GC started."); - markedCommits = markedNodes = 0; - - try { - markUncommittedNodes(); - Id firstBranchRootId = markBranches(); - if (firstBranchRootId != null) { - LOG.debug("First branch root to be preserved: {}", firstBranchRootId); - } - Id firstCommitId = markCommits(); - LOG.debug("First commit to be preserved: {}", firstCommitId); - - LOG.debug("Marked {} commits, {} nodes.", markedCommits, markedNodes); - - if (firstBranchRootId != null && firstBranchRootId.compareTo(firstCommitId) < 0) { - firstCommitId = firstBranchRootId; - } - /* repair dangling parent commit of first preserved commit */ - StoredCommit commit = getCommit(firstCommitId); - if (commit.getParentId() != null) { - MutableCommit firstCommit = new MutableCommit(commit); - firstCommit.setParentId(null); - gcpm.replaceCommit(firstCommit.getId(), firstCommit); - } - - } catch (Exception e) { - /* unable to perform GC */ - LOG.error("Exception occurred in GC cycle", e); - gcState.set(NOT_ACTIVE); - return; - } - - gcState.set(SWEEPING); - - try { - int swept = gcpm.sweep(); - LOG.debug("GC cycle swept {} items", swept); - cache.invalidateAll(); - } catch (Exception e) { - LOG.error("Exception occurred in GC cycle", e); - } finally { - gcState.set(NOT_ACTIVE); - } - - LOG.debug("GC stopped."); - } - - /** - * Mark nodes that have already been put but not committed yet. - * - * @throws Exception - * if an error occurs - */ - private void markUncommittedNodes() throws Exception { - tokensLock.readLock().lock(); - - try { - gcpm.start(); - gcState.set(MARKING); - - PutTokenImpl[] tokens = putTokens.keySet().toArray(new PutTokenImpl[putTokens.size()]); - for (PutTokenImpl token : tokens) { - markNode(token.getLastModified()); - } - } finally { - tokensLock.readLock().unlock(); - } - } - - /** - * Mark branches. - * - * @return first branch root id that needs to be preserved, or {@code null} - * @throws Exception - * if an error occurs - */ - @SuppressWarnings("unchecked") - private Id markBranches() throws Exception { - Map tmpBranches; - - synchronized (branches) { - tmpBranches = (Map) branches.clone(); - } - - Id firstBranchRootId = null; - - /* Mark all branch commits */ - for (Entry entry : tmpBranches.entrySet()) { - Id branchRevId = entry.getKey(); - Id branchRootId = entry.getValue(); - while (!branchRevId.equals(branchRootId)) { - StoredCommit commit = getCommit(branchRevId); - markCommit(commit); - branchRevId = commit.getParentId(); - } - if (firstBranchRootId == null || firstBranchRootId.compareTo(branchRootId) > 0) { - firstBranchRootId = branchRootId; - } - } - /* Mark all master commits till the first branch root id */ - if (firstBranchRootId != null) { - StoredCommit commit = getHeadCommit(); - - for (;;) { - markCommit(commit); - if (commit.getId().equals(firstBranchRootId)) { - break; - } - commit = getCommit(commit.getParentId()); - } - return firstBranchRootId; - } - return null; - } - - /** - * Mark all commits and nodes in a garbage collection cycle. Can be - * customized by subclasses. The default implementation preserves all - * commits that were created within 60 minutes of the current head commit. - *

- * If this method throws an exception, the cycle will be stopped without - * sweeping. - * - * @return first commit id that will be preserved - * @throws Exception - * if an error occurs - */ - protected Id markCommits() throws Exception { - StoredCommit commit = getHeadCommit(); - long tsLimit = commit.getCommitTS() - (60 * 60 * 1000); - - for (;;) { - markCommit(commit); - Id id = commit.getParentId(); - if (id == null) { - break; - } - StoredCommit parentCommit = getCommit(id); - if (parentCommit.getCommitTS() < tsLimit) { - break; - } - commit = parentCommit; - } - return commit.getId(); - } - - /** - * Mark a commit. This marks all nodes belonging to this commit as well. - * - * @param commit commit - * @throws Exception if an error occurs - */ - protected void markCommit(StoredCommit commit) throws Exception { - if (!gcpm.markCommit(commit.getId())) { - return; - } - markedCommits++; - - markNode(getNode(commit.getRootNodeId())); - } - - /** - * Mark a node. This marks all children as well. - * - * @param node node - * @throws Exception if an error occurs - */ - private void markNode(StoredNode node) throws Exception { - if (!gcpm.markNode(node.getId())) { - return; - } - markedNodes++; - - Iterator iter = node.getChildNodeEntries(0, -1); - while (iter.hasNext()) { - ChildNodeEntry c = iter.next(); - markNode(getNode(c.getId())); - } - } -} Index: oak-mk/src/test/java/org/apache/jackrabbit/mk/util/MicroKernelInputStreamTest.java =================================================================== --- oak-mk/src/test/java/org/apache/jackrabbit/mk/util/MicroKernelInputStreamTest.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/mk/MicroKernelInputStreamTest.java (revision ) @@ -11,11 +11,10 @@ * KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ -package org.apache.jackrabbit.mk.util; +package org.apache.jackrabbit.oak.commons.mk; -import org.apache.jackrabbit.mk.api.MicroKernel; -import org.apache.jackrabbit.mk.core.MicroKernelImpl; -import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -23,15 +22,17 @@ import java.io.InputStream; import java.util.Random; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import org.apache.jackrabbit.mk.api.MicroKernel; +import org.apache.jackrabbit.oak.kernel.NodeStoreKernel; +import org.apache.jackrabbit.oak.plugins.segment.SegmentNodeStore; +import org.junit.Test; /** * Tests the {@code MicroKernelInputStream}. */ public class MicroKernelInputStreamTest { - MicroKernel mk = new MicroKernelImpl(); + MicroKernel mk = new NodeStoreKernel(new SegmentNodeStore()); @Test public void small() throws IOException { Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/util/MicroKernelInputStream.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/util/MicroKernelInputStream.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/mk/MicroKernelInputStream.java (revision ) @@ -14,13 +14,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.jackrabbit.mk.util; +package org.apache.jackrabbit.oak.commons.mk; -import org.apache.jackrabbit.mk.api.MicroKernel; -import org.apache.jackrabbit.oak.commons.IOUtils; - import java.io.IOException; import java.io.InputStream; + +import org.apache.jackrabbit.mk.api.MicroKernel; +import org.apache.jackrabbit.oak.commons.IOUtils; /** * An input stream to simplify reading a blob from a {@code MicroKernel}. Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/util/NodeFilter.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/util/NodeFilter.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/util/NodeFilter.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,99 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.util; - -import org.apache.jackrabbit.oak.commons.json.JsopTokenizer; - -import java.util.ArrayList; -import java.util.List; - -/** - * A {@code NodeFilter} represents a filter on property and/or node names specified - * in JSON format. It allows to specify glob patterns for names of nodes and/or - * properties to be included or excluded. - *

- * Example: - *

- * {
- *   "nodes": [ "foo*", "-foo1" ],
- *   "properties": [ "*", "-:childNodeCount" ]
- * }
- * 
- * - * @see NameFilter - * @see org.apache.jackrabbit.mk.api.MicroKernel#getNodes(String, String, int, long, int, String) - */ -public class NodeFilter { - - private final NameFilter nodeFilter; - private final NameFilter propFilter; - - private NodeFilter(NameFilter nodeFilter, NameFilter propFilter) { - this.nodeFilter = nodeFilter; - this.propFilter = propFilter; - } - - public static NodeFilter parse(String json) { - // parse json format filter - JsopTokenizer t = new JsopTokenizer(json); - t.read('{'); - - NameFilter nodeFilter = null, propFilter = null; - - do { - String type = t.readString(); - t.read(':'); - String[] globs = parseArray(t); - if (type.equals("nodes")) { - nodeFilter = new NameFilter(globs); - } else if (type.equals("properties")) { - propFilter = new NameFilter(globs); - } else { - throw new IllegalArgumentException("illegal filter format"); - } - } while (t.matches(',')); - t.read('}'); - - return new NodeFilter(nodeFilter, propFilter); - } - - private static String[] parseArray(JsopTokenizer t) { - List l = new ArrayList(); - t.read('['); - do { - l.add(t.readString()); - } while (t.matches(',')); - t.read(']'); - return l.toArray(new String[l.size()]); - } - - public NameFilter getChildNodeFilter() { - return nodeFilter; - } - - public NameFilter getPropertyFilter() { - return propFilter; - } - - public boolean includeNode(String name) { - return nodeFilter == null || nodeFilter.matches(name); - } - - public boolean includeProperty(String name) { - return propFilter == null || propFilter.matches(name); - } -} \ No newline at end of file Index: oak-it/mk/src/main/java/org/apache/jackrabbit/mk/test/DataStoreIT.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-it/mk/src/main/java/org/apache/jackrabbit/mk/test/DataStoreIT.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-it/mk/src/main/java/org/apache/jackrabbit/mk/test/DataStoreIT.java (revision ) @@ -22,7 +22,7 @@ import java.io.InputStream; import java.util.Random; import junit.framework.Assert; -import org.apache.jackrabbit.mk.util.MicroKernelInputStream; +import org.apache.jackrabbit.oak.commons.mk.MicroKernelInputStream; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/util/UnmodifiableIterator.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/util/UnmodifiableIterator.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/util/UnmodifiableIterator.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.util; - -import java.util.Iterator; - -/** - * - */ -public class UnmodifiableIterator implements Iterator { - - final Iterator it; - - public UnmodifiableIterator(Iterator it) { - this.it = it; - } - - public boolean hasNext() { - return it.hasNext(); - } - - public T next() { - return it.next(); - } - - public void remove() { - throw new UnsupportedOperationException(); - } -} Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/model/Id.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/model/Id.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/model/Id.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,135 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.model; - -import org.apache.jackrabbit.oak.commons.StringUtils; - -import java.util.Arrays; - -/** - * Represents an internal identifier, uniquely identifying - * a {@link Node} or a {@link Commit}. - *

- * This implementation aims at minimizing the in-memory footprint - * of an identifier instance. therefore it doesn't cache e.g. the hashCode - * or the string representation. - *

- * Important Note:

- * An {@link Id} is considered immutable. The {@code byte[]} - * passed to {@link Id#Id(byte[])} must not be reused or modified, the same - * applies for the {@code byte[]} returned by {@link Id#getBytes()}. - */ -public class Id implements Comparable { - - // the raw bytes making up this identifier - private final byte[] raw; - - /** - * Creates a new instance based on the passed {@code byte[]}. - *

- * The passed {@code byte[]} mus not be reused, it's assumed - * to be owned by the new {@code Id} instance. - * - * @param raw the byte representation - */ - public Id(byte[] raw) { - // don't copy the buffer for efficiency reasons - this.raw = raw; - } - - /** - * Creates an {@code Id} instance from its - * string representation as returned by {@link #toString()}. - *

- * The following condition holds true: - *

-     * Id someId = ...;
-     * assert(Id.fromString(someId.toString()).equals(someId));
-     * 
- * - * @param s a string representation of an {@code Id} - * @return an {@code Id} instance - * @throws IllegalArgumentException if {@code s} is not a valid string representation - */ - public static Id fromString(String s) { - return new Id(StringUtils.convertHexToBytes(s)); - } - - /** - * Creates an {@code Id} instance from a long. - * - * @param value a long - * @return an {@code Id} instance - */ - public static Id fromLong(long value) { - byte[] raw = new byte[8]; - - for (int i = raw.length - 1; i >= 0 && value != 0; i--) { - raw[i] = (byte) (value & 0xff); - value >>>= 8; - } - return new Id(raw); - } - - @Override - public int hashCode() { - // the hashCode is intentionally not stored - return Arrays.hashCode(raw); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof Id) { - Id other = (Id) obj; - return Arrays.equals(raw, other.raw); - } - return false; - } - - @Override - public String toString() { - // the string representation is intentionally not stored - return StringUtils.convertBytesToHex(raw); - } - - @Override - public int compareTo(Id o) { - byte[] other = o.getBytes(); - int len = Math.min(raw.length, other.length); - - for (int i = 0; i < len; i++) { - if (raw[i] != other[i]) { - final int rawValue = raw[i] & 0xFF; // unsigned value - final int otherValue = other[i] & 0xFF; // unsigned value - return rawValue - otherValue; - } - } - return raw.length - other.length; - } - - /** - * Returns the raw byte representation of this identifier. - *

- * The returned {@code byte[]} MUST NOT be modified! - * - * @return the raw byte representation - */ - public byte[] getBytes() { - // don't copy the buffer for efficiency reasons - return raw; - } -} Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/store/Binding.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/store/Binding.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/store/Binding.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,85 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.store; - -import java.util.Iterator; - -/** - * - */ -public interface Binding { - - void write(String key, String value) throws Exception; - void write(String key, byte[] value) throws Exception; - void write(String key, long value) throws Exception; - void write(String key, int value) throws Exception; - void writeMap(String key, int count, StringEntryIterator iterator) throws Exception; - void writeMap(String key, int count, BytesEntryIterator iterator) throws Exception; - - String readStringValue(String key) throws Exception; - byte[] readBytesValue(String key) throws Exception; - long readLongValue(String key) throws Exception; - int readIntValue(String key) throws Exception; - StringEntryIterator readStringMap(String key) throws Exception; - BytesEntryIterator readBytesMap(String key) throws Exception; - - static abstract class Entry { - String key; - V value; - - public Entry(String key, V value) { - this.key = key; - this.value = value; - } - - public String getKey() { - return key; - } - - public V getValue() { - return value; - } - } - - static class StringEntry extends Entry { - - public StringEntry(String key, String value) { - super(key, value); - } - - public String getValue() { - return value; - } - } - - static class BytesEntry extends Entry { - - public BytesEntry(String key, byte[] value) { - super(key, value); - } - - public byte[] getValue() { - return value; - } - } - - static interface StringEntryIterator extends Iterator { - } - - static interface BytesEntryIterator extends Iterator { - } -} Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/htree/ChildNodeEntriesHTree.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/htree/ChildNodeEntriesHTree.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/htree/ChildNodeEntriesHTree.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,185 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.htree; - -import java.util.Collections; -import java.util.Iterator; -import java.util.List; - -import org.apache.jackrabbit.mk.model.ChildNodeEntries; -import org.apache.jackrabbit.mk.model.ChildNodeEntry; -import org.apache.jackrabbit.mk.store.Binding; -import org.apache.jackrabbit.mk.store.PersistHook; -import org.apache.jackrabbit.mk.store.RevisionProvider; -import org.apache.jackrabbit.mk.store.RevisionStore; -import org.apache.jackrabbit.mk.store.RevisionStore.PutToken; -import org.apache.jackrabbit.mk.util.AbstractFilteringIterator; -import org.apache.jackrabbit.mk.util.AbstractRangeIterator; - -/** - * HTree based implementation to manage child node entries. - */ -public class ChildNodeEntriesHTree implements ChildNodeEntries, PersistHook { - - private HashDirectory top; - - public ChildNodeEntriesHTree(RevisionProvider provider) { - top = new HashDirectory(provider, 0); - } - - public Object clone() { - ChildNodeEntriesHTree clone = null; - try { - clone = (ChildNodeEntriesHTree) super.clone(); - } catch (CloneNotSupportedException e) { - // can't possibly get here - } - // shallow clone of array of immutable IndexEntry objects - clone.top = (HashDirectory) top.clone(); - return clone; - } - - @Override - public boolean inlined() { - return false; - } - - @Override - public int getCount() { - return top.getCount(); - } - - @Override - public ChildNodeEntry get(String name) { - return top.get(name); - } - - @Override - public Iterator getNames(int offset, int count) { - if (offset < 0 || count < -1) { - throw new IllegalArgumentException(); - } - - if (offset >= getCount() || count == 0) { - List empty = Collections.emptyList(); - return empty.iterator(); - } - - if (count == -1 || (offset + count) > getCount()) { - count = getCount() - offset; - } - - return new AbstractRangeIterator(getEntries(offset, count), 0, -1) { - @Override - protected String doNext() { - ChildNodeEntry cne = (ChildNodeEntry) it.next(); - return cne.getName(); - } - }; - } - - @Override - public Iterator getEntries(int offset, int count) { - return top.getEntries(offset, count); - } - - @Override - public ChildNodeEntry add(ChildNodeEntry entry) { - return top.add(entry); - } - - @Override - public ChildNodeEntry remove(String name) { - return top.remove(name); - } - - @Override - public ChildNodeEntry rename(String oldName, String newName) { - if (oldName.equals(newName)) { - return get(oldName); - } - ChildNodeEntry old = remove(oldName); - if (old == null) { - return null; - } - add(new ChildNodeEntry(newName, old.getId())); - return old; - } - - @Override - public Iterator getAdded(ChildNodeEntries other) { - if (other instanceof ChildNodeEntriesHTree) { - return top.getAdded(((ChildNodeEntriesHTree) other).top); - } - // todo optimize - return new AbstractFilteringIterator(other.getEntries(0, -1)) { - @Override - protected boolean include(ChildNodeEntry entry) { - return get(entry.getName()) == null; - } - }; - } - - @Override - public Iterator getRemoved(ChildNodeEntries other) { - return other.getAdded(this); - } - - @Override - public Iterator getModified(final ChildNodeEntries other) { - if (other instanceof ChildNodeEntriesHTree) { - return top.getModified(((ChildNodeEntriesHTree) other).top); - } - // todo optimize - return new AbstractFilteringIterator(getEntries(0, -1)) { - @Override - protected boolean include(ChildNodeEntry entry) { - ChildNodeEntry namesake = other.get(entry.getName()); - return (namesake != null && !namesake.getId().equals(entry.getId())); - } - }; - } - - @Override - public void serialize(Binding binding) throws Exception { - top.serialize(binding); - } - - public void deserialize(Binding binding) throws Exception { - top.deserialize(binding); - } - - @Override - public void prePersist(RevisionStore store, PutToken token) - throws Exception { - - top.prePersist(store, token); - } - - @Override - public void postPersist(RevisionStore store, PutToken token) - throws Exception { - - // nothing to be done here - } - - @Override - public int getMemory() { - return top.getMemory(); - } - -} Index: oak-mk-remote/src/main/java/org/apache/jackrabbit/mk/server/MicroKernelServlet.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-mk-remote/src/main/java/org/apache/jackrabbit/mk/server/MicroKernelServlet.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk-remote/src/main/java/org/apache/jackrabbit/mk/server/MicroKernelServlet.java (revision ) @@ -26,7 +26,7 @@ import org.apache.jackrabbit.mk.api.MicroKernel; import org.apache.jackrabbit.mk.api.MicroKernelException; import org.apache.jackrabbit.oak.commons.json.JsopBuilder; -import org.apache.jackrabbit.mk.util.MicroKernelInputStream; +import org.apache.jackrabbit.oak.commons.mk.MicroKernelInputStream; import org.apache.jackrabbit.oak.commons.IOUtils; /** Index: oak-mk/src/main/java/org/apache/jackrabbit/mk/model/DiffBuilder.java =================================================================== --- oak-mk/src/main/java/org/apache/jackrabbit/mk/model/DiffBuilder.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/main/java/org/apache/jackrabbit/mk/model/DiffBuilder.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,228 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk.model; - -import org.apache.jackrabbit.oak.commons.json.JsopBuilder; -import org.apache.jackrabbit.mk.store.RevisionProvider; -import org.apache.jackrabbit.oak.commons.PathUtils; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -/** - * JSOP Diff Builder - */ -public class DiffBuilder { - - private final Node before; - private final Node after; - private final String path; - private final int depth; - private final String pathFilter; - private final RevisionProvider rp; - - public DiffBuilder(Node before, Node after, String path, int depth, - RevisionProvider rp, String pathFilter) { - this.before = before; - this.after = after; - this.path = path; - this.depth = depth; - this.rp = rp; - this.pathFilter = (pathFilter == null || "".equals(pathFilter)) ? "/" : pathFilter; - } - - public String build() throws Exception { - final JsopBuilder buff = new JsopBuilder(); - - // maps (key: id of target node, value: list of paths to the target) - // for tracking added/removed nodes; this allows us - // to detect 'move' operations - - final HashMap> addedNodes = new HashMap>(); - final HashMap> removedNodes = new HashMap>(); - - if (!PathUtils.isAncestor(path, pathFilter) - && !path.startsWith(pathFilter)) { - return ""; - } - - if (before == null) { - if (after != null) { - buff.tag('+').key(path).object(); - toJson(buff, after, depth); - return buff.endObject().newline().toString(); - } else { - // path doesn't exist in the specified revisions - return ""; - } - } else if (after == null) { - buff.tag('-'); - buff.value(path); - return buff.newline().toString(); - } - - TraversingNodeDiffHandler diffHandler = new TraversingNodeDiffHandler(rp) { - int levels = depth < 0 ? Integer.MAX_VALUE : depth; - @Override - public void propAdded(String propName, String value) { - String p = PathUtils.concat(getCurrentPath(), propName); - if (p.startsWith(pathFilter)) { - buff.tag('^'). - key(p). - encodedValue(value). - newline(); - } - } - - @Override - public void propChanged(String propName, String oldValue, String newValue) { - String p = PathUtils.concat(getCurrentPath(), propName); - if (p.startsWith(pathFilter)) { - buff.tag('^'). - key(p). - encodedValue(newValue). - newline(); - } - } - - @Override - public void propDeleted(String propName, String value) { - String p = PathUtils.concat(getCurrentPath(), propName); - if (p.startsWith(pathFilter)) { - // since property and node deletions can't be distinguished - // using the "- " notation we're representing - // property deletions as "^ :null" - buff.tag('^'). - key(p). - value(null). - newline(); - } - } - - @Override - public void childNodeAdded(ChildNodeEntry added) { - String p = PathUtils.concat(getCurrentPath(), added.getName()); - if (p.startsWith(pathFilter)) { - ArrayList removedPaths = removedNodes.get(added.getId()); - if (removedPaths != null) { - // move detected - String removedPath = removedPaths.remove(0); - if (removedPaths.isEmpty()) { - removedNodes.remove(added.getId()); - } - buff.tag('>'). - // path/to/deleted/node - key(removedPath). - // path/to/added/node - value(p). - newline(); - } else { - ArrayList addedPaths = addedNodes.get(added.getId()); - if (addedPaths == null) { - addedPaths = new ArrayList(); - addedNodes.put(added.getId(), addedPaths); - } - addedPaths.add(p); - } - } - } - - @Override - public void childNodeDeleted(ChildNodeEntry deleted) { - String p = PathUtils.concat(getCurrentPath(), deleted.getName()); - if (p.startsWith(pathFilter)) { - ArrayList addedPaths = addedNodes.get(deleted.getId()); - if (addedPaths != null) { - // move detected - String addedPath = addedPaths.remove(0); - if (addedPaths.isEmpty()) { - addedNodes.remove(deleted.getId()); - } - buff.tag('>'). - // path/to/deleted/node - key(p). - // path/to/added/node - value(addedPath). - newline(); - } else { - ArrayList removedPaths = removedNodes.get(deleted.getId()); - if (removedPaths == null) { - removedPaths = new ArrayList(); - removedNodes.put(deleted.getId(), removedPaths); - } - removedPaths.add(p); - } - } - } - - @Override - public void childNodeChanged(ChildNodeEntry changed, Id newId) { - String p = PathUtils.concat(getCurrentPath(), changed.getName()); - if (PathUtils.isAncestor(p, pathFilter) - || p.startsWith(pathFilter)) { - --levels; - if (levels >= 0) { - // recurse - super.childNodeChanged(changed, newId); - } else { - buff.tag('^'); - buff.key(p); - buff.object().endObject(); - buff.newline(); - } - ++levels; - } - } - }; - diffHandler.start(before, after, path); - - // finally process remaining added nodes ... - for (Map.Entry> entry : addedNodes.entrySet()) { - for (String p : entry.getValue()) { - buff.tag('+'). - key(p).object(); - toJson(buff, rp.getNode(entry.getKey()), depth); - buff.endObject().newline(); - } - } - // ... and removed nodes - for (Map.Entry> entry : removedNodes.entrySet()) { - for (String p : entry.getValue()) { - buff.tag('-'); - buff.value(p); - buff.newline(); - } - } - return buff.toString(); - } - - private void toJson(JsopBuilder builder, Node node, int depth) throws Exception { - for (Map.Entry entry : node.getProperties().entrySet()) { - builder.key(entry.getKey()).encodedValue(entry.getValue()); - } - if (depth != 0) { - for (Iterator it = node.getChildNodeEntries(0, -1); it.hasNext(); ) { - ChildNodeEntry entry = it.next(); - builder.key(entry.getName()).object(); - toJson(builder, rp.getNode(entry.getId()), depth < 0 ? depth : depth - 1); - builder.endObject(); - } - } - } -} Index: oak-mk/src/test/java/org/apache/jackrabbit/mk/MicroKernelImplTest.java =================================================================== --- oak-mk/src/test/java/org/apache/jackrabbit/mk/MicroKernelImplTest.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/src/test/java/org/apache/jackrabbit/mk/MicroKernelImplTest.java (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,434 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.mk; - -import java.io.File; - -import org.apache.commons.io.FileUtils; -import org.apache.jackrabbit.mk.core.MicroKernelImpl; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -public class MicroKernelImplTest { - - private File homeDir; - private MicroKernelImpl mk; - - @Before - public void setup() throws Exception { - homeDir = new File("target/mk"); - if (homeDir.exists()) { - FileUtils.cleanDirectory(homeDir); - } - mk = new MicroKernelImpl(homeDir.getPath()); - } - - @After - public void tearDown() throws Exception { - if (mk != null) { - mk.dispose(); - } - } - - @Test - public void diffWithMove() { - String base = mk.commit("", "+\"/a\":{\"b\":{}}", mk.getHeadRevision(), null); - String head = mk.commit("", "+\"/a/c\":{}+\"/a/d\":{}-\"/a/b\"", base, null); - String diff = mk.diff(base, head, "/a", 0); - assertTrue(diff.contains("c")); - assertTrue(diff.contains("d")); - } - - /** - * OAK-276: potential clash of commit id's after restart. - */ - @Test - public void potentialClashOfCommitIds() { - String headRev = mk.commit("/", "+\"a\" : {}", mk.getHeadRevision(), null); - String branchRev = mk.branch(mk.getHeadRevision()); - - mk.dispose(); - mk = new MicroKernelImpl(homeDir.getPath()); - assertEquals("Stored head should be equal", headRev, mk.getHeadRevision()); - - headRev = mk.commit("/", "+\"b\" : {}", mk.getHeadRevision(), null); - assertFalse("Commit must not have same id as branch", headRev.equals(branchRev)); - } - - @Test - public void diffWithDepth() { - String head = mk.getHeadRevision(); - String r1 = mk.commit("/", "+\"a\" : { \"l\": 1, \"x\": { \"l\": 2, \"y\": {} } }", head, null); - String r2 = mk.commit("/", ">\"a\" : \"b\"", r1, null); - assertEquals("+\"/b\":{\"l\":1}", mk.diff(r1, r2, "/b", 0).trim()); - assertEquals("+\"/b\":{\"l\":1,\"x\":{\"l\":2}}", mk.diff(r1, r2, "/b", 1).trim()); - assertEquals("+\"/b\":{\"l\":1,\"x\":{\"l\":2,\"y\":{}}}", mk.diff(r1, r2, "/b", -1).trim()); - } - - - @Test - public void rebaseWithoutChanges() { - String branch = mk.branch(null); - String rebased = mk.rebase(branch, null); - assertEquals(branch, rebased); - } - - @Test - public void fastForwardRebase() { - String branch = mk.branch(null); - branch = mk.commit("", "+\"/a\":{}", branch, null); - String rebased = mk.rebase(branch, null); - assertEquals(branch, rebased); - } - - @Test - public void rebaseEmptyBranch() { - String branch = mk.branch(null); - String trunk = mk.commit("", "+\"/a\":{}", null, null); - String rebased = mk.rebase(branch, null); - - assertEquals("{\":childNodeCount\":1,\"a\":{}}", mk.getNodes("/", rebased, 0, 0, -1, null)); - assertEquals("{\":childNodeCount\":1,\"a\":{}}", mk.getNodes("/", null, 0, 0, -1, null)); - assertEquals(trunk, mk.getHeadRevision()); - assertFalse((trunk.equals(rebased))); - } - - @Test - public void rebaseAddNode() { - mk.commit("", "+\"/x\":{}", null, null); - String branch = mk.branch(null); - branch = mk.commit("", "+\"/x/b\":{}", branch, null); - String trunk = mk.commit("", "+\"/x/a\":{}", null, null); - String rebased = mk.rebase(branch, null); - - assertEquals(1, mk.getChildNodeCount("/x", null)); - assertNotNull(mk.getNodes("/x/a", null, 0, 0, -1, null)); - - assertEquals(1, mk.getChildNodeCount("/x", branch)); - assertNotNull(mk.getNodes("/x/b", branch, 0, 0, -1, null)); - - assertEquals(2, mk.getChildNodeCount("/x", rebased)); - assertNotNull(mk.getNodes("/x/a", rebased, 0, 0, -1, null)); - assertNotNull(mk.getNodes("/x/b", rebased, 0, 0, -1, null)); - } - - @Test - public void rebaseRemoveNode() { - mk.commit("", "+\"/x\":{\"y\":{}}", null, null); - String branch = mk.branch(null); - branch = mk.commit("", "-\"/x/y\"", branch, null); - String trunk = mk.commit("", "+\"/x/a\":{}", null, null); - String rebased = mk.rebase(branch, null); - - assertEquals(2, mk.getChildNodeCount("/x", null)); - assertNotNull(mk.getNodes("/x/a", null, 0, 0, -1, null)); - assertNotNull(mk.getNodes("/x/y", null, 0, 0, -1, null)); - - assertEquals(0, mk.getChildNodeCount("/x", branch)); - - assertEquals(1, mk.getChildNodeCount("/x", rebased)); - assertNotNull(mk.getNodes("/x/a", rebased, 0, 0, -1, null)); - } - - @Test - public void rebaseAddProperty() { - mk.commit("", "+\"/x\":{\"y\":{}}", null, null); - String branch = mk.branch(null); - branch = mk.commit("", "^\"/x/y/p\":42", branch, null); - String trunk = mk.commit("", "^\"/x/y/q\":99", null, null); - String rebased = mk.rebase(branch, null); - - String branchNode = mk.getNodes("/x/y", branch, 0, 0, -1, null); - assertTrue(branchNode.contains("\"p\":42")); - assertFalse(branchNode.contains("\"q\":99")); - - String rebasedNode = mk.getNodes("/x/y", rebased, 0, 0, -1, null); - assertTrue(rebasedNode.contains("\"p\":42")); - assertTrue(rebasedNode.contains("\"q\":99")); - - String trunkNode = mk.getNodes("/x/y", null, 0, 0, -1, null); - assertFalse(trunkNode.contains("\"p\":42")); - assertTrue(trunkNode.contains("\"q\":99")); - } - - @Test - public void rebaseRemoveProperty() { - mk.commit("", "+\"/x\":{\"y\":{\"p\":42}}", null, null); - String branch = mk.branch(null); - branch = mk.commit("", "^\"/x/y/p\":null", branch, null); - String trunk = mk.commit("", "^\"/x/y/q\":99", null, null); - String rebased = mk.rebase(branch, null); - - String branchNode = mk.getNodes("/x/y", branch, 0, 0, -1, null); - assertFalse(branchNode.contains("\"p\":42")); - assertFalse(branchNode.contains("\"q\":99")); - - String rebasedNode = mk.getNodes("/x/y", rebased, 0, 0, -1, null); - assertFalse(rebasedNode.contains("\"p\":42")); - assertTrue(rebasedNode.contains("\"q\":99")); - - String trunkNode = mk.getNodes("/x/y", null, 0, 0, -1, null); - assertTrue(trunkNode.contains("\"p\":42")); - assertTrue(trunkNode.contains("\"q\":99")); - } - - @Test - public void rebaseChangeProperty() { - mk.commit("", "+\"/x\":{\"y\":{\"p\":42}}", null, null); - String branch = mk.branch(null); - branch = mk.commit("", "^\"/x/y/p\":41", branch, null); - String trunk = mk.commit("", "^\"/x/y/q\":99", null, null); - String rebased = mk.rebase(branch, null); - - String branchNode = mk.getNodes("/x/y", branch, 0, 0, -1, null); - assertTrue(branchNode.contains("\"p\":41")); - assertFalse(branchNode.contains("\"q\":99")); - - String rebasedNode = mk.getNodes("/x/y", rebased, 0, 0, -1, null); - assertTrue(rebasedNode.contains("\"p\":41")); - assertTrue(rebasedNode.contains("\"q\":99")); - - String trunkNode = mk.getNodes("/x/y", null, 0, 0, -1, null); - assertTrue(trunkNode.contains("\"p\":42")); - assertTrue(trunkNode.contains("\"q\":99")); - } - - @Test - public void rebaseChangePropertyWithSameValue() { - mk.commit("", "+\"/x\":{\"y\":{\"p\":42}}", null, null); - String branch = mk.branch(null); - branch = mk.commit("", "^\"/x/y/p\":99", branch, null); - String trunk = mk.commit("", "^\"/x/y/p\":99", null, null); - String rebased = mk.rebase(branch, null); - - String branchNode = mk.getNodes("/x/y", branch, 0, 0, -1, null); - assertTrue(branchNode.contains("\"p\":99")); - - String rebasedNode = mk.getNodes("/x/y", branch, 0, 0, -1, null); - assertTrue(rebasedNode.contains("\"p\":99")); - - String trunkNode = mk.getNodes("/x/y", null, 0, 0, -1, null); - assertTrue(trunkNode.contains("\"p\":99")); - } - - @Test - public void rebaseAddExistingNode() { - mk.commit("", "+\"/x\":{}", null, null); - String branch = mk.branch(null); - branch = mk.commit("", "+\"/x/a\":{\"foo\":true}", branch, null); - mk.commit("", "+\"/x/a\":{\"b\":{}}", null, null); - - branch = mk.rebase(branch, null); - - assertTrue(mk.nodeExists("/x/a/b", branch)); - assertFalse(mk.nodeExists("/x/a/foo", null)); - String branchNode = mk.getNodes("/x", branch, 100, 0, -1, null); - assertFalse(branchNode.contains(":conflict")); - } - - @Test - public void rebaseAddExistingConflictingNode() { - mk.commit("", "+\"/x\":{}", null, null); - String branch = mk.branch(null); - branch = mk.commit("", "+\"/x/a\":{\"foo\":true}", branch, null); - mk.commit("", "+\"/x/a\":{\"foo\":false,\"b\":{}}", null, null); - - branch = mk.rebase(branch, null); - - assertTrue(mk.nodeExists("/x/a/b", branch)); - String branchNode = mk.getNodes("/x", branch, 100, 0, -1, null); - assertTrue(branchNode.contains(":conflict")); - } - - @Test - public void rebaseAddExistingProperties() { - mk.commit("", "+\"/x\":{\"y\":{}}", null, null); - String branch = mk.branch(null); - branch = mk.commit("", "^\"/x/y/p\":42 ^\"/x/y/q\":42", branch, null); - mk.commit("", "^\"/x/y/p\":99 ^\"/x/y/q\":99", null, null); - - branch = mk.rebase(branch, null); - - String branchNode = mk.getNodes("/x/y", branch, 0, 0, -1, null); - assertTrue(branchNode.contains("\"p\":99")); - String conflict = mk.getNodes("/x/y/:conflict", branch, 100, 0, -1, null); - assertTrue(conflict, - conflict.equals("{\":childNodeCount\":1,\"addExistingProperty\":{\"q\":42,\"p\":42,\":childNodeCount\":0}}") || - conflict.equals("{\":childNodeCount\":1,\"addExistingProperty\":{\"p\":42,\"q\":42,\":childNodeCount\":0}}")); - } - - @Test - public void rebaseChangeRemovedProperty() { - mk.commit("", "+\"/x\":{\"y\":{\"p\":42}}", null, null); - String branch = mk.branch(null); - branch = mk.commit("", "^\"/x/y/p\":99", branch, null); - mk.commit("", "^\"/x/y/p\":null", null, null); - - branch = mk.rebase(branch, null); - - String branchNode = mk.getNodes("/x/y", branch, 0, 0, -1, null); - assertFalse(branchNode.contains("\"p\":99")); - String conflict = mk.getNodes("/x/y/:conflict", branch, 100, 0, -1, null); - assertEquals( - "{\":childNodeCount\":1,\"changeDeletedProperty\":{\"p\":99,\":childNodeCount\":0}}", - conflict); - } - - @Test - public void rebaseRemoveChangedProperty() { - mk.commit("", "+\"/x\":{\"y\":{\"p\":42}}", null, null); - String branch = mk.branch(null); - branch = mk.commit("", "^\"/x/y/p\":null", branch, null); - mk.commit("", "^\"/x/y/p\":99", null, null); - - branch = mk.rebase(branch, null); - - String branchNode = mk.getNodes("/x/y", branch, 0, 0, -1, null); - assertTrue(branchNode.contains("\"p\":99")); - String conflict = mk.getNodes("/x/y/:conflict", branch, 100, 0, -1, null); - assertEquals( - "{\":childNodeCount\":1,\"deleteChangedProperty\":{\"p\":42,\":childNodeCount\":0}}", - conflict); - } - - @Test - public void rebaseChangedChangedProperty() { - mk.commit("", "+\"/x\":{\"y\":{\"p\":42}}", null, null); - String branch = mk.branch(null); - branch = mk.commit("", "^\"/x/y/p\":41", branch, null); - mk.commit("", "^\"/x/y/p\":99", null, null); - - branch = mk.rebase(branch, null); - - String branchNode = mk.getNodes("/x/y", branch, 0, 0, -1, null); - assertTrue(branchNode.contains("\"p\":99")); - String conflict = mk.getNodes("/x/y/:conflict", branch, 100, 0, -1, null); - assertEquals( - "{\":childNodeCount\":1,\"changeChangedProperty\":{\"p\":41,\":childNodeCount\":0}}", - conflict); - } - - @Test - public void rebaseRemoveChangedNode() { - mk.commit("", "+\"/x\":{\"y\":{}}", null, null); - String branch = mk.branch(null); - branch = mk.commit("", "-\"/x/y\"", branch, null); - mk.commit("", "^\"/x/y/p\":42", null, null); - - branch = mk.rebase(branch, null); - - String branchNode = mk.getNodes("/x/y", branch, 0, 0, -1, null); - assertTrue(branchNode.contains("\"p\":42")); - String conflict = mk.getNodes("/x/:conflict", branch, 100, 0, -1, null); - assertEquals( - "{\":childNodeCount\":1,\"deleteChangedNode\":{\":childNodeCount\":1,\"y\":{\":childNodeCount\":0}}}", - conflict); - } - - @Test - public void rebaseChangeRemovedNode() { - mk.commit("", "+\"/x\":{\"y\":{}}", null, null); - String branch = mk.branch(null); - branch = mk.commit("", "^\"/x/p\":42", branch, null); - mk.commit("", "-\"/x\"", null, null); - - branch = mk.rebase(branch, null); - - assertFalse(mk.nodeExists("/x", branch)); - String conflict = mk.getNodes("/:conflict", branch, 100, 0, -1, null); - assertEquals( - "{\":childNodeCount\":1,\"changeDeletedNode\":{\":childNodeCount\":1,\"x\":{\"p\":42,\"" + - ":childNodeCount\":1,\"y\":{\":childNodeCount\":0}}}}", - conflict); - } - - @Test - public void rebaseRemoveRemovedProperty() { - mk.commit("", "+\"/x\":{\"y\":{\"p\":42}}", null, null); - String branch = mk.branch(null); - branch = mk.commit("", "^\"/x/y/p\":null", branch, null); - mk.commit("", "^\"/x/y/p\":null", null, null); - - branch = mk.rebase(branch, null); - - String branchNode = mk.getNodes("/x/y", branch, 0, 0, -1, null); - assertFalse(branchNode.contains("\"p\":42")); - String conflict = mk.getNodes("/x/y/:conflict", branch, 100, 0, -1, null); - assertEquals( - "{\":childNodeCount\":1,\"deleteDeletedProperty\":{\"p\":42,\":childNodeCount\":0}}", - conflict); - } - - @Test - public void rebaseRemoveRemovedNode() { - mk.commit("", "+\"/x\":{\"y\":{}}", null, null); - String branch = mk.branch(null); - branch = mk.commit("", "-\"/x/y\"", branch, null); - mk.commit("", "-\"/x/y\"", null, null); - - branch = mk.rebase(branch, null); - - assertFalse(mk.nodeExists("/x/y", branch)); - String conflict = mk.getNodes("/x/:conflict", branch, 100, 0, -1, null); - assertEquals( - "{\":childNodeCount\":1,\"deleteDeletedNode\":{\":childNodeCount\":1,\"y\":{\":childNodeCount\":0}}}", - conflict); - } - - @Test - public void mergeRebased() { - mk.commit("", "+\"/x\":{\"y\":{}}", null, null); - String branch = mk.branch(null); - String trunk = mk.commit("", "^\"/x/p\":42", null, null); - branch = mk.commit("", "^\"/x/q\":43", branch, null); - branch = mk.rebase(branch, null); - - String branchNode = mk.getNodes("/x", branch, 0, 0, -1, null); - assertTrue(branchNode.contains("\"p\":42")); - assertTrue(branchNode.contains("\"q\":43")); - - mk.merge(branch, null); - String trunkNode = mk.getNodes("/x", branch, 0, 0, -1, null); - assertTrue(trunkNode.contains("\"p\":42")); - assertTrue(trunkNode.contains("\"q\":43")); - } - - @Test // OAK-1122 - public void emptyCommit() { - String rev = mk.getHeadRevision(); - assertEquals("empty commit must return current head revision", - rev, mk.commit("/", "", rev, null)); - // now the same on a branch - rev = mk.branch(rev); - // commit something to branch - rev = mk.commit("/", "+\"x\":{}", rev, null); - assertEquals("empty branch commit must return current head of branch revision", - rev, mk.commit("/", "", rev, null)); - } - - @Test(expected = Throwable.class) - public void foo() { - mk.commit("", "+\"/x\":{}", null, null); - mk.commit("", "+\"/x/\":{}", null, null); - } -} Index: oak-mk/pom.xml =================================================================== --- oak-mk/pom.xml (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) +++ oak-mk/pom.xml (revision 66a4bbb0d497e5d0849bf585cb170a8b9b3f8852) @@ -1,160 +0,0 @@ - - - - - - 4.0.0 - - - org.apache.jackrabbit - oak-parent - 1.1-SNAPSHOT - ../oak-parent/pom.xml - - - oak-mk - Oak MicroKernel - bundle - - - - - org.apache.felix - maven-bundle-plugin - - - - org.apache.jackrabbit.mk.json, - org.apache.jackrabbit.mk.util, - org.apache.jackrabbit.mk.core, - org.apache.jackrabbit.mk.blobs - - - - - - org.apache.felix - maven-scr-plugin - - - - - - - - org.osgi - org.osgi.core - provided - - - org.osgi - org.osgi.compendium - provided - - - biz.aQute.bnd - bndlib - provided - - - org.apache.felix - org.apache.felix.scr.annotations - provided - - - - - org.apache.jackrabbit - oak-mk-api - ${project.version} - - - - - org.apache.jackrabbit - oak-commons - ${project.version} - - - - - org.apache.jackrabbit - oak-blob - ${project.version} - - - - - org.slf4j - slf4j-api - - - - - com.google.guava - guava - - - - - com.h2database - h2 - ${h2.version} - true - - - - - com.google.code.findbugs - jsr305 - - - - - commons-io - commons-io - 1.4 - - - - - com.googlecode.json-simple - json-simple - 1.1 - test - - - junit - junit - test - - - ch.qos.logback - logback-classic - test - - - org.apache.jackrabbit - oak-commons - ${project.version} - tests - test - - - -