You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by th...@apache.org on 2010/04/23 15:43:37 UTC
svn commit: r937293 [2/3] - in /jackrabbit/sandbox/jackrabbit-j3: ./
src/main/java/org/apache/jackrabbit/j3/
src/main/java/org/apache/jackrabbit/j3/api/
src/main/java/org/apache/jackrabbit/j3/api/management/
src/main/java/org/apache/jackrabbit/j3/api/o...
Added: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/data/GarbageCollector.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/data/GarbageCollector.java?rev=937293&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/data/GarbageCollector.java (added)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/data/GarbageCollector.java Fri Apr 23 13:43:36 2010
@@ -0,0 +1,355 @@
+/*
+ * 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.data;
+
+import org.apache.jackrabbit.j3.RepositoryImpl;
+import org.apache.jackrabbit.j3.SessionImpl;
+import org.apache.jackrabbit.j3.SessionListener;
+import org.apache.jackrabbit.j3.api.management.DataStoreGarbageCollector;
+import org.apache.jackrabbit.j3.api.management.MarkEventListener;
+import org.apache.jackrabbit.j3.api.observation.SynchronousEventListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.jcr.InvalidItemStateException;
+import javax.jcr.Item;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.Property;
+import javax.jcr.PropertyIterator;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.Workspace;
+import javax.jcr.observation.Event;
+import javax.jcr.observation.EventIterator;
+import javax.jcr.observation.ObservationManager;
+
+/**
+ * Garbage collector for DataStore. This implementation is iterates through all
+ * nodes and reads the binary properties. To detect nodes that are moved while
+ * the scan runs, event listeners are started. Like the well known garbage
+ * collection in Java, the items that are still in use are marked. Currently
+ * this achieved by updating the modified date of the entries. Newly added
+ * entries are detected because the modified date is changed when they are
+ * added.
+ * <p>
+ * Example code to run the data store garbage collection:
+ * <pre>
+ * JackrabbitRepositoryFactory jf = (JackrabbitRepositoryFactory) factory;
+ * RepositoryManager m = factory.getRepositoryManager((JackrabbitRepository) rep);
+ * GarbageCollector gc = m.createDataStoreGarbageCollector();
+ * try {
+ * gc.mark();
+ * gc.sweep();
+ * } finally {
+ * gc.close();
+ * }
+ * </pre>
+ */
+public class GarbageCollector implements DataStoreGarbageCollector {
+
+ /** logger instance */
+ private static final Logger LOG = LoggerFactory.getLogger(GarbageCollector.class);
+
+ private MarkEventListener callback;
+
+ private long sleepBetweenNodes;
+
+ private int testDelay;
+
+ private final DataStore store;
+
+ private long startScanTimestamp;
+
+ private final ArrayList<Listener> listeners = new ArrayList<Listener>();
+
+ private final Session[] sessionList;
+ private SessionListener sessionListener;
+
+ private final AtomicBoolean closed = new AtomicBoolean();
+
+ /**
+ * Create a new garbage collector.
+ * This method is usually not called by the application, it is called
+ * by SessionImpl.createDataStoreGarbageCollector().
+ *
+ * @param rep the repository
+ * @param session the session that created this object (optional)
+ * @param list the persistence managers
+ * @param sessionList the sessions to access the workspaces
+ */
+ public GarbageCollector(RepositoryImpl rep, SessionImpl session, Session[] sessionList) {
+ store = rep.getDataStore();
+ this.sessionList = sessionList;
+
+ if (session != null) {
+ // Auto-close if the main session logs out
+ this.sessionListener = new SessionListener() {
+ public void loggedOut(Session session) {
+ }
+ public void loggingOut(Session session) {
+ close();
+ }
+ };
+ session.addListener(sessionListener);
+ }
+ }
+
+ public void setSleepBetweenNodes(long millis) {
+ this.sleepBetweenNodes = millis;
+ }
+
+ public long getSleepBetweenNodes() {
+ return sleepBetweenNodes;
+ }
+
+ /**
+ * When testing the garbage collection, a delay is used instead of simulating concurrent access.
+ *
+ * @param testDelay the delay in milliseconds
+ */
+ public void setTestDelay(int testDelay) {
+ this.testDelay = testDelay;
+ }
+
+ public void setMarkEventListener(MarkEventListener callback) {
+ this.callback = callback;
+ }
+
+ public void mark() throws RepositoryException {
+ if (store == null) {
+ throw new RepositoryException("No DataStore configured.");
+ }
+ long now = System.currentTimeMillis();
+ if (startScanTimestamp == 0) {
+ startScanTimestamp = now;
+ store.updateModifiedDateOnAccess(startScanTimestamp);
+ }
+
+ for (Session s : sessionList) {
+ scanNodes(s);
+ }
+ }
+
+ private void scanNodes(Session session) throws RepositoryException {
+
+ // add a listener to get 'new' nodes
+ // actually, new nodes are not the problem, but moved nodes
+ listeners.add(new Listener(session));
+
+ // adding a link to a BLOB updates the modified date
+ // reading usually doesn't, but when scanning, it does
+ recurse(session.getRootNode(), sleepBetweenNodes);
+ }
+
+ /**
+ * Stop the observation listener if any are installed.
+ */
+ public void stopScan() throws RepositoryException {
+ if (listeners.size() > 0) {
+ for (Listener listener : listeners) {
+ try {
+ listener.stop();
+ } catch (Exception e) {
+ throw new RepositoryException(e);
+ }
+ }
+ listeners.clear();
+ }
+ }
+
+ public int sweep() throws RepositoryException {
+ if (startScanTimestamp == 0) {
+ throw new RepositoryException("scan must be called first");
+ }
+ stopScan();
+ return store.deleteAllOlderThan(startScanTimestamp);
+ }
+
+ /**
+ * Get the data store if one is used.
+ *
+ * @return the data store, or null
+ */
+ public DataStore getDataStore() {
+ return store;
+ }
+
+ private void recurse(final Node n, long sleep) throws RepositoryException {
+ if (sleep > 0) {
+ try {
+ Thread.sleep(sleep);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ }
+ if (callback != null) {
+ callback.beforeScanning(n);
+ }
+ try {
+ for (PropertyIterator it = n.getProperties(); it.hasNext();) {
+ Property p = it.nextProperty();
+ try {
+ if (p.getType() == PropertyType.BINARY) {
+ if (n.hasProperty("jcr:uuid")) {
+ rememberNode(n.getProperty("jcr:uuid").getString());
+ } else {
+ rememberNode(n.getPath());
+ }
+ if (p.isMultiple()) {
+ p.getLengths();
+ } else {
+ p.getLength();
+ }
+ }
+ } catch (InvalidItemStateException e) {
+ LOG.debug("Property removed concurrently - ignoring", e);
+ }
+ }
+ } catch (InvalidItemStateException e) {
+ LOG.debug("Node removed concurrently - ignoring", e);
+ }
+ try {
+ for (NodeIterator it = n.getNodes(); it.hasNext();) {
+ recurse(it.nextNode(), sleep);
+ }
+ } catch (InvalidItemStateException e) {
+ LOG.debug("Node removed concurrently - ignoring", e);
+ }
+ }
+
+ private void rememberNode(String path) {
+ // Do nothing at the moment
+ // TODO It may be possible to delete some items early
+ /*
+ * To delete files early in the garbage collection scan, we could do
+ * this:
+ *
+ * A) If garbage collection was run before, see if there a file with the
+ * list of UUIDs ('uuids.txt').
+ *
+ * B) If yes, and if the checksum is ok, read all those nodes first (if
+ * not so many). This updates the modified date of all old files that
+ * are still in use. Afterwards, delete all files with an older modified
+ * date than the last scan! Newer files, and files that are read have a
+ * newer modification date.
+ *
+ * C) Delete the 'uuids.txt' file (in any case).
+ *
+ * D) Iterate (recurse) through all nodes and properties like now. If a
+ * node has a binary property, store the UUID of the node in the file
+ * ('uuids.txt'). Also store the time when the scan started.
+ *
+ * E) Checksum and close the file.
+ *
+ * F) Like now, delete files with an older modification date than this
+ * scan.
+ *
+ * We can't use node path for this, UUIDs are required as nodes could be
+ * moved around.
+ *
+ * This mechanism requires that all data stores update the last modified
+ * date when calling addRecord and that record already exists.
+ *
+ */
+ }
+
+ public void close() {
+ if (!closed.getAndSet(true)) {
+ try {
+ stopScan();
+ } catch (RepositoryException e) {
+ LOG.warn("An error occured when stopping the event listener", e);
+ }
+ for (Session s : sessionList) {
+ s.logout();
+ }
+ }
+ }
+
+ /**
+ * Auto-close in case the application didn't call it explicitly.
+ */
+ protected void finalize() throws Throwable {
+ close();
+ super.finalize();
+ }
+
+ /**
+ * Event listener to detect moved nodes.
+ * A SynchronousEventListener is used to make sure this method is called before the main iteration ends.
+ */
+ class Listener implements SynchronousEventListener {
+
+ private final Session session;
+
+ private final ObservationManager manager;
+
+ private Exception lastException;
+
+ Listener(Session session)
+ throws UnsupportedRepositoryOperationException,
+ RepositoryException {
+ this.session = session;
+ Workspace ws = session.getWorkspace();
+ manager = ws.getObservationManager();
+ manager.addEventListener(this, Event.NODE_ADDED, "/", true, null,
+ null, false);
+ }
+
+ void stop() throws Exception {
+ if (lastException != null) {
+ throw lastException;
+ }
+ manager.removeEventListener(this);
+ }
+
+ public void onEvent(EventIterator events) {
+ if (testDelay > 0) {
+ try {
+ Thread.sleep(testDelay);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ }
+ while (events.hasNext()) {
+ Event event = events.nextEvent();
+ try {
+ String path = event.getPath();
+ try {
+ Item item = session.getItem(path);
+ if (item.isNode()) {
+ Node n = (Node) item;
+ recurse(n, testDelay);
+ }
+ } catch (PathNotFoundException e) {
+ // ignore
+ }
+ } catch (Exception e) {
+ lastException = e;
+ }
+ }
+ }
+ }
+
+}
Added: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/data/LazyFileInputStream.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/data/LazyFileInputStream.java?rev=937293&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/data/LazyFileInputStream.java (added)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/data/LazyFileInputStream.java Fri Apr 23 13:43:36 2010
@@ -0,0 +1,167 @@
+/*
+ * 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.data;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+import org.apache.commons.io.input.AutoCloseInputStream;
+
+/**
+ * This input stream delays opening the file until the first byte is read, and
+ * closes and discards the underlying stream as soon as the end of input has
+ * been reached or when the stream is explicitly closed.
+ */
+public class LazyFileInputStream extends AutoCloseInputStream {
+
+ /**
+ * The file descriptor to use.
+ */
+ protected final FileDescriptor fd;
+
+ /**
+ * The file to read from.
+ */
+ protected final File file;
+
+ /**
+ * True if the input stream was opened. It is also set to true if the stream
+ * was closed without reading (to avoid opening the file after the stream
+ * was closed).
+ */
+ protected boolean opened;
+
+ /**
+ * Creates a new <code>LazyFileInputStream</code> for the given file. If the
+ * file is unreadable, a FileNotFoundException is thrown.
+ * The file is not opened until the first byte is read from the stream.
+ *
+ * @param file the file
+ * @throws java.io.FileNotFoundException
+ */
+ public LazyFileInputStream(File file)
+ throws FileNotFoundException {
+ super(null);
+ if (!file.canRead()) {
+ throw new FileNotFoundException(file.getPath());
+ }
+ this.file = file;
+ this.fd = null;
+ }
+
+ /**
+ * Creates a new <code>LazyFileInputStream</code> for the given file
+ * descriptor.
+ * The file is not opened until the first byte is read from the stream.
+ *
+ * @param fdObj
+ */
+ public LazyFileInputStream(FileDescriptor fd) {
+ super(null);
+ this.file = null;
+ this.fd = fd;
+ }
+
+ /**
+ * Creates a new <code>LazyFileInputStream</code> for the given file. If the
+ * file is unreadable, a FileNotFoundException is thrown.
+ *
+ * @param name
+ * @throws java.io.FileNotFoundException
+ */
+ public LazyFileInputStream(String name) throws FileNotFoundException {
+ this(new File(name));
+ }
+
+ /**
+ * Open the stream if required.
+ *
+ * @throws java.io.IOException
+ */
+ protected void open() throws IOException {
+ if (!opened) {
+ opened = true;
+ if (fd != null) {
+ in = new FileInputStream(fd);
+ } else {
+ in = new FileInputStream(file);
+ }
+ }
+ }
+
+ public int read() throws IOException {
+ open();
+ return super.read();
+ }
+
+ public int available() throws IOException {
+ open();
+ return super.available();
+ }
+
+ public void close() throws IOException {
+ // make sure the file is not opened afterwards
+ opened = true;
+
+ // only close the file if it was in fact opened
+ if (in != null) {
+ super.close();
+ }
+ }
+
+ public synchronized void reset() throws IOException {
+ open();
+ super.reset();
+ }
+
+ public boolean markSupported() {
+ try {
+ open();
+ } catch (IOException e) {
+ throw new IllegalStateException(e.toString());
+ }
+ return super.markSupported();
+ }
+
+ public synchronized void mark(int readlimit) {
+ try {
+ open();
+ } catch (IOException e) {
+ throw new IllegalStateException(e.toString());
+ }
+ super.mark(readlimit);
+ }
+
+ public long skip(long n) throws IOException {
+ open();
+ return super.skip(n);
+ }
+
+ public int read(byte[] b) throws IOException {
+ open();
+ return super.read(b, 0, b.length);
+ }
+
+ public int read(byte[] b, int off, int len) throws IOException {
+ open();
+ return super.read(b, off, len);
+ }
+
+}
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=937293&r1=937292&r2=937293&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 Fri Apr 23 13:43:36 2010
@@ -21,11 +21,17 @@ package org.apache.jackrabbit.j3.mc;
*/
public interface StorageSession {
+ int MAIN_WORKSPACE_ID = 0;
+
Val getRootNodeId();
NodeData getNode(Val nodeId);
- Val newNodeId(Val parentId);
+ Val newNodeId(Val parentNodeId, int workspaceId, Val relPath);
+
+ int getWorkspaceId(Val nodeId);
+
+ Val convertNodeId(Val nodeId, int newWorkspaceId);
void store(long date, NodeData[] nodes, Bundle[] events);
@@ -41,6 +47,8 @@ public interface StorageSession {
boolean supportsTemp();
+ boolean supportsNodeIdsWithoutPath();
+
void storeTemp(int block, NodeData[] nodes, Bundle[] events);
NodeData[] getTempNodes(int block);
Added: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/Utils.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/Utils.java?rev=937293&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/Utils.java (added)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/Utils.java Fri Apr 23 13:43:36 2010
@@ -0,0 +1,75 @@
+/*
+ * 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.mc;
+
+import org.apache.jackrabbit.j3.util.ExceptionFactory;
+
+/**
+ * A utility class.
+ */
+public class Utils {
+
+ 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/mc/Val.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/Val.java?rev=937293&r1=937292&r2=937293&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/Val.java (original)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/Val.java Fri Apr 23 13:43:36 2010
@@ -432,4 +432,53 @@ public class Val implements Comparable<V
return Val.get(newArray);
}
+ public 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);
+ }
+ }
+
+ public 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);
+ }
+ }
+
+ public 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/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=937293&r1=937292&r2=937293&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 Fri Apr 23 13:43:36 2010
@@ -17,10 +17,10 @@
package org.apache.jackrabbit.j3.mc.jdbc;
import java.sql.Connection;
+import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
-import java.util.concurrent.atomic.AtomicLong;
import org.apache.jackrabbit.j3.mc.NodeData;
import org.apache.jackrabbit.j3.mc.Storage;
import org.apache.jackrabbit.j3.mc.StorageSession;
@@ -32,58 +32,149 @@ import org.apache.jackrabbit.j3.util.Exc
*/
public class JdbcStorage implements Storage {
+ private static final String SETTING_VERSION_READ = "versionRead";
+ private static final String SETTING_VERSION_WRITE = "versionWrite";
+ private static final String SETTING_NEXT_BASE_NODE_ID = "nextBaseNodeId";
+
+ private static final String VERSION_READ = "1";
+ private static final String VERSION_WRITE = "1";
+ private static final int NODE_ID_INCREMENT = 32;
+
private final String url;
private boolean initDone;
private static final Val rootNodeId = Val.get(0);
- private AtomicLong nextNodeId;
- private AtomicLong nextSessionId = new AtomicLong(1);
+ private long nextBaseNodeId;
+ private long lastBaseNodeId;
+ private long nextSessionId = 1;
+
+ private Connection connControl;
+ private Connection connLock;
+ private PreparedStatement prepUpdateSetting;
public JdbcStorage(String url) {
this.url = url;
}
- public StorageSession openSession(String user, char[] password) {
+ public synchronized StorageSession openSession(String user, char[] password) {
try {
Connection conn = JdbcUtils.getConnection(null, url, user, new String(password));
- JdbcStorageSession session = new JdbcStorageSession(this, conn, nextSessionId.getAndIncrement());
- init(conn, session);
+ JdbcStorageSession session = new JdbcStorageSession(this, conn, nextSessionId++);
+ if (connControl == null) {
+ connLock = JdbcUtils.getConnection(null, url, user, new String(password));
+ connControl = JdbcUtils.getConnection(null, url, user, new String(password));
+ init(session);
+ }
return session;
} catch (SQLException e) {
throw ExceptionFactory.mcException(e);
}
}
- private synchronized void init(Connection conn, JdbcStorageSession session) {
+ private String getSetting(String name, String defaultValue) throws SQLException {
+ PreparedStatement prep = connControl.prepareStatement("select value from settings where name = ?");
+ prep.setString(1, name);
+ ResultSet rs = prep.executeQuery();
+ if (rs.next()) {
+ return rs.getString(1);
+ }
+ setSetting(name, defaultValue);
+ return defaultValue;
+ }
+
+ private void setSetting(String name, String value) throws SQLException {
+ if (prepUpdateSetting == null) {
+ prepUpdateSetting = connControl.prepareStatement("update settings set value = ? where name = ?");
+ }
+ PreparedStatement prep = prepUpdateSetting;
+ prep.setString(1, value);
+ prep.setString(2, name);
+ int count = prep.executeUpdate();
+ if (count == 0) {
+ prep = connControl.prepareStatement("insert into settings(name, value) values(?, ?)");
+ prep.setString(1, name);
+ prep.setString(2, value);
+ prep.execute();
+ }
+ }
+
+ private synchronized void init(JdbcStorageSession session) {
if (initDone) {
return;
}
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))");
+ Statement stat = connControl.createStatement();
+ stat.execute("create table if not exists settings(name varchar(255), value varchar(255))");
+ String read = getSetting(SETTING_VERSION_READ, VERSION_READ);
+ if (VERSION_READ.compareTo(read) > 0) {
+ throw ExceptionFactory.mcException("Invalid read version: {0}", read);
+ }
+ String write = getSetting(SETTING_VERSION_WRITE, VERSION_WRITE);
+ if (!VERSION_WRITE.equals(write)) {
+ // could switch to read-only now
+ throw ExceptionFactory.mcException("Invalid write version: {0}", write);
+ }
+ stat.execute("create table if not exists lock(id int primary key)");
+ lock();
+ stat.execute("create table if not exists nodes(id bigint primary key, version bigint, data binary)");
+ stat.execute("create table if not exists nodes_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 nodes_temp_block on nodes_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()) {
+ nextBaseNodeId = Long.parseLong(getSetting(SETTING_NEXT_BASE_NODE_ID, "0"));
+ if (nextBaseNodeId == 0) {
NodeData root = new NodeData(rootNodeId, null, 0);
session.store(0, new NodeData[] { root }, null);
+ nextBaseNodeId++;
}
+
} catch (SQLException e) {
throw ExceptionFactory.mcException(e);
}
initDone = true;
}
+ private void lock() {
+ try {
+ connLock.setAutoCommit(false);
+ Statement lock = connLock.createStatement();
+ lock.execute("insert into lock values(1)");
+ } catch (SQLException e) {
+ throw ExceptionFactory.mcException("Repository is already in use", e);
+ }
+ }
+
+ private void unlock() {
+ try {
+ connLock.rollback();
+ connLock.close();
+ } catch (SQLException e) {
+ throw ExceptionFactory.mcException(e);
+ }
+ }
+
public void close() {
+ try {
+ setSetting(SETTING_NEXT_BASE_NODE_ID, Long.toString(nextBaseNodeId));
+ connControl.close();
+ } catch (SQLException e) {
+ throw ExceptionFactory.mcException(e);
+ }
+ unlock();
}
- Val newNodeId() {
- return Val.get(nextNodeId.getAndIncrement());
+ synchronized long newBaseNodeId() {
+ long id = nextBaseNodeId++;
+ if (id > lastBaseNodeId) {
+ lastBaseNodeId += NODE_ID_INCREMENT;
+ try {
+ setSetting(SETTING_NEXT_BASE_NODE_ID, Long.toString(lastBaseNodeId));
+ } catch (SQLException e) {
+ throw ExceptionFactory.mcException(e);
+ }
+ }
+ return id;
}
Val getRootNodeId() {
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=937293&r1=937292&r2=937293&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 Fri Apr 23 13:43:36 2010
@@ -65,17 +65,17 @@ public class JdbcStorageSession implemen
try {
ResultSet rs;
if (tempNodeBlocks > 0) {
- PreparedStatement p = prepare("select data from bundles_temp where id = ? and sessionId = ?");
+ PreparedStatement p = prepare("select data from nodes_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 = prepare("select data from nodes where id = ?");
p.setLong(1, nodeId.getLong());
rs = p.executeQuery();
}
} else {
- PreparedStatement p = prepare("select data from bundles where id = ?");
+ PreparedStatement p = prepare("select data from nodes where id = ?");
p.setLong(1, nodeId.getLong());
rs = p.executeQuery();
}
@@ -93,8 +93,18 @@ public class JdbcStorageSession implemen
}
}
- public Val newNodeId(Val parentId) {
- return storage.newNodeId();
+ public Val newNodeId(Val parentNodeId, int workspaceId, Val relPath) {
+ long base = storage.newBaseNodeId();
+ return Val.get(Val.getNodeId(workspaceId, base));
+ }
+
+ public int getWorkspaceId(Val nodeId) {
+ return Val.getWorkspaceId(nodeId.getLong());
+ }
+
+ public Val convertNodeId(Val nodeId, int newWorkspaceId) {
+ long baseNodeId = Val.getBaseNodeId(nodeId.getLong());
+ return Val.get(Val.getNodeId(newWorkspaceId, baseNodeId));
}
public void store(long date, NodeData[] nodes, Bundle[] events) {
@@ -113,8 +123,8 @@ public class JdbcStorageSession implemen
store(date, tempNodes, tempEvents);
}
}
- PreparedStatement insert = prepare("insert into bundles(id, version, data) values(?, ?, ?)");
- PreparedStatement update = prepare("update bundles set version = ?, data = ? where id = ?");
+ PreparedStatement insert = prepare("insert into nodes(id, version, data) values(?, ?, ?)");
+ PreparedStatement update = prepare("update nodes set version = ?, data = ? where id = ?");
for (NodeData n : nodes) {
n.incrementVersion();
bundle.reset();
@@ -175,8 +185,8 @@ public class JdbcStorageSession implemen
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 = ?");
+ PreparedStatement insert = prepare("insert into nodes_temp(id, sessionId, block, version, data) values(?, ?, ?, ?, ?)");
+ PreparedStatement update = prepare("update nodes_temp set block = ?, version = ?, data = ? where id = ? and sessionId = ?");
for (NodeData n : nodes) {
bundle.reset();
n.writeTo(bundle);
@@ -230,7 +240,7 @@ public class JdbcStorageSession implemen
try {
PreparedStatement prep;
if (nodes) {
- prep = prepare("delete from bundles_temp where sessionId = ?");
+ prep = prepare("delete from nodes_temp where sessionId = ?");
prep.setLong(1, sessionId);
prep.execute();
tempNodeBlocks = 0;
@@ -254,10 +264,14 @@ public class JdbcStorageSession implemen
return true;
}
+ public boolean supportsNodeIdsWithoutPath() {
+ return true;
+ }
+
public NodeData[] getTempNodes(int block) {
ArrayList<NodeData> list = new ArrayList<NodeData>();
try {
- PreparedStatement get = prepare("select data from bundles_temp where sessionId = ? and block = ? order by id");
+ PreparedStatement get = prepare("select data from nodes_temp where sessionId = ? and block = ? order by id");
get.setLong(1, sessionId);
get.setInt(2, block);
ResultSet rs = get.executeQuery();
Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/mem/MemStorage.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/mem/MemStorage.java?rev=937293&r1=937292&r2=937293&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/mem/MemStorage.java (original)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/mem/MemStorage.java Fri Apr 23 13:43:36 2010
@@ -30,7 +30,7 @@ public class MemStorage implements Stora
private static final Val rootNodeId = Val.get(0);
private final HashMap<Val, NodeData> content = new HashMap<Val, NodeData>();
- private AtomicLong nextNodeId = new AtomicLong(1);
+ private AtomicLong nextBaseNodeId = new AtomicLong(1);
public MemStorage() {
NodeData root = new NodeData(rootNodeId, null, 0);
@@ -44,8 +44,8 @@ public class MemStorage implements Stora
return new MemStorageSession(this, content);
}
- public Val newNodeId() {
- return Val.get(nextNodeId.getAndIncrement());
+ long newBaseNodeId() {
+ return nextBaseNodeId.getAndIncrement();
}
Val getRootNodeId() {
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=937293&r1=937292&r2=937293&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 Fri Apr 23 13:43:36 2010
@@ -47,8 +47,18 @@ public class MemStorageSession implement
return storage.getRootNodeId();
}
- public Val newNodeId(Val parentId) {
- return storage.newNodeId();
+ public Val newNodeId(Val parentNodeId, int workspaceId, Val relPath) {
+ long base = storage.newBaseNodeId();
+ return Val.get(Val.getNodeId(workspaceId, base));
+ }
+
+ public int getWorkspaceId(Val nodeId) {
+ return Val.getWorkspaceId(nodeId.getLong());
+ }
+
+ public Val convertNodeId(Val nodeId, int newWorkspaceId) {
+ long baseNodeId = Val.getBaseNodeId(nodeId.getLong());
+ return Val.get(Val.getNodeId(newWorkspaceId, baseNodeId));
}
public void store(long date, NodeData[] nodes, Bundle[] events) {
@@ -76,6 +86,10 @@ public class MemStorageSession implement
return false;
}
+ public boolean supportsNodeIdsWithoutPath() {
+ return true;
+ }
+
public Bundle[] getEvents(long date, int size) {
throw ExceptionFactory.unsupportedOperation();
}
Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/util/Constants.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/util/Constants.java?rev=937293&r1=937292&r2=937293&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/util/Constants.java (original)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/util/Constants.java Fri Apr 23 13:43:36 2010
@@ -44,4 +44,7 @@ public class Constants {
public static final int BUNDLE_MIN_COMPRESS = 3;
public static final int JOURNAL_LOAD_SIZE = 16;
+ public static final String LOG_UNCLOSED_SESSIONS = "logUnclosedSessions";
+ public static final boolean LOG_UNCLOSED_SESSIONS_DEFAULT = true;
+
}
Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/util/LobStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/util/LobStore.java?rev=937293&r1=937292&r2=937293&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/util/LobStore.java (original)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/util/LobStore.java Fri Apr 23 13:43:36 2010
@@ -23,6 +23,7 @@ import java.io.SequenceInputStream;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import org.apache.jackrabbit.j3.RepositoryImpl;
+import org.apache.jackrabbit.j3.data.DataStore;
import org.apache.jackrabbit.j3.mc.Val;
/**
@@ -41,6 +42,10 @@ public class LobStore {
return null;
}
+ public DataStore getDataStore() {
+ return null;
+ }
+
public Val createValue(InputStream in) throws RepositoryException {
try {
int min = getMinRecordLength();
Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/util/Log.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/util/Log.java?rev=937293&r1=937292&r2=937293&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/util/Log.java (original)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/util/Log.java Fri Apr 23 13:43:36 2010
@@ -34,9 +34,6 @@ public class Log {
private static int nextId;
public boolean debug;
- public Log() {
- }
-
private void log(String message) {
if (message != null && debug) {
System.out.println(message);
@@ -221,6 +218,11 @@ public class Log {
return n;
}
+ public void warn(String message, Exception e) {
+ System.err.println(message);
+ e.printStackTrace();
+ }
+
/*
Find & replace:
@@ -249,6 +251,9 @@ public $1 $2\(\)$3 \{$4log.code\(this, "
;// TODO(\R)
;$1// TODO$1
+(log.code\(this, ")(.*".*\R.* // TODO)
+$1TODO $2
+
*/
}
Modified: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/util/StringUtils.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/util/StringUtils.java?rev=937293&r1=937292&r2=937293&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/util/StringUtils.java (original)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/util/StringUtils.java Fri Apr 23 13:43:36 2010
@@ -38,4 +38,18 @@ public class StringUtils {
return buff.toString();
}
+ /**
+ * Check if two strings are equal. Here, null is equal to null.
+ *
+ * @param a the first value
+ * @param b the second value
+ * @return true if both are null or both are equal
+ */
+ public static boolean equals(String a, String b) {
+ if (a == null) {
+ return b == null;
+ }
+ return a.equals(b);
+ }
+
}
Modified: jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestAll.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestAll.java?rev=937293&r1=937292&r2=937293&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestAll.java (original)
+++ jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestAll.java Fri Apr 23 13:43:36 2010
@@ -35,12 +35,15 @@ public class TestAll {
TestSuite suite = new TestSuite("org.apache.jackrabbit.j3");
int todo;
- // repository lock mechanism (required for sessions, journal?)
+ // XA API
+ // integrated lob storage
+ // virtual repository
+ // session attribute to request cache size (only smaller except if in admin group)
// Repository.OPTION_JOURNALED_OBSERVATION_SUPPORTED
// external events
- // auto-close sessions, optionally log open stack trace
// ability to auto-delete old event journal entries
- // ability to disable the even journal
+ // ability to disable the even journal (for each session?)
+ // try supporting path as the node id
// events: save space for n=addNode+n.setProperty+... or n.setProperty+n.setProperty+...
@@ -57,6 +60,7 @@ public class TestAll {
suite.addTestSuite(TestLock.class);
suite.addTestSuite(TestSimple.class);
suite.addTestSuite(TestObservation.class);
+ suite.addTestSuite(TestSessionGC.class);
suite.addTestSuite(TestNextConfiguration.class);
}
Modified: jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestBase.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestBase.java?rev=937293&r1=937292&r2=937293&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestBase.java (original)
+++ jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestBase.java Fri Apr 23 13:43:36 2010
@@ -37,33 +37,39 @@ public class TestBase extends TestCase {
public static final String[] URL = new String[] {
// "jdbc:h2:target/repos/test&log=debug",
+ // "jdbc:h2:target/repos/test;TRACE_LEVEL_SYSTEM_OUT=2",
"jdbc:h2:target/repos/test",
"mem:",
"jdbc:h2:mem:test",
};
- private Repository repository;
+ protected RepositoryFactory repositoryFactory;
+ protected Repository repository;
protected Session session;
- public void setUp() throws Exception {
+ protected void setUp() throws Exception {
FileUtils.deleteDirectory(new File("target/repos"));
String factoryClass = "org.apache.jackrabbit.j3.RepositoryFactoryImpl";
String url = URL[configurationId];
- RepositoryFactory factory = (RepositoryFactory) Class.forName(factoryClass).newInstance();
+ repositoryFactory = (RepositoryFactory) Class.forName(factoryClass).newInstance();
Map<String, String> parameters = new HashMap<String, String>();
parameters.put("url", url);
- repository = factory.getRepository(parameters);
+ repository = repositoryFactory.getRepository(parameters);
session = openSession();
}
- public void tearDown() throws Exception {
+ protected void tearDown() throws Exception {
session.logout();
}
protected Session openSession() throws LoginException, RepositoryException {
- SimpleCredentials credentials = new SimpleCredentials("sa", "sa".toCharArray());
+ SimpleCredentials credentials = getCredentials();
return repository.login(credentials);
}
+ protected SimpleCredentials getCredentials() {
+ return new SimpleCredentials("sa", "sa".toCharArray());
+ }
+
}
Modified: jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestBundle.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestBundle.java?rev=937293&r1=937292&r2=937293&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestBundle.java (original)
+++ jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestBundle.java Fri Apr 23 13:43:36 2010
@@ -28,22 +28,22 @@ public class TestBundle extends TestCase
public void testNodeId() {
try {
- RepositoryImpl.getNodeId(268435456, 0);
+ Val.getNodeId(268435456, 0);
fail();
} catch (IllegalArgumentException e) {
// expected
}
try {
- RepositoryImpl.getNodeId(-1, 0);
+ Val.getNodeId(-1, 0);
fail();
} catch (IllegalArgumentException e) {
// expected
}
for (int workspaceId = 0; workspaceId < 268435455;) {
for (long baseNodeId = 0; baseNodeId < Integer.MAX_VALUE;) {
- long nodeId = RepositoryImpl.getNodeId(workspaceId, baseNodeId);
- long w = RepositoryImpl.getWorkspaceId(nodeId);
- long b = RepositoryImpl.getBaseNodeId(nodeId);
+ long nodeId = Val.getNodeId(workspaceId, baseNodeId);
+ long w = Val.getWorkspaceId(nodeId);
+ long b = Val.getBaseNodeId(nodeId);
assertEquals(workspaceId, w);
assertEquals(baseNodeId, b);
if (baseNodeId < 1000) {
Modified: jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestEventJournal.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestEventJournal.java?rev=937293&r1=937292&r2=937293&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestEventJournal.java (original)
+++ jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestEventJournal.java Fri Apr 23 13:43:36 2010
@@ -43,6 +43,8 @@ public class TestEventJournal extends Te
assertEquals(Event.PROPERTY_ADDED, e.getType());
assertEquals("userData", e.getUserData());
+ session2.logout();
+
n.remove();
session.save();
}
Modified: jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestObservation.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestObservation.java?rev=937293&r1=937292&r2=937293&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestObservation.java (original)
+++ jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestObservation.java Fri Apr 23 13:43:36 2010
@@ -30,6 +30,7 @@ import javax.jcr.observation.EventListen
public class TestObservation extends TestBase {
private ArrayList<String> eventList = new ArrayList<String>();
+ private boolean ownEvent;
public void test() throws Exception {
session.getRootNode().addNode("t");
@@ -39,6 +40,14 @@ public class TestObservation extends Tes
Event.PROPERTY_ADDED | Event.PROPERTY_CHANGED |
Event.PROPERTY_REMOVED, "/", true, null, null, false);
+ // testNestedWrite
+ ownEvent = true;
+ Node test = session.getRootNode().addNode("x");
+ session.save();
+ test.remove();
+ session.save();
+ ownEvent = false;
+
Session session2 = openSession();
Node n2 = session2.getNode("/t");
session2.getWorkspace().getObservationManager().setUserData("x");
@@ -46,8 +55,8 @@ public class TestObservation extends Tes
session2.save();
session2.logout();
- assertEquals(2, eventList.size());
- assertEquals("[/t/test:1:x, /t/test/jcr:primaryType:4:x]", eventList.toString());
+ assertEquals(5, eventList.size());
+ assertEquals("[/x:1:null, /x/jcr:primaryType:4:null, null:2:null, /t/test:1:x, /t/test/jcr:primaryType:4:x]", eventList.toString());
}
/**
@@ -65,6 +74,14 @@ public class TestObservation extends Tes
s = e.toString();
}
eventList.add(s);
+ if (ownEvent) {
+ try {
+ session.getRootNode().addNode("testNestedWrite");
+ fail();
+ } catch (RepositoryException e) {
+ // expected
+ }
+ }
}
}
Added: jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestSessionGC.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestSessionGC.java?rev=937293&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestSessionGC.java (added)
+++ jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestSessionGC.java Fri Apr 23 13:43:36 2010
@@ -0,0 +1,82 @@
+/*
+ * 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.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+import org.apache.jackrabbit.j3.api.JackrabbitRepositoryFactory;
+import org.apache.jackrabbit.j3.api.management.RepositoryManager;
+import org.apache.jackrabbit.j3.util.Constants;
+
+/**
+ * Test that sessions get garbage collected.
+ */
+public class TestSessionGC extends TestBase {
+
+ public void testSessionsGetGarbageCollected() throws RepositoryException {
+ RepositoryManager manager = ((JackrabbitRepositoryFactory) repositoryFactory).getRepositoryManager(repository);
+ ArrayList<WeakReference<Session>> list = new ArrayList<WeakReference<Session>>();
+ ReferenceQueue<Session> detect = new ReferenceQueue<Session>();
+ Error error = null;
+ int charsPerSession = 100000;
+ try {
+ Runtime rt = Runtime.getRuntime();
+ for (int i = 0;;) {
+ SimpleCredentials sc = getCredentials();
+ sc.setAttribute(Constants.LOG_UNCLOSED_SESSIONS, false);
+ Session s = repository.login(sc);
+ i++;
+ if (i % 100 == 0) {
+ long mem = rt.totalMemory() - rt.freeMemory();
+ System.out.println("open: " + i + " mem (kb): " + mem / 1024);
+ }
+ // eat a lot of memory so it gets garbage collected quickly
+ // (or quickly runs out of memory)
+ Node n = s.getRootNode().addNode("n" + i);
+ // can't use the same content: the value factory would detect it
+ char[] ch = new char[charsPerSession];
+ ch[0] = (char) (i / 256);
+ ch[i] = (char) (i % 256);
+ n.setProperty("x", new String(ch));
+ list.add(new WeakReference<Session>(s, detect));
+ if (detect.poll() != null) {
+ break;
+ }
+ }
+ } catch (OutOfMemoryError e) {
+ error = e;
+ }
+ for (int i = 0; i < list.size(); i++) {
+ Reference<Session> ref = list.get(i);
+ Session s = ref.get();
+ if (s != null) {
+ s.logout();
+ }
+ }
+ manager.stop();
+ if (error != null) {
+ throw error;
+ }
+ }
+
+}