Return-Path: Delivered-To: apmail-jackrabbit-commits-archive@www.apache.org Received: (qmail 49792 invoked from network); 18 Apr 2010 09:53:22 -0000 Received: from unknown (HELO mail.apache.org) (140.211.11.3) by 140.211.11.9 with SMTP; 18 Apr 2010 09:53:22 -0000 Received: (qmail 46917 invoked by uid 500); 18 Apr 2010 09:53:21 -0000 Delivered-To: apmail-jackrabbit-commits-archive@jackrabbit.apache.org Received: (qmail 46835 invoked by uid 500); 18 Apr 2010 09:53:21 -0000 Mailing-List: contact commits-help@jackrabbit.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@jackrabbit.apache.org Delivered-To: mailing list commits@jackrabbit.apache.org Received: (qmail 46828 invoked by uid 99); 18 Apr 2010 09:53:21 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 18 Apr 2010 09:53:21 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED,T_FRT_STOCK2 X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 18 Apr 2010 09:53:14 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 17794238890B; Sun, 18 Apr 2010 09:52:29 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r935321 [1/2] - in /jackrabbit/sandbox/jackrabbit-j3/src: main/java/org/apache/jackrabbit/j3/ main/java/org/apache/jackrabbit/j3/mc/ main/java/org/apache/jackrabbit/j3/mc/jdbc/ main/java/org/apache/jackrabbit/j3/mc/mem/ main/java/org/apache... Date: Sun, 18 Apr 2010 09:52:28 -0000 To: commits@jackrabbit.apache.org From: thomasm@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20100418095229.17794238890B@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: thomasm Date: Sun Apr 18 09:52:27 2010 New Revision: 935321 URL: http://svn.apache.org/viewvc?rev=935321&view=rev Log: Unlimited transient space / transaction size Added: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/ChangeSet.java jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventFilter.java jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventJournalImpl.java jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestEventJournal.java jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/slow/ jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/slow/TestLargeTransaction.java Removed: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventList.java Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/NodeImpl.java jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/NodeState.java jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/RangeIteratorImpl.java jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/RepositoryImpl.java jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/SessionImpl.java jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/Bundle.java jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/NodeData.java jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/StorageSession.java jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/jdbc/JdbcStorage.java jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/jdbc/JdbcStorageSession.java jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/mem/MemStorageSession.java jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/nodetype/NodeTypeImpl.java jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/nodetype/NodeTypeIteratorImpl.java jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddLock.java jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddMixin.java jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddNode.java jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddProperty.java jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventConsumer.java jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventImpl.java jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventModifyProperty.java jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventRemoveNode.java jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/ObservationManagerImpl.java jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/query/RowIteratorImpl.java jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/security/AccessControlManagerImpl.java jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/util/Constants.java jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/version/VersionIteratorImpl.java jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestAll.java jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestBundle.java jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestConcurrentWrite.java jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestLock.java jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestObservation.java jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestSimple.java Added: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/ChangeSet.java URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/ChangeSet.java?rev=935321&view=auto ============================================================================== --- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/ChangeSet.java (added) +++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/ChangeSet.java Sun Apr 18 09:52:27 2010 @@ -0,0 +1,384 @@ +/* + * 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.j3; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.BitSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import javax.jcr.RepositoryException; +import org.apache.jackrabbit.j3.mc.Bundle; +import org.apache.jackrabbit.j3.mc.NodeData; +import org.apache.jackrabbit.j3.mc.StorageSession; +import org.apache.jackrabbit.j3.mc.Val; +import org.apache.jackrabbit.j3.observation.EventImpl; +import org.apache.jackrabbit.j3.util.Constants; +import org.apache.jackrabbit.j3.util.ExceptionFactory; +import org.apache.jackrabbit.j3.util.Log; + +/** + * This objects keeps changed nodes and events for a session. Once there are too + * many entries, the data is stored in a backend storage. + */ +public class ChangeSet { + + private final LinkedHashMap nodes = new LinkedHashMap(); + private final LinkedList events = new LinkedList(); + private final int maxMemorySize; + private final SessionImpl session; + private final StorageSession storageSession; + private final Log log; + private final boolean unlimited; + private String userId; + private int tempBlocks; + private long persistedDate; + private String userData; + private int nodeMemoryUsed; + private int nodesCountTotal; + private boolean persistEvents = true; + + /** + * A bloom filter to quickly check if an entry might be in the backend storage. + */ + private final BitSet backendFilter = new BitSet(); + private final int backendFilterMask; + + public ChangeSet(SessionImpl session, StorageSession storageSession, int maxMemorySize) { + this.session = session; + this.storageSession = storageSession; + this.maxMemorySize = maxMemorySize; + this.log = session.getLog(); + this.userId = session.getUserId(); + if (maxMemorySize == Integer.MAX_VALUE) { + unlimited = true; + backendFilterMask = 0; + } else { + unlimited = false; + // the bloom filter uses about 10% of the cache size + int maxFilterBytes = maxMemorySize / 10; + int maxFilterBits = maxFilterBytes * 8; + int p = 4; + while (p < maxFilterBits) { + p <<= 1; + } + backendFilterMask = (p >> 1) - 1; + } + } + + public Iterator valueIterator() { + if (tempBlocks == 0) { + return nodes.values().iterator(); + } + return new TransientNodeIterator(nodes.values().iterator(), tempBlocks); + } + + public NodeState get(Val key) { + NodeState node = nodes.get(key); + if (node != null || unlimited) { + return node; + } + if (!backendFilter.get(key.hashCode() & backendFilterMask)) { + return null; + } + NodeData data = storageSession.getNode(key); + if (data == null) { + return null; + } + node = new NodeState(session, data, 0); + put(key, node); + return node; + } + + public void put(Val key, NodeState value) { + NodeState old = nodes.put(key, value); + if (old == value) { + return; + } + if (unlimited) { + nodesCountTotal = nodes.size(); + return; + } + if (old != null) { + nodeMemoryUsed -= old.getNodeData().getMemoryUsed(); + } else { + nodesCountTotal++; + } + nodeMemoryUsed += value.getNodeData().getMemoryUsed(); + if (nodeMemoryUsed + events.size() * Constants.MEM_EVENT > maxMemorySize) { + store(true, nodes.size() / 2); + } + } + + boolean hasPendingChanges() { + return nodesCountTotal > 0; + } + + void clearAll() { + clearNodes(); + clearEvents(); + tempBlocks = 0; + } + + void clearEvents() { + events.clear(); + if (tempBlocks > 0) { + storageSession.clearTemp(false, true); + } + } + + void clearNodes() { + nodesCountTotal = 0; + nodes.clear(); + if (tempBlocks > 0) { + backendFilter.clear(); + storageSession.clearTemp(true, false); + } + nodeMemoryUsed = 0; + } + + public void storeAll() { + store(false, 0); + } + + private void store(boolean temporary, int skip) { + Iterator it = nodes.values().iterator(); + NodeData[] nodeArray = new NodeData[nodes.size() - skip]; + // re-calculate the memory because it might have changed + nodeMemoryUsed = 0; + for (int i = 0; it.hasNext() && i < skip; i++) { + NodeData n = it.next().getNodeData(); + nodeMemoryUsed += n.getMemoryUsed(); + } + for (int i = 0; it.hasNext(); i++) { + NodeData n = it.next().getNodeData(); + if (temporary) { + backendFilter.set(n.getId().hashCode() & backendFilterMask); + it.remove(); + } + nodeArray[i] = n; + } + Bundle[] bundles; + if (persistEvents || temporary) { + bundles = getEventBundles(); + } else { + bundles = null; + } + if (temporary) { + storageSession.storeTemp(tempBlocks++, nodeArray, bundles); + events.clear(); + } else { + long now = System.currentTimeMillis(); + storageSession.store(now, nodeArray, bundles); + } + } + + public SessionImpl getSession() { + return session; + } + + public Log getLog() { + return log; + } + + public void dispatchEvents() { + persistedDate = System.currentTimeMillis(); + userData = session.getObservationUserData(); + session.getRepository().dispatchEvents(this); + } + + public long getPersistedDate() { + return persistedDate; + } + + public void applyEvents() throws RepositoryException { + Iterator it = getEvents(); + while (it.hasNext()) { + it.next().apply(); + } + } + + public Iterator getEvents() { + if (tempBlocks == 0) { + return events.iterator(); + } + return new EventIterator(events.iterator(), tempBlocks); + } + + public void addEvent(EventImpl event) { + events.add(event); + } + + private Bundle[] getEventBundles() { + ArrayList bundles = new ArrayList(); + Bundle b = null; + for (EventImpl e : events) { + if (b == null) { + b = new Bundle(new byte[events.size()]); + writeHeader(b); + } + e.writeTo(b); + if (b.getPos() > Constants.SIZE_EVENT_BUNDLE) { + bundles.add(b); + b = null; + } + } + if (b != null && b.getPos() > 0) { + bundles.add(b); + } + return bundles.toArray(new Bundle[bundles.size()]); + } + + private void writeHeader(Bundle b) { + if (userId != null) { + b.writeVarInt(EventImpl.TOKEN_USER_ID); + b.writeVal(Val.get(userId)); + } + if (userData != null) { + b.writeVarInt(EventImpl.TOKEN_USER_DATA); + b.writeVal(Val.get(userData)); + } + } + + public String getUserData() { + return userData; + } + + public String getUserID() { + return userId; + } + + public String toString() { + return "nodes: " + nodesCountTotal + " events: " + events.size() + " temp blocks: " + tempBlocks; + } + + /** + * An iterator over all events. + */ + class EventIterator implements Iterator { + + private final int maxBlock; + private Iterator iterator; + private Iterator lastIterator; + private EventImpl current; + private int currentBlock; + + EventIterator(Iterator lastIterator, int maxBlock) { + this.lastIterator = lastIterator; + this.maxBlock = maxBlock; + go(); + } + + private void go() { + while (true) { + if (iterator == null) { + if (currentBlock == maxBlock) { + iterator = lastIterator; + } else { + Bundle[] bundles = storageSession.getTempEvents(currentBlock++); + iterator = EventImpl.readFrom(ChangeSet.this, bundles); + } + } + if (iterator.hasNext()) { + current = iterator.next(); + break; + } + if (iterator == lastIterator) { + current = null; + break; + } + iterator = null; + } + } + + public boolean hasNext() { + return current != null; + } + + public EventImpl next() { + EventImpl e = current; + go(); + return e; + } + + public void remove() { + throw ExceptionFactory.unsupportedOperation(); + } + + } + + /** + * An iterator over all nodes. + */ + class TransientNodeIterator implements Iterator { + + private final int maxBlock; + private Iterator iterator; + private NodeState current; + private int currentBlock; + + TransientNodeIterator(Iterator iterator, int maxBlock) { + this.iterator = iterator; + this.maxBlock = maxBlock; + go(); + } + + public boolean hasNext() { + return current != null; + } + + public NodeState next() { + NodeState n = current; + go(); + return n; + } + + private void go() { + while (true) { + if (iterator.hasNext()) { + current = iterator.next(); + break; + } + if (currentBlock == maxBlock) { + current = null; + break; + } + NodeData[] data = storageSession.getTempNodes(currentBlock++); + NodeState[] nodes = new NodeState[data.length]; + for (int i = 0; i < nodes.length; i++) { + nodes[i] = new NodeState(session, data[i], 0); + } + iterator = Arrays.asList(nodes).iterator(); + } + } + + public void remove() { + throw ExceptionFactory.unsupportedOperation(); + } + + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public void setUserData(String userData) { + this.userData = userData; + } + +} Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/NodeImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/NodeImpl.java?rev=935321&r1=935320&r2=935321&view=diff ============================================================================== --- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/NodeImpl.java (original) +++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/NodeImpl.java Sun Apr 18 09:52:27 2010 @@ -19,6 +19,7 @@ package org.apache.jackrabbit.j3; import java.io.InputStream; import java.math.BigDecimal; import java.util.Calendar; +import java.util.HashSet; import javax.jcr.AccessDeniedException; import javax.jcr.Binary; import javax.jcr.InvalidItemStateException; @@ -52,6 +53,7 @@ import javax.jcr.version.VersionHistory; import org.apache.jackrabbit.j3.lock.LockImpl; import org.apache.jackrabbit.j3.mc.Val; import org.apache.jackrabbit.j3.nodetype.NodeTypeImpl; +import org.apache.jackrabbit.j3.nodetype.NodeTypeManagerImpl; import org.apache.jackrabbit.j3.nodetype.PropertyDefinitionImpl; import org.apache.jackrabbit.j3.observation.EventAddLock; import org.apache.jackrabbit.j3.observation.EventAddMixin; @@ -96,8 +98,10 @@ public class NodeImpl implements Node, L private NodeImpl addNode(String relPath, NodeTypeImpl nt) throws RepositoryException { SessionImpl s = state.getSession(); synchronized (s) { - NodeImpl node = s.createNode(this, state.getId()); - EventAddNode event = new EventAddNode(s, Val.get(relPath), node); + Val nodeId = s.getStorageSession().newNodeId(state.getId()); + EventAddNode event = new EventAddNode(s.getTransientChanges(), this, Val.get(relPath), nodeId); + event.applyAndAdd(); + NodeImpl node = event.getNode(); Val primaryNodeType; if (nt == null) { // TODO primaryNodeTypeName may be incorrect @@ -105,9 +109,8 @@ public class NodeImpl implements Node, L } else { primaryNodeType = nt.getNameVal(); } - EventAddProperty eventSetPrimaryType = new EventAddProperty(s, node, NodeState.PROPERTY_PRIMARY_TYPE, primaryNodeType); + EventAddProperty eventSetPrimaryType = new EventAddProperty(s.getTransientChanges(), node, NodeState.PROPERTY_PRIMARY_TYPE, primaryNodeType); eventSetPrimaryType.applyAndAdd(); - event.applyAndAdd(); if (nt != null) { nt.visit(node); } @@ -120,7 +123,7 @@ public class NodeImpl implements Node, L if (p.isAutoCreated()) { Val propertyName = p.getNameVal(); Val value = p.getDefaultVal(); - EventModifyProperty event = new EventModifyProperty(s, this, propertyName, value); + EventModifyProperty event = new EventModifyProperty(s.getTransientChanges(), this, propertyName, value); event.applyAndAdd(); } } @@ -158,10 +161,18 @@ public class NodeImpl implements Node, L private PropertyImpl setProperty(String name, Val value) throws RepositoryException { SessionImpl s = state.getSession(); Val propertyName = Val.get(name); - EventModifyProperty event = new EventModifyProperty(s, this, propertyName, value); - synchronized (s) { - event.applyAndAdd(); - return new PropertyImpl(this, propertyName); + if (state.getPropertyInternal(propertyName) != null) { + EventModifyProperty event = new EventModifyProperty(s.getTransientChanges(), this, propertyName, value); + synchronized (s) { + event.applyAndAdd(); + return new PropertyImpl(this, propertyName); + } + } else { + EventAddProperty event = new EventAddProperty(s.getTransientChanges(), this, propertyName, value); + synchronized (s) { + event.applyAndAdd(); + return new PropertyImpl(this, propertyName); + } } } @@ -184,7 +195,7 @@ public class NodeImpl implements Node, L return getValueFactory().wrap(state.getPropertyInternal(name)); } - public NodeImpl getParent() throws ItemNotFoundException, AccessDeniedException, RepositoryException { + public NodeImpl getParent() { log.codeAssign(parent, this, "getParent"); return parent; } @@ -258,7 +269,7 @@ public class NodeImpl implements Node, L throw ExceptionFactory.repository("Can not remove the root node"); } synchronized (s) { - EventRemoveNode event = new EventRemoveNode(s, this); + EventRemoveNode event = new EventRemoveNode(s.getTransientChanges(), this); event.applyAndAdd(); } } @@ -306,7 +317,7 @@ public class NodeImpl implements Node, L ConstraintViolationException, LockException, RepositoryException { log.code(this, "addMixin", mixinName); SessionImpl s = state.getSession(); - EventAddMixin event = new EventAddMixin(s, this, Val.get(mixinName)); + EventAddMixin event = new EventAddMixin(s.getTransientChanges(), this, Val.get(mixinName)); synchronized (s) { event.applyAndAdd(); } @@ -333,7 +344,7 @@ public class NodeImpl implements Node, L // TODO the lock token currently is the node id; this is not secure Val lockToken = state.getId(); LockImpl lock = new LockImpl(this, lockToken, isDeep, isSessionScoped); - EventAddLock event = new EventAddLock(s, lock); + EventAddLock event = new EventAddLock(s.getTransientChanges(), lock); synchronized (s) { event.applyAndAdd(); } @@ -458,6 +469,48 @@ public class NodeImpl implements Node, L return log; } + public boolean matchesNodeTypeSet(HashSet nodeTypeSet) throws RepositoryException { + for (NodeType nt : nodeTypeSet) { + if (isNodeType(nt)) { + return true; + } + } + return false; + } + + private boolean isNodeType(NodeType nt) throws RepositoryException { + if (getPrimaryNodeType().isNodeType(nt)) { + return true; + } + for (NodeTypeImpl mixin : getMixinNodeTypes()) { + if (mixin.isNodeType(nt)) { + return true; + } + } + return false; + } + + public NodeTypeImpl[] getMixinNodeTypes() throws RepositoryException { + log.code(this, "getMixinNodeTypes"); + Val m = state.getPropertyInternal(NodeState.PROPERTY_MIXIN_TYPES); + if (m == null) { + return NodeTypeImpl.EMPTY_ARRAY; + } + Val[] array = m.getArray(); + NodeTypeImpl[] mixins = new NodeTypeImpl[array.length]; + NodeTypeManagerImpl ntMan = state.getSession().getNodeTypeManager(); + for (int i = 0; i < array.length; i++) { + mixins[i] = ntMan.getNodeType(array[i]); + } + return mixins; + } + + public boolean isNodeType(String nodeTypeName) throws RepositoryException { + log.code(this, "isNodeType", nodeTypeName); + NodeType nt = getSession().getNodeTypeManager().getNodeType(nodeTypeName); + return isNodeType(nt); + } + public Item getPrimaryItem() throws ItemNotFoundException, RepositoryException { log.code(this, "getPrimaryItem"); // TODO @@ -544,12 +597,6 @@ public class NodeImpl implements Node, L return null; } - public NodeType[] getMixinNodeTypes() throws RepositoryException { - log.code(this, "getMixinNodeTypes"); - // TODO - return null; - } - public NodeIterator getNodes(String namePattern) throws RepositoryException { log.code(this, "getNodes", namePattern); // TODO @@ -652,12 +699,6 @@ public class NodeImpl implements Node, L return false; } - public boolean isNodeType(String nodeTypeName) throws RepositoryException { - log.code(this, "isNodeType", nodeTypeName); - // TODO - return false; - } - public NodeIterator merge(String srcWorkspace, boolean bestEffort) throws NoSuchWorkspaceException, AccessDeniedException, MergeException, LockException, InvalidItemStateException, RepositoryException { log.code(this, "merge", srcWorkspace, bestEffort); Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/NodeState.java URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/NodeState.java?rev=935321&r1=935320&r2=935321&view=diff ============================================================================== --- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/NodeState.java (original) +++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/NodeState.java Sun Apr 18 09:52:27 2010 @@ -48,13 +48,16 @@ public class NodeState { this.modCount = modCount; } - void modify() { + void modifyBegin() { if (modCount++ == 0) { data = data.createCopy(); - session.modify(this); } } + void modifyEnd() { + session.modify(this); + } + void reset(NodeData data) { modCount = 0; this.data = data; @@ -70,7 +73,7 @@ public class NodeState { * @param value the value */ void setPropertyInternal(Val name, Val value) { - modify(); + modifyBegin(); if (name.equals(NodeState.PROPERTY_PRIMARY_TYPE)) { if (value.equals(DEFAULT_PRIMARY_TYPE)) { data.setPrimaryType(null); @@ -80,6 +83,7 @@ public class NodeState { } else { data.setPropertyValue(name, value); } + modifyEnd(); } /** @@ -124,7 +128,7 @@ public class NodeState { return v; } - Val getId() { + public Val getId() { return data.getId(); } @@ -133,18 +137,21 @@ public class NodeState { } void addChild(Val childName, Val id) { - modify(); + modifyBegin(); data.addChild(childName, id); + modifyEnd(); } void removeChild(Val childName) { - modify(); + modifyBegin(); data.removeChild(childName); + modifyEnd(); } void setLockToken(Val lockToken) { - modify(); + modifyBegin(); data.setLockToken(lockToken); + modifyEnd(); } Val getName(NodeState parent) { @@ -197,4 +204,8 @@ public class NodeState { return data.getNextChildId(last == null ? null : last.data); } + boolean isModified() { + return modCount != 0; + } + } Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/RangeIteratorImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/RangeIteratorImpl.java?rev=935321&r1=935320&r2=935321&view=diff ============================================================================== --- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/RangeIteratorImpl.java (original) +++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/RangeIteratorImpl.java Sun Apr 18 09:52:27 2010 @@ -40,14 +40,14 @@ public abstract class RangeIteratorImpl< this.iterator = iterator; this.size = size; this.log = log; - go(); + fetchNext(); } public boolean skip(T x) throws RepositoryException { return false; } - void go() { + void fetchNext() { try { while (true) { if (!iterator.hasNext()) { @@ -66,16 +66,16 @@ public abstract class RangeIteratorImpl< } public Object next() { - return goNext(); + return getNext(); } - public T goNext() { + public T getNext() { pos++; T result = next; if (result == null) { throw ExceptionFactory.noSuchElement(); } - go(); + fetchNext(); return result; } @@ -92,7 +92,7 @@ public abstract class RangeIteratorImpl< public void skip(long skipNum) { log.code(this, "skip", skipNum); for (int i = 0; i < skipNum; i++) { - go(); + getNext(); } } Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/RepositoryImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/RepositoryImpl.java?rev=935321&r1=935320&r2=935321&view=diff ============================================================================== --- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/RepositoryImpl.java (original) +++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/RepositoryImpl.java Sun Apr 18 09:52:27 2010 @@ -36,7 +36,6 @@ import org.apache.jackrabbit.j3.mc.Val; import org.apache.jackrabbit.j3.mc.jdbc.JdbcStorage; import org.apache.jackrabbit.j3.mc.mem.MemStorage; import org.apache.jackrabbit.j3.nodetype.NodeTypeRegistry; -import org.apache.jackrabbit.j3.observation.EventList; import org.apache.jackrabbit.j3.query.qom.QueryObjectModelFactoryImpl; import org.apache.jackrabbit.j3.util.Cache; import org.apache.jackrabbit.j3.util.Constants; @@ -289,9 +288,9 @@ public class RepositoryImpl implements R return lockSystem; } - public synchronized void dispatchEvents(EventList events) { + public synchronized void dispatchEvents(ChangeSet changes) { for (SessionImpl session : sessions) { - session.dispatchEvents(events); + session.dispatchEvents(changes); } } @@ -307,4 +306,53 @@ public class RepositoryImpl implements R return qomFactory; } + static int getWorkspaceId(long nodeId) { + if ((nodeId & 1) == 0) { + return 0; + } else if ((nodeId & 3) == 1) { + return (int) ((nodeId >> 2) & ((1 << 4) - 1)); + } else if ((nodeId & 7) == 3) { + return (int) ((nodeId >> 3) & ((1 << 11) - 1)); + } else if ((nodeId & 15) == 7) { + return (int) ((nodeId >> 4) & ((1 << 28) - 1)); + } else { + throw ExceptionFactory.illegalArgument("Node {0}", nodeId); + } + } + + static long getBaseNodeId(long nodeId) { + if ((nodeId & 1) == 0) { + return nodeId >> 1; + } else if ((nodeId & 3) == 1) { + return nodeId >> 6; + } else if ((nodeId & 7) == 3) { + return nodeId >> 14; + } else if ((nodeId & 15) == 7) { + return nodeId >> 32; + } else { + throw ExceptionFactory.illegalArgument("Node {0}", nodeId); + } + } + + static long getNodeId(int workspaceId, long baseNodeId) { + if (workspaceId == 0) { + // ... nnnnnnnn nnnnnnn0 + return baseNodeId << 1; + } else if ((workspaceId & ~((1 << 4) - 1)) == 0) { + // up to workspace #15 + // ... nnnnnnnn nnwwww01 + return (baseNodeId << 6) + (workspaceId << 2) + 1; + } else if ((workspaceId & ~((1 << 11) - 1)) == 0) { + // up to workspace #2047 + // ... nnwwwwww wwwww011 + return (baseNodeId << 14) + (workspaceId << 3) + 3; + } else if ((workspaceId & ~((1 << 28) - 1)) == 0) { + // up to workspace #268'435'455 + // ... nnnnnnnn wwwwww ... wwww0111 + return (baseNodeId << 32) + ((long) workspaceId << 4) + 7; + } else { + throw ExceptionFactory.illegalArgument("Workspace {0}", workspaceId); + } + } + } Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/SessionImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/SessionImpl.java?rev=935321&r1=935320&r2=935321&view=diff ============================================================================== --- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/SessionImpl.java (original) +++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/SessionImpl.java Sun Apr 18 09:52:27 2010 @@ -21,9 +21,9 @@ import java.io.InputStream; import java.io.OutputStream; import java.lang.ref.WeakReference; import java.security.AccessControlException; -import java.util.HashMap; import java.util.Iterator; import java.util.WeakHashMap; +import java.util.concurrent.atomic.AtomicInteger; import javax.jcr.AccessDeniedException; import javax.jcr.Credentials; import javax.jcr.InvalidItemStateException; @@ -51,11 +51,11 @@ import org.apache.jackrabbit.j3.mc.NodeD import org.apache.jackrabbit.j3.mc.StorageSession; import org.apache.jackrabbit.j3.mc.Val; import org.apache.jackrabbit.j3.nodetype.NodeTypeManagerImpl; -import org.apache.jackrabbit.j3.observation.EventList; import org.apache.jackrabbit.j3.observation.ObservationManagerImpl; import org.apache.jackrabbit.j3.query.QueryManagerImpl; import org.apache.jackrabbit.j3.retention.RetentionManagerImpl; import org.apache.jackrabbit.j3.security.AccessControlManagerImpl; +import org.apache.jackrabbit.j3.util.Constants; import org.apache.jackrabbit.j3.util.ExceptionFactory; import org.apache.jackrabbit.j3.util.Log; import org.apache.jackrabbit.j3.util.LogObject; @@ -68,18 +68,19 @@ import org.xml.sax.SAXException; */ public class SessionImpl implements Session, LogObject { - private static final int MAX_RETRY = 3; + private static final AtomicInteger SESSION_ID = new AtomicInteger(0); + private final RepositoryImpl rep; + private final int id; private final StorageSession storageSession; private final WeakHashMap> weakMap = new WeakHashMap>(); - private final HashMap modified = new HashMap(); + private final ChangeSet changes; private final NamespaceRegistryImpl namespaceRegistry; private final WorkspaceImpl workspace; private final SimpleCredentials credentials; private final String userId; private final Log log; private boolean isAdmin; - private EventList eventList; private LockManagerImpl lockManager; private ObservationManagerImpl observationManager; private NodeTypeManagerImpl nodeTypeManager; @@ -92,13 +93,15 @@ public class SessionImpl implements Sess public SessionImpl(RepositoryImpl rep, SimpleCredentials credentials, StorageSession storageSession, String workspaceName, Log log) { this.rep = rep; + this.id = SESSION_ID.getAndIncrement(); this.log = log; - this.eventList = new EventList(this); this.credentials = credentials; this.userId = credentials.getUserID(); this.storageSession = storageSession; this.workspace = new WorkspaceImpl(this, workspaceName, log); this.namespaceRegistry = NamespaceRegistryImpl.createLocalInstance(log); + int maxMemory = storageSession.supportsTemp() ? Constants.MEM_CACHE_PER_SESSION : Integer.MAX_VALUE; + this.changes = new ChangeSet(this, storageSession, maxMemory); } public synchronized void logout() { @@ -107,8 +110,8 @@ public class SessionImpl implements Sess rep.close(this); } - NodeImpl getNode(NodeImpl parent, Val nodeId) throws RepositoryException { - NodeState state = modified.get(nodeId); + public NodeImpl getNode(NodeImpl parent, Val nodeId) throws RepositoryException { + NodeState state = changes.get(nodeId); if (state == null) { WeakReference ref = weakMap.get(nodeId); state = ref == null ? null : ref.get(); @@ -148,9 +151,8 @@ public class SessionImpl implements Sess return n; } - synchronized NodeImpl createNode(NodeImpl parent, Val parentId) { - Val nodeId = storageSession.newNodeId(parentId); - NodeData newData = new NodeData(nodeId, parentId, 0); + public synchronized NodeImpl createNode(NodeImpl parent, Val parentId, Val newNodeId) { + NodeData newData = new NodeData(newNodeId, parentId, 0); NodeState state = new NodeState(this, newData, 1); modify(state); cacheNodeState(state); @@ -164,14 +166,14 @@ public class SessionImpl implements Sess } synchronized void modify(NodeState state) { - modified.put(state.getId(), state); + changes.put(state.getId(), state); } public synchronized void save() throws AccessDeniedException, ItemExistsException, ReferentialIntegrityException, ConstraintViolationException, InvalidItemStateException, VersionException, LockException, NoSuchNodeTypeException, RepositoryException { log.code(this, "save"); - for (int i = 0; i < MAX_RETRY; i++) { + for (int i = 0; i < Constants.MAX_STORE_RETRY; i++) { try { trySave(); return; @@ -184,24 +186,15 @@ public class SessionImpl implements Sess } private void trySave() { - NodeData[] changed = new NodeData[modified.size()]; - Iterator it = modified.values().iterator(); - for (int i = 0; i < modified.size(); i++) { + changes.storeAll(); + for (Iterator it = changes.valueIterator(); it.hasNext();) { NodeState s = it.next(); - changed[i] = s.getNodeData(); - } - storageSession.save(changed); - for (NodeData n : changed) { + NodeData n = s.getNodeData(); rep.cacheNodeData(n); + s.reset(n); } - it = modified.values().iterator(); - for (int i = 0; i < modified.size(); i++) { - NodeState s = it.next(); - s.reset(s.getNodeData()); - } - modified.clear(); - eventList.persisted(); - eventList = new EventList(this); + changes.dispatchEvents(); + changes.clearAll(); } public synchronized NodeImpl getNodeByIdentifier(String id) throws ItemNotFoundException, RepositoryException { @@ -217,16 +210,11 @@ public class SessionImpl implements Sess public synchronized void refresh(boolean keepChanges) throws RepositoryException { log.code(this, "refresh", keepChanges); - Iterator it = modified.values().iterator(); - for (int i = 0; i < modified.size(); i++) { - NodeState s = it.next(); - NodeData data = getPersistedNodeData(s.getId()); - s.reset(data); - } if (keepChanges) { - eventList.apply(); + changes.clearNodes(); + changes.applyEvents(); } else { - eventList = new EventList(this); + changes.clearAll(); } } @@ -269,7 +257,7 @@ public class SessionImpl implements Sess public synchronized boolean hasPendingChanges() throws RepositoryException { log.code(this, "hasPendingChanges"); - return modified.size() > 0; + return changes.hasPendingChanges(); } public synchronized ObservationManagerImpl getObservationManager() { @@ -287,11 +275,11 @@ public class SessionImpl implements Sess return nodeTypeManager; } - public void dispatchEvents(EventList events) { + public void dispatchEvents(ChangeSet changes) { if (observationManager == null) { return; } - observationManager.dispatchEvents(events); + observationManager.dispatchEvents(changes); } public NamespaceRegistryImpl getNamespaceRegistry() { @@ -300,16 +288,13 @@ public class SessionImpl implements Sess public void setObservationUserData(String userData) { this.observationUserData = userData; + changes.setUserData(userData); } public String getObservationUserData() { return observationUserData; } - public EventList getEventList() { - return eventList; - } - public String getNamespacePrefix(String uri) throws NamespaceException, RepositoryException { log.code(this, "getNamespacePrefix", uri); return namespaceRegistry.getPrefix(uri); @@ -407,6 +392,10 @@ public class SessionImpl implements Sess return log; } + public ChangeSet getTransientChanges() { + return changes; + } + public boolean isLive() { log.code(this, "isLive"); // TODO Auto-generated method stub @@ -549,7 +538,7 @@ public class SessionImpl implements Sess } public String toString() { - return rep + " events: " + eventList + " modified nodes: " + modified.size() + " weak map: " + weakMap.size(); + return "session #" + id + " " + rep + " changes: " + changes + " weak map: " + weakMap.size(); } } Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/Bundle.java URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/Bundle.java?rev=935321&r1=935320&r2=935321&view=diff ============================================================================== --- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/Bundle.java (original) +++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/Bundle.java Sun Apr 18 09:52:27 2010 @@ -17,6 +17,7 @@ package org.apache.jackrabbit.j3.mc; import javax.jcr.PropertyType; +import org.apache.jackrabbit.j3.util.Constants; import org.apache.jackrabbit.j3.util.ExceptionFactory; /** @@ -51,7 +52,7 @@ public class Bundle { */ private int pos; - private Bundle(byte[] data) { + public Bundle(byte[] data) { this.data = data; } @@ -161,13 +162,12 @@ public class Bundle { } /** - * Get the current write position of this buffer, which is the current - * length. + * The total length of the buffer. * * @return the length */ public int length() { - return pos; + return data.length; } /** @@ -223,6 +223,10 @@ public class Bundle { data[pos++] = x; } + private byte readByte() { + return data[pos++]; + } + /** * Append a value. * @@ -305,7 +309,7 @@ public class Bundle { throw ExceptionFactory.illegalArgument("type: {0}", v.getType()); } int len = pos - start; - if (len > 8) { + if (len >= Constants.BUNDLE_MIN_COMPRESS) { int hash = data[start] ^ data[start + 1] ^ data[start + 2]; hash = hash & (last.length - 1); int test = last[hash]; @@ -320,10 +324,13 @@ public class Bundle { } } if (i == len) { - // write back pointer instead of the data - pos = start; - writeByte((byte) BACK_POINTER); - writeVarInt(start - test); + // write back pointer instead of the data, + // but only if that's smaller + if (len > 3 || getVarIntLen(start - test) < 2) { + pos = start; + writeByte((byte) BACK_POINTER); + writeVarInt(start - test); + } } } } @@ -602,4 +609,21 @@ public class Bundle { data = d; } + public void writeBoolean(boolean value) { + writeByte((byte) (value ? 1 : 0)); + } + + public boolean readBoolean() { + return readByte() == 1; + } + + /** + * Get the current write/read position of this buffer. + * + * @return the position + */ + public int getPos() { + return pos; + } + } Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/NodeData.java URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/NodeData.java?rev=935321&r1=935320&r2=935321&view=diff ============================================================================== --- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/NodeData.java (original) +++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/NodeData.java Sun Apr 18 09:52:27 2010 @@ -30,6 +30,7 @@ public class NodeData implements CacheEl private static final int BIT_PROPERTIES = 4; private static final int BIT_PRIMARY_TYPE = 8; private static final int BIT_LOCKED = 16; + private static final int BIT_EMBEDDED_CHILD_NODES = 32; private final Val id; private final Val primaryParentId; @@ -85,7 +86,7 @@ public class NodeData implements CacheEl public void addChild(Val childName, Val childId) { if (getChildId(childName) != null) { - throw ExceptionFactory.mcException("Duplicate node"); + throw ExceptionFactory.mcException("Duplicate node {0}", childName); } childNameIdPairs = updatePair(childNameIdPairs, childName, childId); } @@ -333,6 +334,9 @@ public class NodeData implements CacheEl int count = bundle.readVarInt(); data.propertyValuePairs = readArray(bundle, count * 2); } + if ((flags & BIT_EMBEDDED_CHILD_NODES) != 0) { + throw ExceptionFactory.unsupportedOperation(); + } return data; } Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/StorageSession.java URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/StorageSession.java?rev=935321&r1=935320&r2=935321&view=diff ============================================================================== --- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/StorageSession.java (original) +++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/StorageSession.java Sun Apr 18 09:52:27 2010 @@ -21,18 +21,32 @@ package org.apache.jackrabbit.j3.mc; */ public interface StorageSession { - void close(); - Val getRootNodeId(); NodeData getNode(Val nodeId); Val newNodeId(Val parentId); - void save(NodeData[] changed); + void store(long date, NodeData[] nodes, Bundle[] events); + + Bundle[] getEvents(long date, int size); Val convertIdentifierToNodeId(String id); String convertNodeIdToIdentifier(Val nodeId); + void close(); + + boolean supportsEventJournal(); + + boolean supportsTemp(); + + void storeTemp(int block, NodeData[] nodes, Bundle[] events); + + NodeData[] getTempNodes(int block); + + Bundle[] getTempEvents(int block); + + void clearTemp(boolean nodes, boolean events); + } Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/jdbc/JdbcStorage.java URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/jdbc/JdbcStorage.java?rev=935321&r1=935320&r2=935321&view=diff ============================================================================== --- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/jdbc/JdbcStorage.java (original) +++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/jdbc/JdbcStorage.java Sun Apr 18 09:52:27 2010 @@ -36,6 +36,7 @@ public class JdbcStorage implements Stor private boolean initDone; private static final Val rootNodeId = Val.get(0); private AtomicLong nextNodeId; + private AtomicLong nextSessionId = new AtomicLong(1); public JdbcStorage(String url) { this.url = url; @@ -44,7 +45,7 @@ public class JdbcStorage implements Stor public StorageSession openSession(String user, char[] password) { try { Connection conn = JdbcUtils.getConnection(null, url, user, new String(password)); - JdbcStorageSession session = new JdbcStorageSession(this, conn); + JdbcStorageSession session = new JdbcStorageSession(this, conn, nextSessionId.getAndIncrement()); init(conn, session); return session; } catch (SQLException e) { @@ -59,12 +60,18 @@ public class JdbcStorage implements Stor try { Statement stat = conn.createStatement(); stat.execute("create table if not exists bundles(id bigint primary key, version bigint, data binary)"); + stat.execute("create table if not exists bundles_temp(id bigint, sessionId bigint, block int, version int, data binary, primary key(id, sessionId))"); + stat.execute("create table if not exists events(id identity, persistedDate bigint, data binary)"); + stat.execute("create table if not exists events_temp(id identity, sessionId bigint, block int, data binary)"); + stat.execute("create index if not exists events_persisted on events(persistedDate, id)"); + stat.execute("create index if not exists bundles_temp_block on bundles_temp(sessionId, block, id)"); + stat.execute("create index if not exists events_temp_block on events_temp(sessionId, block)"); ResultSet rs = stat.executeQuery("select max(id) from bundles"); rs.next(); nextNodeId = new AtomicLong(rs.getLong(1) + 1); if (rs.wasNull()) { NodeData root = new NodeData(rootNodeId, null, 0); - session.save(new NodeData[] { root }); + session.store(0, new NodeData[] { root }, null); } } catch (SQLException e) { throw ExceptionFactory.mcException(e); Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/jdbc/JdbcStorageSession.java URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/jdbc/JdbcStorageSession.java?rev=935321&r1=935320&r2=935321&view=diff ============================================================================== --- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/jdbc/JdbcStorageSession.java (original) +++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/jdbc/JdbcStorageSession.java Sun Apr 18 09:52:27 2010 @@ -20,6 +20,7 @@ import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.ArrayList; import java.util.HashMap; import org.apache.jackrabbit.j3.mc.Bundle; import org.apache.jackrabbit.j3.mc.NodeData; @@ -36,10 +37,15 @@ public class JdbcStorageSession implemen private final Connection conn; private final HashMap prepared = new HashMap(); private final Bundle bundle = Bundle.create(512); + private final long sessionId; + private int tempNodeBlocks; + private int tempEventBlocks; + private long nextEventId; - JdbcStorageSession(JdbcStorage storage, Connection conn) { + JdbcStorageSession(JdbcStorage storage, Connection conn, long sessionId) { this.storage = storage; this.conn = conn; + this.sessionId = sessionId; } private PreparedStatement prepare(String sql) throws SQLException { @@ -51,23 +57,28 @@ public class JdbcStorageSession implemen return p; } - public void close() { - try { - conn.close(); - } catch (SQLException e) { - throw ExceptionFactory.mcException(e); - } - } - public Val getRootNodeId() { return storage.getRootNodeId(); } public NodeData getNode(Val nodeId) { try { - PreparedStatement p = prepare("select data from bundles where id = ?"); - p.setLong(1, nodeId.getLong()); - ResultSet rs = p.executeQuery(); + ResultSet rs; + if (tempNodeBlocks > 0) { + PreparedStatement p = prepare("select data from bundles_temp where id = ? and sessionId = ?"); + p.setLong(1, nodeId.getLong()); + p.setLong(2, sessionId); + rs = p.executeQuery(); + if (!rs.next()) { + p = prepare("select data from bundles where id = ?"); + p.setLong(1, nodeId.getLong()); + rs = p.executeQuery(); + } + } else { + PreparedStatement p = prepare("select data from bundles where id = ?"); + p.setLong(1, nodeId.getLong()); + rs = p.executeQuery(); + } if (!rs.next()) { rs.close(); return null; @@ -86,34 +97,111 @@ public class JdbcStorageSession implemen return storage.newNodeId(); } - public void save(NodeData[] changed) { + public void store(long date, NodeData[] nodes, Bundle[] events) { try { - PreparedStatement insert = prepare("insert into bundles(id, version, data) values(?, ?, ?)"); - PreparedStatement update = prepare("update bundles set version = ?, data = ? where id = ?"); - for (NodeData n : changed) { - try { - if (n.getVersion() == 0) { - n.incrementVersion(); - insert.setLong(1, n.getId().getLong()); - insert.setLong(2, n.getVersion()); - bundle.reset(); - n.writeTo(bundle); - insert.setBytes(3, bundle.getBytes()); - insert.executeUpdate(); + if (tempNodeBlocks > 0 || tempEventBlocks > 0) { + int max = Math.max(tempNodeBlocks, tempEventBlocks); + tempNodeBlocks = 0; + for (int i = 0; i <= max; i++) { + NodeData[] tempNodes = getTempNodes(i); + Bundle[] tempEvents; + if (events == null) { + tempEvents = null; } else { - n.incrementVersion(); - update.setLong(3, n.getId().getLong()); - update.setLong(1, n.getVersion()); - bundle.reset(); - n.writeTo(bundle); - update.setBytes(2, bundle.getBytes()); - int updateCount = update.executeUpdate(); - if (updateCount != 1) { - throw ExceptionFactory.mcException("Update failed, update count is {0}", updateCount); - } + tempEvents = getTempEvents(i); } - } catch (SQLException e) { - throw ExceptionFactory.mcException(e); + store(date, tempNodes, tempEvents); + } + } + PreparedStatement insert = prepare("insert into bundles(id, version, data) values(?, ?, ?)"); + PreparedStatement update = prepare("update bundles set version = ?, data = ? where id = ?"); + for (NodeData n : nodes) { + n.incrementVersion(); + bundle.reset(); + n.writeTo(bundle); + update.setLong(3, n.getId().getLong()); + update.setLong(1, n.getVersion()); + update.setBytes(2, bundle.getBytes()); + int updateCount = update.executeUpdate(); + if (updateCount == 0) { + insert.setLong(1, n.getId().getLong()); + insert.setLong(2, n.getVersion()); + insert.setBytes(3, bundle.getBytes()); + insert.executeUpdate(); + } + } + if (events != null) { + PreparedStatement eventsInsert = prepare("insert into events(persistedDate, data) values(?, ?)"); + for (Bundle e : events) { + eventsInsert.setLong(1, date); + eventsInsert.setBytes(2, e.getBytes()); + eventsInsert.execute(); + } + } + } catch (SQLException e) { + throw ExceptionFactory.mcException(e); + } + } + + public Bundle[] getEvents(long date, int size) { + try { + if (date != -1) { + PreparedStatement get = prepare("select min(id) from events where persistedDate >= ?"); + get.setLong(1, date); + ResultSet rs = get.executeQuery(); + rs.next(); + nextEventId = rs.getLong(1); + } + PreparedStatement get = prepare("select id, data from events where id >= ? limit ?"); + get.setLong(1, nextEventId); + get.setInt(2, size); + ResultSet rs = get.executeQuery(); + ArrayList bundles = new ArrayList(); + while (rs.next()) { + nextEventId = rs.getLong(1) + 1; + byte[] data = rs.getBytes(2); + Bundle b = new Bundle(data); + bundles.add(b); + } + if (bundles.size() == 0) { + return null; + } + return bundles.toArray(new Bundle[bundles.size()]); + } catch (SQLException e) { + throw ExceptionFactory.mcException(e); + } + } + + public void storeTemp(int block, NodeData[] nodes, Bundle[] events) { + tempNodeBlocks = Math.max(tempNodeBlocks, block + 1); + try { + PreparedStatement insert = prepare("insert into bundles_temp(id, sessionId, block, version, data) values(?, ?, ?, ?, ?)"); + PreparedStatement update = prepare("update bundles_temp set block = ?, version = ?, data = ? where id = ? and sessionId = ?"); + for (NodeData n : nodes) { + bundle.reset(); + n.writeTo(bundle); + update.setLong(4, n.getId().getLong()); + update.setLong(5, sessionId); + update.setLong(1, block); + update.setLong(2, n.getVersion()); + update.setBytes(3, bundle.getBytes()); + int updateCount = update.executeUpdate(); + if (updateCount == 0) { + insert.setLong(1, n.getId().getLong()); + insert.setLong(2, sessionId); + insert.setLong(3, block); + insert.setLong(4, n.getVersion()); + insert.setBytes(5, bundle.getBytes()); + insert.executeUpdate(); + } + } + if (events != null) { + PreparedStatement eventsInsert = prepare("insert into events_temp(sessionId, block, data) values(?, ?, ?)"); + for (Bundle e : events) { + eventsInsert.setLong(1, sessionId); + eventsInsert.setLong(2, block); + eventsInsert.setBytes(3, e.getBytes()); + eventsInsert.execute(); } } } catch (SQLException e) { @@ -129,5 +217,77 @@ public class JdbcStorageSession implemen return nodeId.getString(); } + public void close() { + try { + clearTemp(true, true); + conn.close(); + } catch (SQLException e) { + throw ExceptionFactory.mcException(e); + } + } + + public void clearTemp(boolean nodes, boolean events) { + try { + PreparedStatement prep; + if (nodes) { + prep = prepare("delete from bundles_temp where sessionId = ?"); + prep.setLong(1, sessionId); + prep.execute(); + tempNodeBlocks = 0; + } + if (events) { + prep = prepare("delete from events_temp where sessionId = ?"); + prep.setLong(1, sessionId); + prep.execute(); + tempEventBlocks = 0; + } + } catch (SQLException e) { + throw ExceptionFactory.mcException(e); + } + } + + public boolean supportsEventJournal() { + return true; + } + + public boolean supportsTemp() { + return true; + } + + public NodeData[] getTempNodes(int block) { + ArrayList list = new ArrayList(); + try { + PreparedStatement get = prepare("select data from bundles_temp where sessionId = ? and block = ? order by id"); + get.setLong(1, sessionId); + get.setInt(2, block); + ResultSet rs = get.executeQuery(); + while (rs.next()) { + byte[] data = rs.getBytes(1); + Bundle bundle = Bundle.create(data); + list.add(NodeData.readFrom(bundle)); + } + return list.toArray(new NodeData[list.size()]); + } catch (SQLException e) { + throw ExceptionFactory.mcException(e); + } + } + + public Bundle[] getTempEvents(int block) { + ArrayList list = new ArrayList(); + try { + PreparedStatement get = prepare("select data from events_temp where sessionId = ? and block = ? order by id"); + get.setLong(1, sessionId); + get.setInt(2, block); + ResultSet rs = get.executeQuery(); + while (rs.next()) { + byte[] data = rs.getBytes(1); + Bundle bundle = Bundle.create(data); + list.add(bundle); + } + return list.toArray(new Bundle[list.size()]); + } catch (SQLException e) { + throw ExceptionFactory.mcException(e); + } + } } Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/mem/MemStorageSession.java URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/mem/MemStorageSession.java?rev=935321&r1=935320&r2=935321&view=diff ============================================================================== --- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/mem/MemStorageSession.java (original) +++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/mem/MemStorageSession.java Sun Apr 18 09:52:27 2010 @@ -17,9 +17,11 @@ package org.apache.jackrabbit.j3.mc.mem; import java.util.HashMap; +import org.apache.jackrabbit.j3.mc.Bundle; import org.apache.jackrabbit.j3.mc.NodeData; import org.apache.jackrabbit.j3.mc.StorageSession; import org.apache.jackrabbit.j3.mc.Val; +import org.apache.jackrabbit.j3.util.ExceptionFactory; /** * A session for the memory storage. @@ -49,9 +51,9 @@ public class MemStorageSession implement return storage.newNodeId(); } - public void save(NodeData[] changed) { + public void store(long date, NodeData[] nodes, Bundle[] events) { synchronized (storage) { - for (NodeData n : changed) { + for (NodeData n : nodes) { content.put(n.getId(), n); n.incrementVersion(); } @@ -66,4 +68,32 @@ public class MemStorageSession implement return nodeId.getString(); } + public boolean supportsTemp() { + return false; + } + + public boolean supportsEventJournal() { + return false; + } + + public Bundle[] getEvents(long date, int size) { + throw ExceptionFactory.unsupportedOperation(); + } + + public void storeTemp(int block, NodeData[] nodes, Bundle[] events) { + throw ExceptionFactory.unsupportedOperation(); + } + + public NodeData[] getTempNodes(int block) { + throw ExceptionFactory.unsupportedOperation(); + } + + public Bundle[] getTempEvents(int block) { + throw ExceptionFactory.unsupportedOperation(); + } + + public void clearTemp(boolean nodes, boolean events) { + throw ExceptionFactory.unsupportedOperation(); + } + } Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/nodetype/NodeTypeImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/nodetype/NodeTypeImpl.java?rev=935321&r1=935320&r2=935321&view=diff ============================================================================== --- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/nodetype/NodeTypeImpl.java (original) +++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/nodetype/NodeTypeImpl.java Sun Apr 18 09:52:27 2010 @@ -32,6 +32,7 @@ import org.apache.jackrabbit.j3.mc.Val; */ public class NodeTypeImpl extends NodeTypeDefinitionImpl implements NodeType { + public static final NodeTypeImpl[] EMPTY_ARRAY = new NodeTypeImpl[0]; private final NodeTypeImpl[] declaredSupertypes; NodeTypeImpl(NodeTypeManagerImpl manager, NodeTypeDefinitionImpl ntd) { @@ -235,6 +236,18 @@ public class NodeTypeImpl extends NodeTy return isNodeType(manager.parseName(nodeTypeName)); } + public boolean isNodeType(NodeType nt) { + if (this == nt) { + return true; + } + for (NodeTypeImpl s : declaredSupertypes) { + if (s.isNodeType(nt)) { + return true; + } + } + return false; + } + private boolean isNodeType(Val n) { if (n.equals(name)) { return true; Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/nodetype/NodeTypeIteratorImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/nodetype/NodeTypeIteratorImpl.java?rev=935321&r1=935320&r2=935321&view=diff ============================================================================== --- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/nodetype/NodeTypeIteratorImpl.java (original) +++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/nodetype/NodeTypeIteratorImpl.java Sun Apr 18 09:52:27 2010 @@ -33,7 +33,7 @@ class NodeTypeIteratorImpl extends Range public NodeType nextNodeType() { log.code(this, "nextNodeType"); - return goNext(); + return getNext(); } } \ No newline at end of file Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddLock.java URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddLock.java?rev=935321&r1=935320&r2=935321&view=diff ============================================================================== --- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddLock.java (original) +++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddLock.java Sun Apr 18 09:52:27 2010 @@ -18,8 +18,11 @@ package org.apache.jackrabbit.j3.observa import javax.jcr.RepositoryException; import javax.jcr.observation.Event; -import org.apache.jackrabbit.j3.SessionImpl; +import org.apache.jackrabbit.j3.NodeImpl; +import org.apache.jackrabbit.j3.ChangeSet; import org.apache.jackrabbit.j3.lock.LockImpl; +import org.apache.jackrabbit.j3.mc.Bundle; +import org.apache.jackrabbit.j3.mc.Val; /** @@ -28,17 +31,42 @@ import org.apache.jackrabbit.j3.lock.Loc public class EventAddLock extends EventImpl { private final LockImpl lock; - public EventAddLock(SessionImpl session, LockImpl lock) { - super(session); + public EventAddLock(ChangeSet changes, LockImpl lock) { + super(changes); this.lock = lock; } + public int getType() { + return Event.PROPERTY_ADDED; + } + + @Override public void apply() throws RepositoryException { lock.getNode().doAddLock(lock); } - public int getType() { - return Event.PROPERTY_ADDED; + @Override + public void writeTo(Bundle bundle) { + bundle.writeVarInt(TOKEN_ADD_LOCK); + bundle.writeVal(lock.getNode().getNodeState().getId()); + bundle.writeVal(lock.getInternalLockToken()); + bundle.writeBoolean(lock.isDeep()); + bundle.writeBoolean(lock.isSessionScoped()); + } + + public static EventAddLock readFrom(ChangeSet changes, Bundle bundle) throws RepositoryException { + Val id = bundle.readVal(); + NodeImpl node = changes.getSession().getNode(null, id); + Val lockToken = bundle.readVal(); + boolean isDeep = bundle.readBoolean(); + boolean isSessionScoped = bundle.readBoolean(); + LockImpl lock = new LockImpl(node, lockToken, isDeep, isSessionScoped); + return new EventAddLock(changes, lock); + } + + @Override + public NodeImpl getParentNode() { + return lock.getNode(); } } Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddMixin.java URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddMixin.java?rev=935321&r1=935320&r2=935321&view=diff ============================================================================== --- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddMixin.java (original) +++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddMixin.java Sun Apr 18 09:52:27 2010 @@ -16,10 +16,12 @@ */ package org.apache.jackrabbit.j3.observation; +import javax.jcr.RepositoryException; import javax.jcr.lock.LockException; import javax.jcr.observation.Event; import org.apache.jackrabbit.j3.NodeImpl; -import org.apache.jackrabbit.j3.SessionImpl; +import org.apache.jackrabbit.j3.ChangeSet; +import org.apache.jackrabbit.j3.mc.Bundle; import org.apache.jackrabbit.j3.mc.Val; /** @@ -29,18 +31,38 @@ public class EventAddMixin extends Event private final NodeImpl node; private final Val mixin; - public EventAddMixin(SessionImpl session, NodeImpl node, Val mixin) { - super(session); + public EventAddMixin(ChangeSet changes, NodeImpl node, Val mixin) { + super(changes); this.node = node; this.mixin = mixin; } + public int getType() { + return Event.PROPERTY_CHANGED; + } + + @Override public void apply() throws LockException { node.doAddMixin(mixin); } - public int getType() { - return Event.PROPERTY_CHANGED; + @Override + public void writeTo(Bundle bundle) { + bundle.writeVarInt(TOKEN_ADD_MIXIN); + bundle.writeVal(node.getNodeState().getId()); + bundle.writeVal(mixin); + } + + public static EventAddMixin readFrom(ChangeSet changes, Bundle bundle) throws RepositoryException { + Val id = bundle.readVal(); + NodeImpl node = changes.getSession().getNode(null, id); + Val mixin = bundle.readVal(); + return new EventAddMixin(changes, node, mixin); + } + + @Override + public NodeImpl getParentNode() { + return node; } } Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddNode.java URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddNode.java?rev=935321&r1=935320&r2=935321&view=diff ============================================================================== --- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddNode.java (original) +++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddNode.java Sun Apr 18 09:52:27 2010 @@ -20,31 +20,44 @@ import javax.jcr.RepositoryException; import javax.jcr.lock.LockException; import javax.jcr.observation.Event; import org.apache.jackrabbit.j3.NodeImpl; -import org.apache.jackrabbit.j3.SessionImpl; +import org.apache.jackrabbit.j3.ChangeSet; +import org.apache.jackrabbit.j3.mc.Bundle; import org.apache.jackrabbit.j3.mc.Val; /** * Add a node. */ public class EventAddNode extends EventImpl { - private final NodeImpl newNode; + private final NodeImpl parent; + private final Val parentId; private final Val childName; + private final Val newNodeId; + private NodeImpl newNode; private String path; - public EventAddNode(SessionImpl session, Val childName, NodeImpl newNode) { - super(session); + public EventAddNode(ChangeSet changes, NodeImpl parent, Val childName, Val newNodeId) { + super(changes); + this.parent = parent; + this.parentId = parent.getNodeState().getId(); this.childName = childName; - this.newNode = newNode; + this.newNodeId = newNodeId; } - public void apply() throws LockException { - newNode.getParentNode().doAddNode(childName, newNode); + public NodeImpl getNode() { + return newNode; } public int getType() { return Event.NODE_ADDED; } + @Override + public void apply() throws LockException { + newNode = getSession().createNode(parent, parentId, newNodeId); + newNode.getParentNode().doAddNode(childName, newNode); + } + + @Override public String getPath() throws RepositoryException { if (path == null) { path = newNode.getPath(); @@ -52,4 +65,28 @@ public class EventAddNode extends EventI return path; } + @Override + public void writeTo(Bundle bundle) { + bundle.writeVarInt(TOKEN_ADD_NODE); + bundle.writeVal(parentId); + bundle.writeVal(childName); + bundle.writeVal(newNodeId); + } + + public static EventAddNode readFrom(ChangeSet changes, Bundle bundle) throws RepositoryException { + Val parentId = bundle.readVal(); + NodeImpl parent = changes.getSession().getNode(null, parentId); + Val childName = bundle.readVal(); + Val newNodeId = bundle.readVal(); + EventAddNode e = new EventAddNode(changes, parent, childName, newNodeId); + e.newNode = e.getSession().getNode(parent, newNodeId); + return e; + } + + @Override + public NodeImpl getParentNode() { + // TODO return the parent, or the node? + return parent; + } + } \ No newline at end of file Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddProperty.java URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddProperty.java?rev=935321&r1=935320&r2=935321&view=diff ============================================================================== --- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddProperty.java (original) +++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventAddProperty.java Sun Apr 18 09:52:27 2010 @@ -20,7 +20,8 @@ import javax.jcr.RepositoryException; import javax.jcr.lock.LockException; import javax.jcr.observation.Event; import org.apache.jackrabbit.j3.NodeImpl; -import org.apache.jackrabbit.j3.SessionImpl; +import org.apache.jackrabbit.j3.ChangeSet; +import org.apache.jackrabbit.j3.mc.Bundle; import org.apache.jackrabbit.j3.mc.Val; /** @@ -32,26 +33,48 @@ public class EventAddProperty extends Ev private final Val value; private String path; - public EventAddProperty(SessionImpl session, NodeImpl node, Val propertyName, Val value) { - super(session); + public EventAddProperty(ChangeSet changes, NodeImpl node, Val propertyName, Val value) { + super(changes); this.node = node; this.propertyName = propertyName; this.value = value; } - public void apply() throws LockException { - node.doSetProperty(propertyName, value); - } - public int getType() { return Event.PROPERTY_ADDED; } public String getPath() throws RepositoryException { if (path == null) { - path = node.getPath() + "/" + eventList.getSession().nameToString(propertyName); + path = node.getPath() + "/" + getSession().nameToString(propertyName); } return path; } + @Override + public void apply() throws LockException { + node.doSetProperty(propertyName, value); + } + + @Override + public void writeTo(Bundle bundle) { + bundle.writeVarInt(TOKEN_ADD_PROPERTY); + bundle.writeVal(node.getNodeState().getId()); + bundle.writeVal(propertyName); + bundle.writeVal(value); + } + + public static EventAddProperty readFrom(ChangeSet changes, Bundle bundle) throws RepositoryException { + Val id = bundle.readVal(); + NodeImpl node = changes.getSession().getNode(null, id); + Val propertyName = bundle.readVal(); + Val value = bundle.readVal(); + return new EventAddProperty(changes, node, propertyName, value); + } + + @Override + public NodeImpl getParentNode() { + return node; + } + } \ No newline at end of file Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventConsumer.java URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventConsumer.java?rev=935321&r1=935320&r2=935321&view=diff ============================================================================== --- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventConsumer.java (original) +++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventConsumer.java Sun Apr 18 09:52:27 2010 @@ -16,13 +16,13 @@ */ package org.apache.jackrabbit.j3.observation; -import java.util.HashSet; import javax.jcr.RepositoryException; import javax.jcr.observation.Event; import javax.jcr.observation.EventIterator; import javax.jcr.observation.EventListener; import org.apache.jackrabbit.j3.RangeIteratorImpl; import org.apache.jackrabbit.j3.SessionImpl; +import org.apache.jackrabbit.j3.ChangeSet; import org.apache.jackrabbit.j3.util.Log; /** @@ -30,67 +30,25 @@ import org.apache.jackrabbit.j3.util.Log */ public class EventConsumer { - private final SessionImpl session; private final EventListener listener; - private final int eventTypes; - private final String absPath; - private final boolean isDeep; - private final HashSet identifierSet; - private final HashSet nodeTypeNameSet; - private final boolean noLocal; + private final SessionImpl session; + private final EventFilter filter; - EventConsumer(SessionImpl session, EventListener listener, int eventTypes, String absPath, boolean isDeep, String[] identifiers, String[] nodeTypeName, boolean noLocal) { + EventConsumer(SessionImpl session, EventListener listener, EventFilter filter) { this.session = session; this.listener = listener; - this.eventTypes = eventTypes; - this.absPath = absPath; - this.isDeep = isDeep; - if (identifiers == null) { - identifierSet = null; - } else { - identifierSet = new HashSet(); - for (String id : identifiers) { - identifierSet.add(id); - } - } - if (nodeTypeName == null) { - nodeTypeNameSet = null; - } else { - nodeTypeNameSet = new HashSet(); - for (String name : nodeTypeName) { - nodeTypeNameSet.add(name); - } - } - this.noLocal = noLocal; + this.filter = filter; } public EventListener getListener() { return listener; } - boolean matchesType(int type) { - return (type & eventTypes) != 0; - } - - boolean matchesIdentifier(String identifier) { - if (identifier == null || identifierSet == null) { - return true; - } - return identifierSet.contains(identifier); - } - - boolean matchesNodeTypeName(String nodeTypeName) { - if (nodeTypeName == null || nodeTypeNameSet == null) { - return true; - } - return nodeTypeNameSet.contains(nodeTypeName); - } - - void dispatch(EventList events) { - if (noLocal && events.getSession() == session) { + void dispatch(ChangeSet changes) { + if (filter.getNoLocal() && changes.getSession() == session) { return; } - listener.onEvent(new FilteredEventIterator(events, session.getLog())); + listener.onEvent(new FilteredEventIterator(changes, session.getLog())); } /** @@ -98,22 +56,16 @@ public class EventConsumer { */ class FilteredEventIterator extends RangeIteratorImpl implements EventIterator { - FilteredEventIterator(EventList events, Log log) { - super(events.getChangeList().iterator(), -1, log); + FilteredEventIterator(ChangeSet changes, Log log) { + super(changes.getEvents(), -1, log); } public boolean skip(EventImpl x) throws RepositoryException { - if (!matchesType(x.getType())) { - return true; - } - if (!matchesIdentifier(x.getIdentifier())) { - return true; - } - return false; + return !filter.matches(x); } public Event nextEvent() { - EventImpl e = goNext(); + EventImpl e = getNext(); log.codeAssign(e, this, "nextEvent"); return e; } Added: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventFilter.java URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventFilter.java?rev=935321&view=auto ============================================================================== --- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventFilter.java (added) +++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventFilter.java Sun Apr 18 09:52:27 2010 @@ -0,0 +1,109 @@ +/* + * 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.j3.observation; + +import java.util.HashSet; +import javax.jcr.RepositoryException; +import javax.jcr.nodetype.NoSuchNodeTypeException; +import javax.jcr.nodetype.NodeType; +import org.apache.jackrabbit.j3.SessionImpl; +import org.apache.jackrabbit.j3.util.ExceptionFactory; + +/** + * A filter for event iterators. + */ +public class EventFilter { + private final SessionImpl session; + private final int eventTypes; + private final String absPath; + private final boolean isDeep; + private final HashSet identifierSet; + private final HashSet nodeTypeSet; + private final boolean noLocal; + + EventFilter(SessionImpl session, int eventTypes, String absPath, boolean isDeep, String[] identifiers, String[] nodeTypeName, boolean noLocal) throws NoSuchNodeTypeException, RepositoryException { + this.session = session; + this.eventTypes = eventTypes; + this.absPath = absPath; + this.isDeep = isDeep; + if (identifiers == null) { + identifierSet = null; + } else { + identifierSet = new HashSet(); + for (String id : identifiers) { + identifierSet.add(id); + } + } + if (nodeTypeName == null) { + nodeTypeSet = null; + } else { + nodeTypeSet = new HashSet(); + for (String name : nodeTypeName) { + NodeType nt = session.getNodeTypeManager().getNodeType(name); + nodeTypeSet.add(nt); + } + } + this.noLocal = noLocal; + } + + public boolean matches(EventImpl event) { + if ((event.getType() & eventTypes) == 0) { + return false; + } + if (identifierSet != null) { + String id = event.getIdentifier(); + if (id != null && !identifierSet.contains(id)) { + return false; + } + } + if (absPath != null) { + // TODO need to match path according to this sessions namespace mapping + String path; + try { + path = event.getPath(); + if (path != null) { + if (isDeep) { + if (!path.startsWith(absPath)) { + return false; + } + } else { + if (!path.equals(absPath)) { + return false; + } + } + } + } catch (RepositoryException e) { + throw ExceptionFactory.runtime(e); + } + } + if (nodeTypeSet != null) { + try { + if (!event.matchesNodeTypeSet(nodeTypeSet)) { + return false; + } + } catch (RepositoryException e) { + throw ExceptionFactory.runtime(e); + } + } + return true; + } + + public boolean getNoLocal() { + return noLocal; + } + +}