You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by dp...@apache.org on 2008/10/27 15:31:01 UTC
svn commit: r708199 - in /jackrabbit/branches/1.5/jackrabbit-core/src:
main/java/org/apache/jackrabbit/core/cluster/
test/java/org/apache/jackrabbit/core/cluster/
test/java/org/apache/jackrabbit/core/journal/
Author: dpfister
Date: Mon Oct 27 07:31:01 2008
New Revision: 708199
URL: http://svn.apache.org/viewvc?rev=708199&view=rev
Log:
JCR-1553 - ClusterNode not properly shutdown when repository has shutdown
Added:
jackrabbit/branches/1.5/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/UpdateEventFactory.java (with props)
Modified:
jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterNode.java
jackrabbit/branches/1.5/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/ClusterRecordTest.java
jackrabbit/branches/1.5/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/journal/MemoryJournal.java
Modified: jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterNode.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterNode.java?rev=708199&r1=708198&r2=708199&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterNode.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterNode.java Mon Oct 27 07:31:01 2008
@@ -35,6 +35,7 @@
import org.apache.jackrabbit.core.state.ChangeLog;
import org.apache.jackrabbit.uuid.UUID;
+import EDU.oswego.cs.dl.util.concurrent.Latch;
import EDU.oswego.cs.dl.util.concurrent.Mutex;
import javax.jcr.RepositoryException;
@@ -69,6 +70,11 @@
private static final String PRODUCER_ID = "JR";
/**
+ * Default stop delay.
+ */
+ private static final long DEFAULT_STOP_DELAY = 5000;
+
+ /**
* Status constant.
*/
private static final int NONE = 0;
@@ -104,16 +110,31 @@
private long syncDelay;
/**
+ * Stop delay, in milliseconds.
+ */
+ private long stopDelay;
+
+ /**
* Journal used.
*/
private Journal journal;
/**
+ * Synchronization thread.
+ */
+ private Thread syncThread;
+
+ /**
* Mutex used when syncing.
*/
private final Mutex syncLock = new Mutex();
/**
+ * Latch used to communicate a stop request to the synchronization thread.
+ */
+ private final Latch stopLatch = new Latch();
+
+ /**
* Status flag, one of {@link #NONE}, {@link #STARTED} or {@link #STOPPED}.
*/
private int status;
@@ -209,6 +230,26 @@
}
/**
+ * Set the stop delay, i.e. number of millseconds to wait for the
+ * synchronization thread to stop.
+ *
+ * @param stopDelay stop delay in milliseconds
+ */
+ public void setStopDelay(long stopDelay) {
+ this.stopDelay = stopDelay;
+ }
+
+ /**
+ * Return the stop delay.
+ *
+ * @return stop delay
+ * @see #setStopDelay(long)
+ */
+ public long getStopDelay() {
+ return stopDelay;
+ }
+
+ /**
* Starts this cluster node.
*
* @throws ClusterException if an error occurs
@@ -220,6 +261,7 @@
Thread t = new Thread(this, "ClusterNode-" + clusterNodeId);
t.setDaemon(true);
t.start();
+ syncThread = t;
status = STARTED;
}
@@ -230,14 +272,13 @@
*/
public void run() {
for (;;) {
- synchronized (this) {
- try {
- wait(syncDelay);
- } catch (InterruptedException e) {}
-
- if (status == STOPPED) {
- return;
+ try {
+ if (stopLatch.attempt(syncDelay)) {
+ break;
}
+ } catch (InterruptedException e) {
+ String msg = "Interrupted while waiting for stop latch.";
+ log.warn(msg);
}
try {
sync();
@@ -284,13 +325,24 @@
if (status != STOPPED) {
status = STOPPED;
+ stopLatch.release();
+
+ // Give synchronization thread some time to finish properly before
+ // closing down the journal (see JCR-1553)
+ if (syncThread != null) {
+ try {
+ syncThread.join(stopDelay);
+ } catch (InterruptedException e) {
+ String msg = "Interrupted while joining synchronization thread.";
+ log.warn(msg);
+ }
+ }
if (journal != null) {
journal.close();
}
if (instanceRevision != null) {
instanceRevision.close();
}
- notifyAll();
}
}
Modified: jackrabbit/branches/1.5/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/ClusterRecordTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/ClusterRecordTest.java?rev=708199&r1=708198&r2=708199&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/ClusterRecordTest.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/ClusterRecordTest.java Mon Oct 27 07:31:01 2008
@@ -17,16 +17,9 @@
package org.apache.jackrabbit.core.cluster;
import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
import java.util.Properties;
-import javax.jcr.Session;
-import javax.jcr.observation.Event;
-
import org.apache.jackrabbit.core.NodeId;
-import org.apache.jackrabbit.core.PropertyId;
-import org.apache.jackrabbit.core.RepositoryImpl;
import org.apache.jackrabbit.core.cluster.SimpleEventListener.LockEvent;
import org.apache.jackrabbit.core.cluster.SimpleEventListener.NamespaceEvent;
import org.apache.jackrabbit.core.cluster.SimpleEventListener.NodeTypeEvent;
@@ -37,17 +30,9 @@
import org.apache.jackrabbit.core.config.JournalConfig;
import org.apache.jackrabbit.core.journal.MemoryJournal;
import org.apache.jackrabbit.core.nodetype.NodeTypeDef;
-import org.apache.jackrabbit.core.observation.EventState;
-import org.apache.jackrabbit.core.state.ChangeLog;
-import org.apache.jackrabbit.core.state.NodeState;
-import org.apache.jackrabbit.core.state.PropertyState;
import org.apache.jackrabbit.spi.Name;
-import org.apache.jackrabbit.spi.NameFactory;
-import org.apache.jackrabbit.spi.Path;
-import org.apache.jackrabbit.spi.PathFactory;
import org.apache.jackrabbit.spi.commons.name.NameConstants;
import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl;
-import org.apache.jackrabbit.spi.commons.name.PathFactoryImpl;
import org.apache.jackrabbit.test.JUnitTest;
import org.apache.jackrabbit.uuid.UUID;
@@ -63,34 +48,14 @@
private static final String DEFAULT_WORKSPACE = "default";
/**
- * Default user.
- */
- private static final String DEFAULT_USER = "admin";
-
- /**
- * Root node id.
- */
- private static final NodeId ROOT_NODE_ID = RepositoryImpl.ROOT_NODE_ID;
-
- /**
* Default sync delay: 5 seconds.
*/
private static final long SYNC_DELAY = 5000;
/**
- * Default session, used for event state creation.
+ * Update event factory.
*/
- private final Session session = new ClusterSession(DEFAULT_USER);
-
- /**
- * Name factory.
- */
- private NameFactory nameFactory = NameFactoryImpl.getInstance();
-
- /**
- * Path factory.
- */
- private PathFactory pathFactory = PathFactoryImpl.getInstance();
+ private final UpdateEventFactory factory = UpdateEventFactory.getInstance();
/**
* Records shared among multiple memory journals.
@@ -137,26 +102,7 @@
* @throws Exception
*/
public void testUpdateOperation() throws Exception {
- NodeState n1 = createNodeState();
- NodeState n2 = createNodeState();
- NodeState n3 = createNodeState();
- PropertyState p1 = createPropertyState(n1.getNodeId(), "{}a");
- PropertyState p2 = createPropertyState(n2.getNodeId(), "{}b");
-
- ChangeLog changes = new ChangeLog();
- changes.added(n1);
- changes.added(p1);
- changes.deleted(p2);
- changes.modified(n2);
- changes.deleted(n3);
-
- List events = new ArrayList();
- events.add(createEventState(n1, Event.NODE_ADDED, "{}n1"));
- events.add(createEventState(p1, n1, Event.PROPERTY_ADDED));
- events.add(createEventState(p2, n2, Event.PROPERTY_REMOVED));
- events.add(createEventState(n3, Event.NODE_REMOVED, "{}n3"));
-
- UpdateEvent update = new UpdateEvent(changes, events);
+ UpdateEvent update = factory.createUpdateOperation();
UpdateEventChannel channel = master.createUpdateChannel(DEFAULT_WORKSPACE);
channel.updateCreated(update);
@@ -328,88 +274,4 @@
}
return clusterNode;
}
-
- /**
- * Create a node state.
- *
- * @return node state
- */
- private NodeState createNodeState() {
- Name ntName = nameFactory.create("{}testnt");
- NodeState n = new NodeState(
- new NodeId(UUID.randomUUID()), ntName,
- ROOT_NODE_ID, NodeState.STATUS_EXISTING, false);
- n.setMixinTypeNames(Collections.EMPTY_SET);
- return n;
- }
-
- /**
- * Create a property state.
- *
- * @param parentId parent node id
- * @param name property name
- */
- private PropertyState createPropertyState(NodeId parentId, String name) {
- Name propName = nameFactory.create(name);
- return new PropertyState(
- new PropertyId(parentId, propName),
- NodeState.STATUS_EXISTING, false);
- }
-
- /**
- * Create an event state for an operation on a node.
- *
- * @param n node state
- * @param type <code>Event.NODE_ADDED</code> or <code>Event.NODE_REMOVED</code>
- * @param name node name
- * @return event state
- */
- private EventState createEventState(NodeState n, int type, String name) {
- Path.Element relPath = pathFactory.createElement(nameFactory.create(name));
-
- switch (type) {
- case Event.NODE_ADDED:
- return EventState.childNodeAdded(
- n.getParentId(), pathFactory.getRootPath(),
- n.getNodeId(), relPath, n.getNodeTypeName(),
- n.getMixinTypeNames(), session);
- case Event.NODE_REMOVED:
- return EventState.childNodeRemoved(
- n.getParentId(), pathFactory.getRootPath(),
- n.getNodeId(), relPath, n.getNodeTypeName(),
- n.getMixinTypeNames(), session);
- }
- return null;
- }
-
- /**
- * Create an event state for a property operation.
- *
- * @param n node state
- * @param type <code>Event.NODE_ADDED</code> or <code>Event.NODE_REMOVED</code>
- * @param name property name
- * @return event state
- */
- private EventState createEventState(PropertyState p, NodeState parent, int type) {
- Path.Element relPath = pathFactory.createElement(p.getName());
-
- switch (type) {
- case Event.PROPERTY_ADDED:
- return EventState.propertyAdded(
- p.getParentId(), pathFactory.getRootPath(), relPath,
- parent.getNodeTypeName(), parent.getMixinTypeNames(),
- session);
- case Event.PROPERTY_CHANGED:
- return EventState.propertyChanged(
- p.getParentId(), pathFactory.getRootPath(), relPath,
- parent.getNodeTypeName(), parent.getMixinTypeNames(),
- session);
- case Event.PROPERTY_REMOVED:
- return EventState.propertyRemoved(
- p.getParentId(), pathFactory.getRootPath(), relPath,
- parent.getNodeTypeName(), parent.getMixinTypeNames(),
- session);
- }
- return null;
- }
}
Added: jackrabbit/branches/1.5/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/UpdateEventFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/UpdateEventFactory.java?rev=708199&view=auto
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/UpdateEventFactory.java (added)
+++ jackrabbit/branches/1.5/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/UpdateEventFactory.java Mon Oct 27 07:31:01 2008
@@ -0,0 +1,206 @@
+/*
+ * 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.core.cluster;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.jcr.Session;
+import javax.jcr.observation.Event;
+
+import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.PropertyId;
+import org.apache.jackrabbit.core.RepositoryImpl;
+import org.apache.jackrabbit.core.cluster.SimpleEventListener.UpdateEvent;
+import org.apache.jackrabbit.core.observation.EventState;
+import org.apache.jackrabbit.core.state.ChangeLog;
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.core.state.PropertyState;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.NameFactory;
+import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.spi.PathFactory;
+import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl;
+import org.apache.jackrabbit.spi.commons.name.PathFactoryImpl;
+import org.apache.jackrabbit.uuid.UUID;
+
+/**
+ * Simplistic factory that produces update events, consisting of node identifiers,
+ * property identifiers and event states.
+ */
+public class UpdateEventFactory {
+
+ /**
+ * Root node id.
+ */
+ private static final NodeId ROOT_NODE_ID = RepositoryImpl.ROOT_NODE_ID;
+
+ /**
+ * Default user.
+ */
+ private static final String DEFAULT_USER = "admin";
+
+ /**
+ * Instance of this class.
+ */
+ private static final UpdateEventFactory INSTANCE = new UpdateEventFactory();
+
+ /**
+ * Default session, used for event state creation.
+ */
+ private final Session session = new ClusterSession(DEFAULT_USER);
+
+ /**
+ * Name factory.
+ */
+ private NameFactory nameFactory = NameFactoryImpl.getInstance();
+
+ /**
+ * Path factory.
+ */
+ private PathFactory pathFactory = PathFactoryImpl.getInstance();
+
+ /**
+ * Create a new instance of this class. Private as there is only one
+ * instance acting as singleton.
+ */
+ private UpdateEventFactory() {
+ }
+
+ /**
+ * Return the instance of this class.
+ *
+ * @return factory
+ */
+ public static UpdateEventFactory getInstance() {
+ return INSTANCE;
+ }
+
+ /**
+ * Create an update operation.
+ *
+ * @return update operation
+ */
+ public UpdateEvent createUpdateOperation() {
+ NodeState n1 = createNodeState();
+ NodeState n2 = createNodeState();
+ NodeState n3 = createNodeState();
+ PropertyState p1 = createPropertyState(n1.getNodeId(), "{}a");
+ PropertyState p2 = createPropertyState(n2.getNodeId(), "{}b");
+
+ ChangeLog changes = new ChangeLog();
+ changes.added(n1);
+ changes.added(p1);
+ changes.deleted(p2);
+ changes.modified(n2);
+ changes.deleted(n3);
+
+ List events = new ArrayList();
+ events.add(createEventState(n1, Event.NODE_ADDED, "{}n1"));
+ events.add(createEventState(p1, n1, Event.PROPERTY_ADDED));
+ events.add(createEventState(p2, n2, Event.PROPERTY_REMOVED));
+ events.add(createEventState(n3, Event.NODE_REMOVED, "{}n3"));
+
+ return new UpdateEvent(changes, events);
+ }
+
+
+ /**
+ * Create a node state.
+ *
+ * @return node state
+ */
+ protected NodeState createNodeState() {
+ Name ntName = nameFactory.create("{}testnt");
+ NodeState n = new NodeState(
+ new NodeId(UUID.randomUUID()), ntName,
+ ROOT_NODE_ID, NodeState.STATUS_EXISTING, false);
+ n.setMixinTypeNames(Collections.EMPTY_SET);
+ return n;
+ }
+
+ /**
+ * Create a property state.
+ *
+ * @param parentId parent node id
+ * @param name property name
+ */
+ protected PropertyState createPropertyState(NodeId parentId, String name) {
+ Name propName = nameFactory.create(name);
+ return new PropertyState(
+ new PropertyId(parentId, propName),
+ NodeState.STATUS_EXISTING, false);
+ }
+
+ /**
+ * Create an event state for an operation on a node.
+ *
+ * @param n node state
+ * @param type <code>Event.NODE_ADDED</code> or <code>Event.NODE_REMOVED</code>
+ * @param name node name
+ * @return event state
+ */
+ protected EventState createEventState(NodeState n, int type, String name) {
+ Path.Element relPath = pathFactory.createElement(nameFactory.create(name));
+
+ switch (type) {
+ case Event.NODE_ADDED:
+ return EventState.childNodeAdded(
+ n.getParentId(), pathFactory.getRootPath(),
+ n.getNodeId(), relPath, n.getNodeTypeName(),
+ n.getMixinTypeNames(), session);
+ case Event.NODE_REMOVED:
+ return EventState.childNodeRemoved(
+ n.getParentId(), pathFactory.getRootPath(),
+ n.getNodeId(), relPath, n.getNodeTypeName(),
+ n.getMixinTypeNames(), session);
+ }
+ return null;
+ }
+
+ /**
+ * Create an event state for a property operation.
+ *
+ * @param n node state
+ * @param type <code>Event.NODE_ADDED</code> or <code>Event.NODE_REMOVED</code>
+ * @param name property name
+ * @return event state
+ */
+ protected EventState createEventState(PropertyState p, NodeState parent, int type) {
+ Path.Element relPath = pathFactory.createElement(p.getName());
+
+ switch (type) {
+ case Event.PROPERTY_ADDED:
+ return EventState.propertyAdded(
+ p.getParentId(), pathFactory.getRootPath(), relPath,
+ parent.getNodeTypeName(), parent.getMixinTypeNames(),
+ session);
+ case Event.PROPERTY_CHANGED:
+ return EventState.propertyChanged(
+ p.getParentId(), pathFactory.getRootPath(), relPath,
+ parent.getNodeTypeName(), parent.getMixinTypeNames(),
+ session);
+ case Event.PROPERTY_REMOVED:
+ return EventState.propertyRemoved(
+ p.getParentId(), pathFactory.getRootPath(), relPath,
+ parent.getNodeTypeName(), parent.getMixinTypeNames(),
+ session);
+ }
+ return null;
+ }
+}
Propchange: jackrabbit/branches/1.5/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/cluster/UpdateEventFactory.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: jackrabbit/branches/1.5/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/journal/MemoryJournal.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/journal/MemoryJournal.java?rev=708199&r1=708198&r2=708199&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/journal/MemoryJournal.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/journal/MemoryJournal.java Mon Oct 27 07:31:01 2008
@@ -29,6 +29,8 @@
import org.apache.jackrabbit.core.journal.JournalException;
import org.apache.jackrabbit.core.journal.RecordIterator;
import org.apache.jackrabbit.spi.commons.namespace.NamespaceResolver;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Memory-based journal, useful for testing purposes only.
@@ -36,6 +38,21 @@
public class MemoryJournal extends AbstractJournal {
/**
+ * Default read delay: none.
+ */
+ private static final long DEFAULT_READ_DELAY = 0;
+
+ /**
+ * Default write delay: none.
+ */
+ private static final long DEFAULT_WRITE_DELAY = 0;
+
+ /**
+ * Logger.
+ */
+ private static Logger log = LoggerFactory.getLogger(MemoryJournal.class);
+
+ /**
* Revision.
*/
private InstanceRevision revision = new MemoryRevision();
@@ -46,6 +63,23 @@
private ArrayList records = new ArrayList();
/**
+ * Set the read delay, i.e. the time in ms to wait before returning
+ * a record.
+ */
+ private long readDelay = DEFAULT_READ_DELAY;
+
+ /**
+ * Set the write delay, i.e. the time in ms to wait before appending
+ * a record.
+ */
+ private long writeDelay = DEFAULT_WRITE_DELAY;
+
+ /**
+ * Flag indicating whether this journal is closed.
+ */
+ private boolean closed;
+
+ /**
* {@inheritDoc}
*/
public InstanceRevision getInstanceRevision() throws JournalException {
@@ -65,7 +99,7 @@
* {@inheritDoc}
*/
protected void doLock() throws JournalException {
- // not implemented
+ checkState();
}
/**
@@ -74,6 +108,8 @@
protected void append(AppendRecord record, InputStream in, int length)
throws JournalException {
+ checkState();
+
byte[] data = new byte[length];
int off = 0;
@@ -90,6 +126,11 @@
throw new JournalException(msg, e);
}
}
+ try {
+ Thread.sleep(writeDelay);
+ } catch (InterruptedException e) {
+ throw new JournalException("Interrupted in append().");
+ }
records.add(new MemoryRecord(getId(), record.getProducerId(), data));
record.setRevision(records.size());
}
@@ -98,7 +139,11 @@
* {@inheritDoc}
*/
protected void doUnlock(boolean successful) {
- // not implemented
+ try {
+ checkState();
+ } catch (JournalException e) {
+ log.warn("Journal already closed while unlocking.");
+ }
}
/**
@@ -107,6 +152,8 @@
protected RecordIterator getRecords(long startRevision)
throws JournalException {
+ checkState();
+
startRevision = Math.max(startRevision, 0);
long stopRevision = records.size();
@@ -123,12 +170,56 @@
}
/**
+ * Return the read delay in milliseconds.
+ *
+ * @return read delay
+ */
+ public long getReadDelay() {
+ return readDelay;
+ }
+
+ /**
+ * Set the read delay in milliseconds.
+ *
+ * @param readDelay read delay
+ */
+ public void setReadDelay(long readDelay) {
+ this.readDelay = readDelay;
+ }
+
+ /**
+ * Return the write delay in milliseconds.
+ *
+ * @return write delay
+ */
+ public long getWriteDelay() {
+ return writeDelay;
+ }
+
+ /**
+ * Set the write delay in milliseconds.
+ *
+ * @param writeDelay write delay
+ */
+ public void setWriteDelay(long writeDelay) {
+ this.writeDelay = writeDelay;
+ }
+
+ /**
* {@inheritDoc}
*/
public void close() {
- // nothing to be done here
+ closed = true;
}
+ /**
+ * Check state of this journal.
+ */
+ private void checkState() throws JournalException {
+ if (closed) {
+ throw new JournalException("Journal closed.");
+ }
+ }
/**
* Memory record.
@@ -233,10 +324,18 @@
int index = (int) revision;
MemoryRecord record = (MemoryRecord) records.get(index);
+ checkState();
+
byte[] data = record.getData();
DataInputStream dataIn = new DataInputStream(
new ByteArrayInputStream(data));
+ try {
+ Thread.sleep(readDelay);
+ } catch (InterruptedException e) {
+ throw new JournalException("Interrupted in read().");
+ }
+
return new ReadRecord(record.getJournalId(), record.getProducerId(),
++revision, dataIn, data.length,
getResolver(), getNamePathResolver());