exo-jcr SVN: r4240 - in jcr/trunk/exo.jcr.component.core/src: main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache and 4 other directories.
by do-not-reply@jboss.org
Author: nfilotto
Date: 2011-04-15 15:11:33 -0400 (Fri, 15 Apr 2011)
New Revision: 4240
Added:
jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/TestWorkspaceStorageCacheInClusterMode.java
jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/infinispan/
jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/infinispan/TestISPNCacheWorkspaceStorageCacheInClusterMode.java
jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/TestJBossCacheWorkspaceStorageCacheInClusterMode.java
jcr/trunk/exo.jcr.component.core/src/test/resources/conf/standalone/cluster/test-jbosscache-data-no-mux.xml
Modified:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/infinispan/BufferedISPNCache.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/BufferedJBossCache.java
jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/TestCacheableWorkspaceDataManager.java
Log:
EXOJCR-1302: Second part of the patch that ensure the atomicity of any operations in the apply methods
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/infinispan/BufferedISPNCache.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/infinispan/BufferedISPNCache.java 2011-04-15 18:02:47 UTC (rev 4239)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/infinispan/BufferedISPNCache.java 2011-04-15 19:11:33 UTC (rev 4240)
@@ -38,6 +38,7 @@
import java.util.Set;
import java.util.concurrent.TimeUnit;
+import javax.transaction.Status;
import javax.transaction.TransactionManager;
/**
@@ -160,6 +161,11 @@
}
public abstract void apply();
+
+ public boolean isTxRequired()
+ {
+ return false;
+ }
}
/**
@@ -255,6 +261,12 @@
+ existingObject.getClass().getName());
}
}
+
+ @Override
+ public boolean isTxRequired()
+ {
+ return true;
+ }
}
/**
@@ -291,6 +303,12 @@
cache.put(key, newSet);
}
}
+
+ @Override
+ public boolean isTxRequired()
+ {
+ return true;
+ }
}
/**
@@ -892,12 +910,62 @@
public void commitTransaction()
{
CompressedISPNChangesBuffer changesContainer = getChangesBufferSafe();
+ TransactionManager tm = getTransactionManager();
try
{
List<ChangesContainer> containers = changesContainer.getSortedList();
for (ChangesContainer cacheChange : containers)
{
- cacheChange.apply();
+ boolean isTxCreated = false;
+ try
+ {
+ if (cacheChange.isTxRequired() && tm != null && tm.getStatus() == Status.STATUS_NO_TRANSACTION)
+ {
+ // No tx exists so we create a new tx
+ if (LOG.isTraceEnabled())
+ LOG.trace("No Tx is active we then create a new tx");
+ tm.begin();
+ isTxCreated = true;
+ }
+ }
+ catch (Exception e)
+ {
+ LOG.warn("Could not create a new tx", e);
+ }
+ try
+ {
+ cacheChange.apply();
+ }
+ catch (RuntimeException e)
+ {
+ if (isTxCreated)
+ {
+ try
+ {
+ if (LOG.isTraceEnabled())
+ LOG.trace("An error occurs the tx will be rollbacked");
+ tm.rollback();
+ }
+ catch (Exception e1)
+ {
+ LOG.warn("Could not rollback the tx", e1);
+ }
+ }
+ throw e;
+ }
+ if (isTxCreated)
+ {
+ try
+ {
+ if (LOG.isTraceEnabled())
+ LOG.trace("The tx will be committed");
+ tm.commit();
+ }
+ catch (Exception e)
+ {
+ LOG.warn("Could not commit the tx", e);
+ }
+ }
}
}
finally
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/BufferedJBossCache.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/BufferedJBossCache.java 2011-04-15 18:02:47 UTC (rev 4239)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/BufferedJBossCache.java 2011-04-15 19:11:33 UTC (rev 4240)
@@ -43,6 +43,7 @@
import java.util.Map;
import java.util.Set;
+import javax.transaction.Status;
import javax.transaction.TransactionManager;
/**
@@ -68,12 +69,15 @@
private final long expirationTimeOut;
+ private final TransactionManager tm;
+
protected static final Log LOG =
ExoLogger.getLogger("org.exoplatform.services.jcr.impl.dataflow.persistent.jbosscache.BufferedJBossCache");
public BufferedJBossCache(Cache<Serializable, Object> parentCache, boolean useExpiration, long expirationTimeOut)
{
super();
+ this.tm = ((CacheSPI<Serializable, Object>)parentCache).getTransactionManager();
this.parentCache = parentCache;
this.useExpiration = useExpiration;
this.expirationTimeOut = expirationTimeOut;
@@ -112,7 +116,53 @@
//log.info("After=" + changesContainer.toString());
for (ChangesContainer cacheChange : containers)
{
- cacheChange.apply();
+ boolean isTxCreated = false;
+ try
+ {
+ if (cacheChange.isTxRequired() && tm != null && tm.getStatus() == Status.STATUS_NO_TRANSACTION)
+ {
+ // No tx exists so we create a new tx
+ if (LOG.isTraceEnabled()) LOG.trace("No Tx is active we then create a new tx");
+ tm.begin();
+ isTxCreated = true;
+ }
+ }
+ catch (Exception e)
+ {
+ LOG.warn("Could not create a new tx", e);
+ }
+ try
+ {
+ cacheChange.apply();
+ }
+ catch (RuntimeException e)
+ {
+ if (isTxCreated)
+ {
+ try
+ {
+ if (LOG.isTraceEnabled()) LOG.trace("An error occurs the tx will be rollbacked");
+ tm.rollback();
+ }
+ catch (Exception e1)
+ {
+ LOG.warn("Could not rollback the tx", e1);
+ }
+ }
+ throw e;
+ }
+ if (isTxCreated)
+ {
+ try
+ {
+ if (LOG.isTraceEnabled()) LOG.trace("The tx will be committed");
+ tm.commit();
+ }
+ catch (Exception e)
+ {
+ LOG.warn("Could not commit the tx", e);
+ }
+ }
}
}
finally
@@ -818,6 +868,11 @@
}
public abstract void apply();
+
+ public boolean isTxRequired()
+ {
+ return false;
+ }
}
/**
@@ -882,6 +937,12 @@
setCacheLocalMode();
cache.put(fqn, key, value);
}
+
+ @Override
+ public boolean isTxRequired()
+ {
+ return true;
+ }
}
/**
@@ -943,7 +1004,7 @@
// object found by FQN and key;
Object existingObject = cache.get(getFqn(), key);
Set<Object> newSet = new HashSet<Object>();
- // if set found of null, perform add
+ // if set found or null, perform add
if (existingObject instanceof Set || (existingObject == null && forceModify))
{
// set found
@@ -967,6 +1028,12 @@
+ existingObject.getClass().getName());
}
}
+
+ @Override
+ public boolean isTxRequired()
+ {
+ return true;
+ }
}
/**
@@ -1009,6 +1076,12 @@
cache.put(fqn, key, newSet);
}
}
+
+ @Override
+ public boolean isTxRequired()
+ {
+ return false;
+ }
}
/**
Modified: jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/TestCacheableWorkspaceDataManager.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/TestCacheableWorkspaceDataManager.java 2011-04-15 18:02:47 UTC (rev 4239)
+++ jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/TestCacheableWorkspaceDataManager.java 2011-04-15 19:11:33 UTC (rev 4240)
@@ -534,7 +534,6 @@
{
}
- @Override
public int getLastOrderNumber(NodeData parent) throws RepositoryException
{
return -1;
@@ -592,7 +591,6 @@
return "0";
}
- @Override
public String getUniqueName()
{
return "MyWorkspaceDataContainer";
Added: jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/TestWorkspaceStorageCacheInClusterMode.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/TestWorkspaceStorageCacheInClusterMode.java (rev 0)
+++ jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/TestWorkspaceStorageCacheInClusterMode.java 2011-04-15 19:11:33 UTC (rev 4240)
@@ -0,0 +1,647 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.jcr.impl.dataflow.persistent;
+
+import org.exoplatform.services.jcr.JcrImplBaseTest;
+import org.exoplatform.services.jcr.dataflow.ItemState;
+import org.exoplatform.services.jcr.dataflow.PlainChangesLog;
+import org.exoplatform.services.jcr.dataflow.PlainChangesLogImpl;
+import org.exoplatform.services.jcr.dataflow.persistent.PersistedNodeData;
+import org.exoplatform.services.jcr.dataflow.persistent.PersistedPropertyData;
+import org.exoplatform.services.jcr.dataflow.persistent.WorkspaceStorageCache;
+import org.exoplatform.services.jcr.datamodel.InternalQName;
+import org.exoplatform.services.jcr.datamodel.ItemData;
+import org.exoplatform.services.jcr.datamodel.ItemType;
+import org.exoplatform.services.jcr.datamodel.NodeData;
+import org.exoplatform.services.jcr.datamodel.PropertyData;
+import org.exoplatform.services.jcr.datamodel.QPath;
+import org.exoplatform.services.jcr.datamodel.QPathEntry;
+import org.exoplatform.services.jcr.datamodel.ValueData;
+import org.exoplatform.services.jcr.impl.Constants;
+import org.exoplatform.services.jcr.impl.storage.SystemDataContainerHolder;
+import org.exoplatform.services.jcr.impl.storage.WorkspaceDataContainerBase;
+import org.exoplatform.services.jcr.storage.WorkspaceDataContainer;
+import org.exoplatform.services.jcr.storage.WorkspaceStorageConnection;
+
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.jcr.InvalidItemStateException;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+
+/**
+ * @author <a href="mailto:nfilotto@exoplatform.com">Nicolas Filotto</a>
+ * @version $Id$
+ *
+ */
+public abstract class TestWorkspaceStorageCacheInClusterMode<T extends WorkspaceStorageCache> extends JcrImplBaseTest
+{
+ public abstract T getCacheImpl() throws Exception;
+
+ public void testRaceConditions() throws Exception
+ {
+ T cache1 = null, cache2 = null;
+ try
+ {
+ MyWorkspaceStorageConnection con = new MyWorkspaceStorageConnection();
+ WorkspaceDataContainer wdc = new MyWorkspaceDataContainer(con);
+ CacheableWorkspaceDataManager cwdmNode1 =
+ new CacheableWorkspaceDataManager(wdc, cache1 = getCacheImpl(), new SystemDataContainerHolder(wdc));
+ CacheableWorkspaceDataManager cwdmNode2 =
+ new CacheableWorkspaceDataManager(wdc, cache2 = getCacheImpl(), new SystemDataContainerHolder(wdc));
+ NodeData parentNode = new PersistedNodeData("parent-id", QPath.makeChildPath(Constants.ROOT_PATH, new InternalQName(null, "parent-node")), Constants.ROOT_UUID, 1, 0,
+ Constants.NT_UNSTRUCTURED, new InternalQName[0], null);
+ // Test getChildNodesData
+ Action readAction = new Action(cwdmNode2)
+ {
+ public void execute(NodeData parentNode) throws Exception
+ {
+ cwdm.getChildNodesData(parentNode);
+ }
+ };
+ Action writeAction = new Action(cwdmNode1)
+ {
+ public void execute(NodeData parentNode) throws Exception
+ {
+ PlainChangesLog chlog = new PlainChangesLogImpl();
+ cwdm.getChildNodesData(parentNode);
+ chlog.add(ItemState.createAddedState(new PersistedNodeData("id-node" + parentNode.getIdentifier(), QPath.makeChildPath(parentNode.getQPath(), new InternalQName(null, "node")), parentNode.getIdentifier(), 1, 0,
+ Constants.NT_UNSTRUCTURED, new InternalQName[0], null)));
+ cwdm.save(chlog);
+ }
+ };
+ executeConcurrentReadNWrite(con, readAction, writeAction, Mode.READ_FIRST, parentNode);
+ assertNotNull(cwdmNode1.getChildNodesData(parentNode));
+ assertEquals(2, cwdmNode1.getChildNodesData(parentNode).size());
+ assertNotNull(cwdmNode2.getChildNodesData(parentNode));
+ assertEquals(2, cwdmNode2.getChildNodesData(parentNode).size());
+ parentNode = new PersistedNodeData("parent-id2", QPath.makeChildPath(Constants.ROOT_PATH, new InternalQName(null, "parent-node2")), Constants.ROOT_UUID, 1, 0,
+ Constants.NT_UNSTRUCTURED, new InternalQName[0], null);
+ executeConcurrentReadNWrite(con, readAction, writeAction, Mode.WRITE_FIRST, parentNode);
+ assertNotNull(cwdmNode1.getChildNodesData(parentNode));
+ assertEquals(2, cwdmNode1.getChildNodesData(parentNode).size());
+ assertNotNull(cwdmNode2.getChildNodesData(parentNode));
+ assertEquals(2, cwdmNode2.getChildNodesData(parentNode).size());
+ // Test getChildPropertiesData
+ readAction = new Action(cwdmNode2)
+ {
+ public void execute(NodeData parentNode) throws Exception
+ {
+ cwdm.getChildPropertiesData(parentNode);
+ }
+ };
+ writeAction = new Action(cwdmNode1)
+ {
+ public void execute(NodeData parentNode) throws Exception
+ {
+ PlainChangesLog chlog = new PlainChangesLogImpl();
+ cwdm.getChildPropertiesData(parentNode);
+ chlog.add(ItemState.createAddedState(new PersistedPropertyData("id-property" + parentNode.getIdentifier(), QPath.makeChildPath(
+ parentNode.getQPath(), new InternalQName(null, "property")), parentNode.getIdentifier(), 0,
+ PropertyType.STRING, false, Arrays.asList((ValueData)new ByteArrayPersistedValueData(0, "some data".getBytes("UTF-8"))))));
+ cwdm.save(chlog);
+ }
+ };
+ parentNode = new PersistedNodeData("parent-id3", QPath.makeChildPath(Constants.ROOT_PATH, new InternalQName(null, "parent-node3")), Constants.ROOT_UUID, 1, 0,
+ Constants.NT_UNSTRUCTURED, new InternalQName[0], null);
+ executeConcurrentReadNWrite(con, readAction, writeAction, Mode.READ_FIRST, parentNode);
+ assertNotNull(cwdmNode1.getChildPropertiesData(parentNode));
+ assertEquals(2, cwdmNode1.getChildPropertiesData(parentNode).size());
+ assertNotNull(cwdmNode2.getChildPropertiesData(parentNode));
+ assertEquals(2, cwdmNode2.getChildPropertiesData(parentNode).size());
+ parentNode = new PersistedNodeData("parent-id4", QPath.makeChildPath(Constants.ROOT_PATH, new InternalQName(null, "parent-node4")), Constants.ROOT_UUID, 1, 0,
+ Constants.NT_UNSTRUCTURED, new InternalQName[0], null);
+ executeConcurrentReadNWrite(con, readAction, writeAction, Mode.WRITE_FIRST, parentNode);
+ assertNotNull(cwdmNode1.getChildPropertiesData(parentNode));
+ assertEquals(2, cwdmNode1.getChildPropertiesData(parentNode).size());
+ assertNotNull(cwdmNode2.getChildPropertiesData(parentNode));
+ assertEquals(2, cwdmNode2.getChildPropertiesData(parentNode).size());
+ // Test getReferencesData
+ readAction = new Action(cwdmNode2)
+ {
+ public void execute(NodeData parentNode) throws Exception
+ {
+ cwdm.getReferencesData(parentNode.getIdentifier(), false);
+ }
+ };
+ writeAction = new Action(cwdmNode1)
+ {
+ public void execute(NodeData parentNode) throws Exception
+ {
+ PlainChangesLog chlog = new PlainChangesLogImpl();
+ cwdm.getReferencesData(parentNode.getIdentifier(), false);
+ chlog.add(ItemState.createAddedState(new PersistedPropertyData("id-reference" + parentNode.getIdentifier(), QPath.makeChildPath(
+ parentNode.getQPath(), new InternalQName(null, "reference")), parentNode.getIdentifier(), 0,
+ PropertyType.REFERENCE, false, Arrays.asList((ValueData)new ByteArrayPersistedValueData(0, parentNode.getIdentifier().getBytes("UTF-8"))))));
+ cwdm.save(chlog);
+ }
+ };
+ parentNode = new PersistedNodeData("parent-id5", QPath.makeChildPath(Constants.ROOT_PATH, new InternalQName(null, "parent-node5")), Constants.ROOT_UUID, 1, 0,
+ Constants.NT_UNSTRUCTURED, new InternalQName[0], null);
+ executeConcurrentReadNWrite(con, readAction, writeAction, Mode.READ_FIRST, parentNode);
+ assertNotNull(cwdmNode1.getReferencesData(parentNode.getIdentifier(), false));
+ assertEquals(2, cwdmNode1.getReferencesData(parentNode.getIdentifier(), false).size());
+ assertNotNull(cwdmNode2.getReferencesData(parentNode.getIdentifier(), false));
+ assertEquals(2, cwdmNode2.getReferencesData(parentNode.getIdentifier(), false).size());
+ parentNode = new PersistedNodeData("parent-id6", QPath.makeChildPath(Constants.ROOT_PATH, new InternalQName(null, "parent-node6")), Constants.ROOT_UUID, 1, 0,
+ Constants.NT_UNSTRUCTURED, new InternalQName[0], null);
+ executeConcurrentReadNWrite(con, readAction, writeAction, Mode.WRITE_FIRST, parentNode);
+ assertNotNull(cwdmNode1.getReferencesData(parentNode.getIdentifier(), false));
+ assertEquals(2, cwdmNode1.getReferencesData(parentNode.getIdentifier(), false).size());
+ assertNotNull(cwdmNode2.getReferencesData(parentNode.getIdentifier(), false));
+ assertEquals(2, cwdmNode2.getReferencesData(parentNode.getIdentifier(), false).size());
+
+ // Test getItemData by Id
+ readAction = new Action(cwdmNode2)
+ {
+ public void execute(NodeData parentNode) throws Exception
+ {
+ cwdm.getItemData(parentNode.getIdentifier());
+ }
+ };
+ writeAction = new Action(cwdmNode1)
+ {
+ public void execute(NodeData parentNode) throws Exception
+ {
+ PlainChangesLog chlog = new PlainChangesLogImpl();
+ cwdm.getItemData(parentNode.getIdentifier());
+ chlog.add(ItemState.createUpdatedState(new PersistedNodeData(parentNode.getIdentifier(), parentNode.getQPath(), Constants.ROOT_UUID, 2, 1,
+ Constants.NT_UNSTRUCTURED, new InternalQName[0], null)));
+ cwdm.save(chlog);
+ }
+ };
+ parentNode = new PersistedNodeData("parent-id7", QPath.makeChildPath(Constants.ROOT_PATH, new InternalQName(null, "parent-node7")), Constants.ROOT_UUID, 1, 0,
+ Constants.NT_UNSTRUCTURED, new InternalQName[0], null);
+ executeConcurrentReadNWrite(con, readAction, writeAction, Mode.READ_FIRST, parentNode);
+ assertNotNull(cwdmNode1.getItemData(parentNode.getIdentifier()));
+ assertEquals(2, cwdmNode1.getItemData(parentNode.getIdentifier()).getPersistedVersion());
+ assertNotNull(cwdmNode2.getItemData(parentNode.getIdentifier()));
+ assertEquals(2, cwdmNode2.getItemData(parentNode.getIdentifier()).getPersistedVersion());
+ parentNode = new PersistedNodeData("parent-id8", QPath.makeChildPath(Constants.ROOT_PATH, new InternalQName(null, "parent-node8")), Constants.ROOT_UUID, 1, 0,
+ Constants.NT_UNSTRUCTURED, new InternalQName[0], null);
+ executeConcurrentReadNWrite(con, readAction, writeAction, Mode.WRITE_FIRST, parentNode);
+ assertNotNull(cwdmNode1.getItemData(parentNode.getIdentifier()));
+ assertEquals(2, cwdmNode1.getItemData(parentNode.getIdentifier()).getPersistedVersion());
+ assertNotNull(cwdmNode2.getItemData(parentNode.getIdentifier()));
+ assertEquals(2, cwdmNode2.getItemData(parentNode.getIdentifier()).getPersistedVersion());
+
+ // Test getItemData by Path
+ final QPathEntry qpe = new QPathEntry(null, "my-property", 1);
+ readAction = new Action(cwdmNode2)
+ {
+ public void execute(NodeData parentNode) throws Exception
+ {
+ cwdm.getItemData(parentNode, qpe, ItemType.PROPERTY);
+ }
+ };
+ writeAction = new Action(cwdmNode1)
+ {
+ public void execute(NodeData parentNode) throws Exception
+ {
+ PlainChangesLog chlog = new PlainChangesLogImpl();
+ cwdm.getItemData(parentNode, qpe, ItemType.PROPERTY);
+ chlog.add(ItemState.createUpdatedState(new PersistedPropertyData("property-by-path"
+ + parentNode.getIdentifier(), QPath.makeChildPath(parentNode.getQPath(), qpe), parentNode
+ .getIdentifier(), 2, PropertyType.STRING, false, Arrays
+ .asList((ValueData)new ByteArrayPersistedValueData(0, "some new data".getBytes("UTF-8"))))));
+ cwdm.save(chlog);
+ }
+ };
+ parentNode = new PersistedNodeData("parent-id9", QPath.makeChildPath(Constants.ROOT_PATH, new InternalQName(null, "parent-node9")), Constants.ROOT_UUID, 1, 0,
+ Constants.NT_UNSTRUCTURED, new InternalQName[0], null);
+ executeConcurrentReadNWrite(con, readAction, writeAction, Mode.READ_FIRST, parentNode);
+ assertNotNull(cwdmNode1.getItemData(parentNode, qpe, ItemType.PROPERTY));
+ assertEquals(2, cwdmNode1.getItemData(parentNode, qpe, ItemType.PROPERTY).getPersistedVersion());
+ assertNotNull(cwdmNode2.getItemData(parentNode, qpe, ItemType.PROPERTY));
+ assertEquals(2, cwdmNode2.getItemData(parentNode, qpe, ItemType.PROPERTY).getPersistedVersion());
+ parentNode = new PersistedNodeData("parent-id10", QPath.makeChildPath(Constants.ROOT_PATH, new InternalQName(null, "parent-node10")), Constants.ROOT_UUID, 1, 0,
+ Constants.NT_UNSTRUCTURED, new InternalQName[0], null);
+ executeConcurrentReadNWrite(con, readAction, writeAction, Mode.WRITE_FIRST, parentNode);
+ assertNotNull(cwdmNode1.getItemData(parentNode, qpe, ItemType.PROPERTY));
+ assertEquals(2, cwdmNode1.getItemData(parentNode, qpe, ItemType.PROPERTY).getPersistedVersion());
+ assertNotNull(cwdmNode2.getItemData(parentNode, qpe, ItemType.PROPERTY));
+ assertEquals(2, cwdmNode2.getItemData(parentNode, qpe, ItemType.PROPERTY).getPersistedVersion());
+ }
+ finally
+ {
+ if (cache1 != null)
+ {
+ try
+ {
+ finalize(cache1);
+ }
+ catch (Exception e)
+ {
+ // ignore me
+ }
+ }
+ if (cache2 != null)
+ {
+ try
+ {
+ finalize(cache2);
+ }
+ catch (Exception e)
+ {
+ // ignore me
+ }
+ }
+ }
+ }
+
+ protected void finalize(T cache)
+ {
+ }
+
+ /**
+ * @param con
+ * @param cwdm
+ * @param mode
+ * @param idNode
+ * @throws InterruptedException
+ */
+ private void executeConcurrentReadNWrite(final MyWorkspaceStorageConnection con, final Action readAction,
+ final Action writeAction, final Mode mode, final NodeData parentNode) throws InterruptedException
+ {
+ final CountDownLatch goSignal = con.initCountDownLatch();
+ con.setParentNode(parentNode);
+ final AtomicReference<Exception> ex = new AtomicReference<Exception>();
+ final CountDownLatch startSignal = new CountDownLatch(1);
+ final CountDownLatch doneSignal = new CountDownLatch(2);
+ Thread writer = new Thread()
+ {
+ public void run()
+ {
+ try
+ {
+ startSignal.await();
+ con.wait.set(mode != Mode.WRITE_FIRST);
+ writeAction.execute(parentNode);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ ex.set(e);
+ }
+ finally
+ {
+ if (mode == Mode.WRITE_FIRST) goSignal.countDown();
+ doneSignal.countDown();
+ }
+ }
+ };
+ writer.start();
+ Thread reader = new Thread()
+ {
+ public void run()
+ {
+ try
+ {
+ startSignal.await();
+ con.wait.set(mode != Mode.READ_FIRST);
+ readAction.execute(parentNode);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ ex.set(e);
+ }
+ finally
+ {
+ if (mode == Mode.READ_FIRST) goSignal.countDown();
+ doneSignal.countDown();
+ }
+ }
+ };
+ reader.start();
+ startSignal.countDown();
+ doneSignal.await();
+ assertNull(ex.get());
+ }
+
+ private abstract class Action
+ {
+
+ protected final CacheableWorkspaceDataManager cwdm;
+ public Action(CacheableWorkspaceDataManager cwdm)
+ {
+ this.cwdm = cwdm;
+ }
+ protected abstract void execute(NodeData parentNode) throws Exception;
+ }
+ private static enum Mode
+ {
+ READ_FIRST, WRITE_FIRST;
+ }
+ private static class MyWorkspaceStorageConnection implements WorkspaceStorageConnection
+ {
+ public ThreadLocal<Boolean> wait = new ThreadLocal<Boolean>();
+ private NodeData parentNode;
+ private CountDownLatch goSignal;
+
+ public CountDownLatch initCountDownLatch()
+ {
+ return this.goSignal = new CountDownLatch(1);
+ }
+
+ public void setParentNode(NodeData parentNode)
+ {
+ this.parentNode = parentNode;
+ }
+
+ public void add(NodeData data) throws RepositoryException, UnsupportedOperationException,
+ InvalidItemStateException, IllegalStateException
+ {
+ }
+
+ public void add(PropertyData data) throws RepositoryException, UnsupportedOperationException,
+ InvalidItemStateException, IllegalStateException
+ {
+ }
+
+ public void close() throws IllegalStateException, RepositoryException
+ {
+ }
+
+ public void commit() throws IllegalStateException, RepositoryException
+ {
+ if (wait.get() != null && wait.get())
+ {
+ try
+ {
+ goSignal.await();
+ }
+ catch (InterruptedException e)
+ {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ public void delete(NodeData data) throws RepositoryException, UnsupportedOperationException,
+ InvalidItemStateException, IllegalStateException
+ {
+ }
+
+ public void delete(PropertyData data) throws RepositoryException, UnsupportedOperationException,
+ InvalidItemStateException, IllegalStateException
+ {
+ }
+
+ public int getChildNodesCount(NodeData parent) throws RepositoryException
+ {
+ return -1;
+ }
+
+ public List<NodeData> getChildNodesData(NodeData parent) throws RepositoryException, IllegalStateException
+ {
+ if (wait.get() != null && wait.get())
+ {
+ try
+ {
+ goSignal.await();
+ }
+ catch (InterruptedException e)
+ {
+ Thread.currentThread().interrupt();
+ }
+ }
+ List<NodeData> children = new ArrayList<NodeData>();
+ children.add(new PersistedNodeData("id-node2" + parentNode.getIdentifier(), QPath.makeChildPath(parent.getQPath(), new InternalQName(null, "node2")), parent.getIdentifier(), 1, 0,
+ Constants.NT_UNSTRUCTURED, new InternalQName[0], null));
+ return children;
+ }
+
+ public List<PropertyData> getChildPropertiesData(NodeData parent) throws RepositoryException,
+ IllegalStateException
+ {
+ if (wait.get() != null && wait.get())
+ {
+ try
+ {
+ goSignal.await();
+ }
+ catch (InterruptedException e)
+ {
+ Thread.currentThread().interrupt();
+ }
+ }
+ List<PropertyData> children = new ArrayList<PropertyData>();
+ try
+ {
+ children.add(new PersistedPropertyData("id-property2" + parentNode.getIdentifier(), QPath.makeChildPath(
+ parentNode.getQPath(), new InternalQName(null, "property2")), parentNode.getIdentifier(), 0,
+ PropertyType.STRING, false, Arrays.asList((ValueData)new ByteArrayPersistedValueData(0, "some data".getBytes("UTF-8")))));
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ e.printStackTrace();
+ }
+ return children;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ItemData getItemData(NodeData parentData, QPathEntry name) throws RepositoryException,
+ IllegalStateException
+ {
+ return getItemData(parentData, name, ItemType.UNKNOWN);
+ }
+
+ public ItemData getItemData(NodeData parentData, QPathEntry name, ItemType itemType) throws RepositoryException,
+ IllegalStateException
+ {
+ if (wait.get() != null && wait.get())
+ {
+ try
+ {
+ goSignal.await();
+ }
+ catch (InterruptedException e)
+ {
+ Thread.currentThread().interrupt();
+ }
+ }
+ if (itemType == ItemType.NODE)
+ {
+ return new PersistedNodeData("my-node" + parentNode.getIdentifier(), QPath.makeChildPath(parentNode.getQPath(), name), Constants.ROOT_UUID, 1, 1,
+ Constants.NT_UNSTRUCTURED, new InternalQName[0], null);
+ }
+ try
+ {
+ return new PersistedPropertyData("property-by-path"
+ + parentNode.getIdentifier(), QPath.makeChildPath(parentNode.getQPath(), name), parentNode
+ .getIdentifier(), 1, PropertyType.STRING, false, Arrays
+ .asList((ValueData)new ByteArrayPersistedValueData(0, "some new data".getBytes("UTF-8"))));
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ public ItemData getItemData(String identifier) throws RepositoryException, IllegalStateException
+ {
+ if (wait.get() != null && wait.get())
+ {
+ try
+ {
+ goSignal.await();
+ }
+ catch (InterruptedException e)
+ {
+ Thread.currentThread().interrupt();
+ }
+ }
+ return parentNode;
+ }
+
+ public List<PropertyData> getReferencesData(String nodeIdentifier) throws RepositoryException,
+ IllegalStateException, UnsupportedOperationException
+ {
+ if (wait.get() != null && wait.get())
+ {
+ try
+ {
+ goSignal.await();
+ }
+ catch (InterruptedException e)
+ {
+ Thread.currentThread().interrupt();
+ }
+ }
+ List<PropertyData> children = new ArrayList<PropertyData>();
+ try
+ {
+ children.add(new PersistedPropertyData("id-reference2" + parentNode.getIdentifier(), QPath.makeChildPath(
+ parentNode.getQPath(), new InternalQName(null, "reference2")), parentNode.getIdentifier(), 0,
+ PropertyType.REFERENCE, false, Arrays.asList((ValueData)new ByteArrayPersistedValueData(0, parentNode.getIdentifier().getBytes("UTF-8")))));
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ e.printStackTrace();
+ }
+ return children;
+ }
+
+ public boolean isOpened()
+ {
+ return true;
+ }
+
+ public List<PropertyData> listChildPropertiesData(NodeData parent) throws RepositoryException,
+ IllegalStateException
+ {
+ return null;
+ }
+
+ public void rename(NodeData data) throws RepositoryException, UnsupportedOperationException,
+ InvalidItemStateException, IllegalStateException
+ {
+ }
+
+ public void rollback() throws IllegalStateException, RepositoryException
+ {
+ }
+
+ public void update(NodeData data) throws RepositoryException, UnsupportedOperationException,
+ InvalidItemStateException, IllegalStateException
+ {
+ }
+
+ public void update(PropertyData data) throws RepositoryException, UnsupportedOperationException,
+ InvalidItemStateException, IllegalStateException
+ {
+ }
+
+ /**
+ * @see org.exoplatform.services.jcr.storage.WorkspaceStorageConnection#getLastOrderNumber(org.exoplatform.services.jcr.datamodel.NodeData)
+ */
+ public int getLastOrderNumber(NodeData parent) throws RepositoryException
+ {
+ return 0;
+ }
+ };
+
+ private static class MyWorkspaceDataContainer extends WorkspaceDataContainerBase
+ {
+
+ private WorkspaceStorageConnection con;
+
+ public MyWorkspaceDataContainer(WorkspaceStorageConnection con)
+ {
+ this.con = con;
+ }
+
+ public boolean isCheckSNSNewConnection()
+ {
+ return false;
+ }
+
+ public boolean isSame(WorkspaceDataContainer another)
+ {
+ return false;
+ }
+
+ public WorkspaceStorageConnection openConnection() throws RepositoryException
+ {
+ return con;
+ }
+
+ public WorkspaceStorageConnection openConnection(boolean readOnly) throws RepositoryException
+ {
+ return con;
+ }
+
+ public WorkspaceStorageConnection reuseConnection(WorkspaceStorageConnection original) throws RepositoryException
+ {
+ return con;
+ }
+
+ public String getInfo()
+ {
+ return "MyWorkspaceDataContainer";
+ }
+
+ public String getName()
+ {
+ return "MyWorkspaceDataContainer";
+ }
+
+ public String getStorageVersion()
+ {
+ return "0";
+ }
+
+ /**
+ * @see org.exoplatform.services.jcr.storage.DataContainer#getUniqueName()
+ */
+ public String getUniqueName()
+ {
+ return "MyWorkspaceDataContainer";
+ }
+ };
+}
Added: jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/infinispan/TestISPNCacheWorkspaceStorageCacheInClusterMode.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/infinispan/TestISPNCacheWorkspaceStorageCacheInClusterMode.java (rev 0)
+++ jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/infinispan/TestISPNCacheWorkspaceStorageCacheInClusterMode.java 2011-04-15 19:11:33 UTC (rev 4240)
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.jcr.impl.dataflow.persistent.infinispan;
+
+import org.exoplatform.container.configuration.ConfigurationManagerImpl;
+import org.exoplatform.services.jcr.config.CacheEntry;
+import org.exoplatform.services.jcr.config.SimpleParameterEntry;
+import org.exoplatform.services.jcr.config.WorkspaceEntry;
+import org.exoplatform.services.jcr.impl.dataflow.persistent.TestWorkspaceStorageCacheInClusterMode;
+import org.exoplatform.services.jcr.infinispan.ISPNCacheFactory;
+
+import java.util.ArrayList;
+
+/**
+ * @author <a href="mailto:nfilotto@exoplatform.com">Nicolas Filotto</a>
+ * @version $Id$
+ *
+ */
+public class TestISPNCacheWorkspaceStorageCacheInClusterMode extends TestWorkspaceStorageCacheInClusterMode<ISPNCacheWorkspaceStorageCache>
+{
+
+ public ISPNCacheWorkspaceStorageCache getCacheImpl() throws Exception
+ {
+ ArrayList<SimpleParameterEntry> list = new ArrayList<SimpleParameterEntry>();
+ list.add(new SimpleParameterEntry(ISPNCacheFactory.INFINISPAN_CONFIG,
+ "jar:/conf/standalone/cluster/test-infinispan-config.xml"));
+ list.add(new SimpleParameterEntry("infinispan-cluster-name", "TestISPNCacheWorkspaceStorageCacheInClusterMode"));
+ list.add(new SimpleParameterEntry("jgroups-configuration", "jar:/conf/standalone/cluster/udp-mux.xml"));
+
+ CacheEntry entry = new CacheEntry(list);
+ entry.setEnabled(true);
+ WorkspaceEntry workspaceEntry = new WorkspaceEntry();
+ workspaceEntry.setCache(entry);
+ workspaceEntry.setUniqueName("MyWorkspace");
+ return new ISPNCacheWorkspaceStorageCache(workspaceEntry, new ConfigurationManagerImpl());
+ }
+
+ protected void finalize(ISPNCacheWorkspaceStorageCache cache)
+ {
+ cache.cache.stop();
+ }
+}
\ No newline at end of file
Added: jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/TestJBossCacheWorkspaceStorageCacheInClusterMode.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/TestJBossCacheWorkspaceStorageCacheInClusterMode.java (rev 0)
+++ jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/TestJBossCacheWorkspaceStorageCacheInClusterMode.java 2011-04-15 19:11:33 UTC (rev 4240)
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2011 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.jcr.impl.dataflow.persistent.jbosscache;
+
+import org.exoplatform.container.configuration.ConfigurationManagerImpl;
+import org.exoplatform.services.jcr.config.CacheEntry;
+import org.exoplatform.services.jcr.config.SimpleParameterEntry;
+import org.exoplatform.services.jcr.config.WorkspaceEntry;
+import org.exoplatform.services.jcr.impl.dataflow.persistent.TestWorkspaceStorageCacheInClusterMode;
+import org.exoplatform.services.transaction.TransactionService;
+
+import java.util.ArrayList;
+
+/**
+ * @author <a href="mailto:nicolas.filotto@exoplatform.com">Nicolas Filotto</a>
+ * @version $Id$
+ */
+public class TestJBossCacheWorkspaceStorageCacheInClusterMode extends TestWorkspaceStorageCacheInClusterMode<JBossCacheWorkspaceStorageCache>
+{
+
+ public JBossCacheWorkspaceStorageCache getCacheImpl() throws Exception
+ {
+ TransactionService transactionService =
+ (TransactionService)container.getComponentInstanceOfType(TransactionService.class);
+
+ ArrayList<SimpleParameterEntry> list = new ArrayList<SimpleParameterEntry>();
+ list.add(new SimpleParameterEntry(JBossCacheWorkspaceStorageCache.JBOSSCACHE_CONFIG,
+ "jar:/conf/standalone/cluster/test-jbosscache-data-no-mux.xml"));
+ list.add(new SimpleParameterEntry("jbosscache-cluster-name", "TestJBossCacheWorkspaceStorageCacheInClusterMode"));
+
+ CacheEntry entry = new CacheEntry(list);
+ entry.setEnabled(true);
+ WorkspaceEntry workspaceEntry = new WorkspaceEntry();
+ workspaceEntry.setCache(entry);
+ workspaceEntry.setUniqueName("MyWorkspace");
+ JBossCacheWorkspaceStorageCache cache = new JBossCacheWorkspaceStorageCache(workspaceEntry,
+ transactionService == null ? null : transactionService, new ConfigurationManagerImpl());
+ cache.start();
+ return cache;
+ }
+
+ protected void finalize(JBossCacheWorkspaceStorageCache cache)
+ {
+ cache.cache.stop();
+ }
+}
\ No newline at end of file
Added: jcr/trunk/exo.jcr.component.core/src/test/resources/conf/standalone/cluster/test-jbosscache-data-no-mux.xml
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/test/resources/conf/standalone/cluster/test-jbosscache-data-no-mux.xml (rev 0)
+++ jcr/trunk/exo.jcr.component.core/src/test/resources/conf/standalone/cluster/test-jbosscache-data-no-mux.xml 2011-04-15 19:11:33 UTC (rev 4240)
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<jbosscache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:jboss:jbosscache-core:config:3.1">
+
+ <locking useLockStriping="false" concurrencyLevel="500" lockParentForChildInsertRemove="false"
+ lockAcquisitionTimeout="20000" />
+ <transaction syncRollbackPhase="true" syncCommitPhase="true" />
+
+ <clustering mode="replication" clusterName="${jbosscache-cluster-name}">
+ <stateRetrieval timeout="20000" fetchInMemoryState="false" />
+ <sync replTimeout="20000"/>
+ <jgroupsConfig configFile="udp.xml">
+ </jgroupsConfig>
+ </clustering>
+
+ <!-- Eviction configuration -->
+ <eviction wakeUpInterval="5000">
+ <default algorithmClass="org.jboss.cache.eviction.ExpirationAlgorithm"
+ actionPolicyClass="org.exoplatform.services.jcr.impl.dataflow.persistent.jbosscache.ParentNodeEvictionActionPolicy"
+ eventQueueSize="1000000">
+ <property name="maxNodes" value="1000000" />
+ <property name="warnNoExpirationKey" value="false" />
+ </default>
+ </eviction>
+</jbosscache>
\ No newline at end of file
15 years
exo-jcr SVN: r4239 - jcr/trunk/exo.jcr.component.webdav/src/test/java/org/exoplatform/services/jcr/webdav/command.
by do-not-reply@jboss.org
Author: nfilotto
Date: 2011-04-15 14:02:47 -0400 (Fri, 15 Apr 2011)
New Revision: 4239
Modified:
jcr/trunk/exo.jcr.component.webdav/src/test/java/org/exoplatform/services/jcr/webdav/command/TestPropFind.java
jcr/trunk/exo.jcr.component.webdav/src/test/java/org/exoplatform/services/jcr/webdav/command/TestSearch.java
Log:
EXOJCR-1307: Failing tests in the webdav project due to an encoding issue
Modified: jcr/trunk/exo.jcr.component.webdav/src/test/java/org/exoplatform/services/jcr/webdav/command/TestPropFind.java
===================================================================
--- jcr/trunk/exo.jcr.component.webdav/src/test/java/org/exoplatform/services/jcr/webdav/command/TestPropFind.java 2011-04-15 13:26:15 UTC (rev 4238)
+++ jcr/trunk/exo.jcr.component.webdav/src/test/java/org/exoplatform/services/jcr/webdav/command/TestPropFind.java 2011-04-15 18:02:47 UTC (rev 4239)
@@ -150,7 +150,7 @@
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
PropFindResponseEntity entity = (PropFindResponseEntity)response.getEntity();
entity.write(outputStream);
- String resp = outputStream.toString();
+ String resp = outputStream.toString("UTF-8");
System.out.println("=======PropFind response==========");
System.out.println(resp);
Modified: jcr/trunk/exo.jcr.component.webdav/src/test/java/org/exoplatform/services/jcr/webdav/command/TestSearch.java
===================================================================
--- jcr/trunk/exo.jcr.component.webdav/src/test/java/org/exoplatform/services/jcr/webdav/command/TestSearch.java 2011-04-15 13:26:15 UTC (rev 4238)
+++ jcr/trunk/exo.jcr.component.webdav/src/test/java/org/exoplatform/services/jcr/webdav/command/TestSearch.java 2011-04-15 18:02:47 UTC (rev 4239)
@@ -92,7 +92,7 @@
SearchResultResponseEntity entity = (SearchResultResponseEntity)response.getEntity();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
entity.write(outputStream);
- String resp = outputStream.toString();
+ String resp = outputStream.toString("UTF-8");
System.out.println("=======Search response============");
System.out.println(resp);
15 years
exo-jcr SVN: r4238 - jcr/branches/1.12.x/patch/1.12.9-GA/JCR-1604.
by do-not-reply@jboss.org
Author: sergiykarpenko
Date: 2011-04-15 09:26:15 -0400 (Fri, 15 Apr 2011)
New Revision: 4238
Modified:
jcr/branches/1.12.x/patch/1.12.9-GA/JCR-1604/JCR-1604.patch
Log:
JCR-1604: new patch proposed
Modified: jcr/branches/1.12.x/patch/1.12.9-GA/JCR-1604/JCR-1604.patch
===================================================================
--- jcr/branches/1.12.x/patch/1.12.9-GA/JCR-1604/JCR-1604.patch 2011-04-14 14:09:41 UTC (rev 4237)
+++ jcr/branches/1.12.x/patch/1.12.9-GA/JCR-1604/JCR-1604.patch 2011-04-15 13:26:15 UTC (rev 4238)
@@ -1,8 +1,780 @@
+Index: exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/TestJBossCacheWorkspaceStorageCacheInClusterMode.java
+===================================================================
+--- exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/TestJBossCacheWorkspaceStorageCacheInClusterMode.java (revision 0)
++++ exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/TestJBossCacheWorkspaceStorageCacheInClusterMode.java (revision 0)
+@@ -0,0 +1,648 @@
++/*
++ * Copyright (C) 2011 eXo Platform SAS.
++ *
++ * This is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU Lesser General Public License as
++ * published by the Free Software Foundation; either version 2.1 of
++ * the License, or (at your option) any later version.
++ *
++ * This software is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this software; if not, write to the Free
++ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
++ */
++package org.exoplatform.services.jcr.impl.dataflow.persistent.jbosscache;
++
++import org.exoplatform.container.configuration.ConfigurationManagerImpl;
++import org.exoplatform.services.jcr.JcrImplBaseTest;
++import org.exoplatform.services.jcr.config.CacheEntry;
++import org.exoplatform.services.jcr.config.SimpleParameterEntry;
++import org.exoplatform.services.jcr.config.WorkspaceEntry;
++import org.exoplatform.services.jcr.dataflow.ItemState;
++import org.exoplatform.services.jcr.dataflow.PlainChangesLog;
++import org.exoplatform.services.jcr.dataflow.PlainChangesLogImpl;
++import org.exoplatform.services.jcr.dataflow.persistent.PersistedNodeData;
++import org.exoplatform.services.jcr.dataflow.persistent.PersistedPropertyData;
++import org.exoplatform.services.jcr.datamodel.InternalQName;
++import org.exoplatform.services.jcr.datamodel.ItemData;
++import org.exoplatform.services.jcr.datamodel.ItemType;
++import org.exoplatform.services.jcr.datamodel.NodeData;
++import org.exoplatform.services.jcr.datamodel.PropertyData;
++import org.exoplatform.services.jcr.datamodel.QPath;
++import org.exoplatform.services.jcr.datamodel.QPathEntry;
++import org.exoplatform.services.jcr.datamodel.ValueData;
++import org.exoplatform.services.jcr.impl.Constants;
++import org.exoplatform.services.jcr.impl.dataflow.persistent.ByteArrayPersistedValueData;
++import org.exoplatform.services.jcr.impl.dataflow.persistent.CacheableWorkspaceDataManager;
++import org.exoplatform.services.jcr.impl.storage.SystemDataContainerHolder;
++import org.exoplatform.services.jcr.impl.storage.WorkspaceDataContainerBase;
++import org.exoplatform.services.jcr.storage.WorkspaceDataContainer;
++import org.exoplatform.services.jcr.storage.WorkspaceStorageConnection;
++import org.exoplatform.services.transaction.TransactionService;
++
++import java.io.UnsupportedEncodingException;
++import java.util.ArrayList;
++import java.util.Arrays;
++import java.util.List;
++import java.util.concurrent.CountDownLatch;
++import java.util.concurrent.atomic.AtomicReference;
++
++import javax.jcr.InvalidItemStateException;
++import javax.jcr.PropertyType;
++import javax.jcr.RepositoryException;
++
++/**
++ * @author <a href="mailto:nicolas.filotto@exoplatform.com">Nicolas Filotto</a>
++ * @version $Id$
++ */
++public class TestJBossCacheWorkspaceStorageCacheInClusterMode extends JcrImplBaseTest
++{
++
++ public JBossCacheWorkspaceStorageCache getCacheImpl() throws Exception
++ {
++ TransactionService transactionService =
++ (TransactionService)container.getComponentInstanceOfType(TransactionService.class);
++
++ ArrayList<SimpleParameterEntry> list = new ArrayList<SimpleParameterEntry>();
++ list.add(new SimpleParameterEntry(JBossCacheWorkspaceStorageCache.JBOSSCACHE_CONFIG,
++ "jar:/conf/standalone/cluster/test-jbosscache-data-no-mux.xml"));
++ list.add(new SimpleParameterEntry("jbosscache-cluster-name", "TestJBossCacheWorkspaceStorageCacheInClusterMode"));
++
++ CacheEntry entry = new CacheEntry(list);
++ WorkspaceEntry workspaceEntry = new WorkspaceEntry();
++ workspaceEntry.setCache(entry);
++ return new JBossCacheWorkspaceStorageCache(workspaceEntry,
++ transactionService == null ? null : transactionService, new ConfigurationManagerImpl());
++ }
++
++ public void testRaceConditions() throws Exception
++ {
++ JBossCacheWorkspaceStorageCache cache1 = null, cache2 = null;
++ try
++ {
++ MyWorkspaceStorageConnection con = new MyWorkspaceStorageConnection();
++ WorkspaceDataContainer wdc = new MyWorkspaceDataContainer(con);
++ CacheableWorkspaceDataManager cwdmNode1 =
++ new CacheableWorkspaceDataManager(wdc, cache1 = getCacheImpl(), new SystemDataContainerHolder(wdc));
++ CacheableWorkspaceDataManager cwdmNode2 =
++ new CacheableWorkspaceDataManager(wdc, cache2 = getCacheImpl(), new SystemDataContainerHolder(wdc));
++ NodeData parentNode = new PersistedNodeData("parent-id", QPath.makeChildPath(Constants.ROOT_PATH, new InternalQName(null, "parent-node")), Constants.ROOT_UUID, 1, 0,
++ Constants.NT_UNSTRUCTURED, new InternalQName[0], null);
++ // Test getChildNodesData
++ Action readAction = new Action(cwdmNode2)
++ {
++ public void execute(NodeData parentNode) throws Exception
++ {
++ cwdm.getChildNodesData(parentNode);
++ }
++ };
++ Action writeAction = new Action(cwdmNode1)
++ {
++ public void execute(NodeData parentNode) throws Exception
++ {
++ PlainChangesLog chlog = new PlainChangesLogImpl();
++ cwdm.getChildNodesData(parentNode);
++ chlog.add(ItemState.createAddedState(new PersistedNodeData("id-node" + parentNode.getIdentifier(), QPath.makeChildPath(parentNode.getQPath(), new InternalQName(null, "node")), parentNode.getIdentifier(), 1, 0,
++ Constants.NT_UNSTRUCTURED, new InternalQName[0], null)));
++ cwdm.save(chlog);
++ }
++ };
++ executeConcurrentReadNWrite(con, readAction, writeAction, Mode.READ_FIRST, parentNode);
++ assertNotNull(cwdmNode1.getChildNodesData(parentNode));
++ assertEquals(2, cwdmNode1.getChildNodesData(parentNode).size());
++ assertNotNull(cwdmNode2.getChildNodesData(parentNode));
++ assertEquals(2, cwdmNode2.getChildNodesData(parentNode).size());
++ parentNode = new PersistedNodeData("parent-id2", QPath.makeChildPath(Constants.ROOT_PATH, new InternalQName(null, "parent-node2")), Constants.ROOT_UUID, 1, 0,
++ Constants.NT_UNSTRUCTURED, new InternalQName[0], null);
++ executeConcurrentReadNWrite(con, readAction, writeAction, Mode.WRITE_FIRST, parentNode);
++ assertNotNull(cwdmNode1.getChildNodesData(parentNode));
++ assertEquals(2, cwdmNode1.getChildNodesData(parentNode).size());
++ assertNotNull(cwdmNode2.getChildNodesData(parentNode));
++ assertEquals(2, cwdmNode2.getChildNodesData(parentNode).size());
++ // Test getChildPropertiesData
++ readAction = new Action(cwdmNode2)
++ {
++ public void execute(NodeData parentNode) throws Exception
++ {
++ cwdm.getChildPropertiesData(parentNode);
++ }
++ };
++ writeAction = new Action(cwdmNode1)
++ {
++ public void execute(NodeData parentNode) throws Exception
++ {
++ PlainChangesLog chlog = new PlainChangesLogImpl();
++ cwdm.getChildPropertiesData(parentNode);
++ chlog.add(ItemState.createAddedState(new PersistedPropertyData("id-property" + parentNode.getIdentifier(), QPath.makeChildPath(
++ parentNode.getQPath(), new InternalQName(null, "property")), parentNode.getIdentifier(), 0,
++ PropertyType.STRING, false, Arrays.asList((ValueData)new ByteArrayPersistedValueData(0, "some data".getBytes("UTF-8"))))));
++ cwdm.save(chlog);
++ }
++ };
++ parentNode = new PersistedNodeData("parent-id3", QPath.makeChildPath(Constants.ROOT_PATH, new InternalQName(null, "parent-node3")), Constants.ROOT_UUID, 1, 0,
++ Constants.NT_UNSTRUCTURED, new InternalQName[0], null);
++ executeConcurrentReadNWrite(con, readAction, writeAction, Mode.READ_FIRST, parentNode);
++ assertNotNull(cwdmNode1.getChildPropertiesData(parentNode));
++ assertEquals(2, cwdmNode1.getChildPropertiesData(parentNode).size());
++ assertNotNull(cwdmNode2.getChildPropertiesData(parentNode));
++ assertEquals(2, cwdmNode2.getChildPropertiesData(parentNode).size());
++ parentNode = new PersistedNodeData("parent-id4", QPath.makeChildPath(Constants.ROOT_PATH, new InternalQName(null, "parent-node4")), Constants.ROOT_UUID, 1, 0,
++ Constants.NT_UNSTRUCTURED, new InternalQName[0], null);
++ executeConcurrentReadNWrite(con, readAction, writeAction, Mode.WRITE_FIRST, parentNode);
++ assertNotNull(cwdmNode1.getChildPropertiesData(parentNode));
++ assertEquals(2, cwdmNode1.getChildPropertiesData(parentNode).size());
++ assertNotNull(cwdmNode2.getChildPropertiesData(parentNode));
++ assertEquals(2, cwdmNode2.getChildPropertiesData(parentNode).size());
++ // Test getReferencesData
++ readAction = new Action(cwdmNode2)
++ {
++ public void execute(NodeData parentNode) throws Exception
++ {
++ cwdm.getReferencesData(parentNode.getIdentifier(), false);
++ }
++ };
++ writeAction = new Action(cwdmNode1)
++ {
++ public void execute(NodeData parentNode) throws Exception
++ {
++ PlainChangesLog chlog = new PlainChangesLogImpl();
++ cwdm.getReferencesData(parentNode.getIdentifier(), false);
++ chlog.add(ItemState.createAddedState(new PersistedPropertyData("id-reference" + parentNode.getIdentifier(), QPath.makeChildPath(
++ parentNode.getQPath(), new InternalQName(null, "reference")), parentNode.getIdentifier(), 0,
++ PropertyType.REFERENCE, false, Arrays.asList((ValueData)new ByteArrayPersistedValueData(0, parentNode.getIdentifier().getBytes("UTF-8"))))));
++ cwdm.save(chlog);
++ }
++ };
++ parentNode = new PersistedNodeData("parent-id5", QPath.makeChildPath(Constants.ROOT_PATH, new InternalQName(null, "parent-node5")), Constants.ROOT_UUID, 1, 0,
++ Constants.NT_UNSTRUCTURED, new InternalQName[0], null);
++ executeConcurrentReadNWrite(con, readAction, writeAction, Mode.READ_FIRST, parentNode);
++ assertNotNull(cwdmNode1.getReferencesData(parentNode.getIdentifier(), false));
++ assertEquals(2, cwdmNode1.getReferencesData(parentNode.getIdentifier(), false).size());
++ assertNotNull(cwdmNode2.getReferencesData(parentNode.getIdentifier(), false));
++ assertEquals(2, cwdmNode2.getReferencesData(parentNode.getIdentifier(), false).size());
++ parentNode = new PersistedNodeData("parent-id6", QPath.makeChildPath(Constants.ROOT_PATH, new InternalQName(null, "parent-node6")), Constants.ROOT_UUID, 1, 0,
++ Constants.NT_UNSTRUCTURED, new InternalQName[0], null);
++ executeConcurrentReadNWrite(con, readAction, writeAction, Mode.WRITE_FIRST, parentNode);
++ assertNotNull(cwdmNode1.getReferencesData(parentNode.getIdentifier(), false));
++ assertEquals(2, cwdmNode1.getReferencesData(parentNode.getIdentifier(), false).size());
++ assertNotNull(cwdmNode2.getReferencesData(parentNode.getIdentifier(), false));
++ assertEquals(2, cwdmNode2.getReferencesData(parentNode.getIdentifier(), false).size());
++
++ // Test getItemData by Id
++ readAction = new Action(cwdmNode2)
++ {
++ public void execute(NodeData parentNode) throws Exception
++ {
++ cwdm.getItemData(parentNode.getIdentifier());
++ }
++ };
++ writeAction = new Action(cwdmNode1)
++ {
++ public void execute(NodeData parentNode) throws Exception
++ {
++ PlainChangesLog chlog = new PlainChangesLogImpl();
++ cwdm.getItemData(parentNode.getIdentifier());
++ chlog.add(ItemState.createUpdatedState(new PersistedNodeData(parentNode.getIdentifier(), parentNode.getQPath(), Constants.ROOT_UUID, 2, 1,
++ Constants.NT_UNSTRUCTURED, new InternalQName[0], null)));
++ cwdm.save(chlog);
++ }
++ };
++ parentNode = new PersistedNodeData("parent-id7", QPath.makeChildPath(Constants.ROOT_PATH, new InternalQName(null, "parent-node7")), Constants.ROOT_UUID, 1, 0,
++ Constants.NT_UNSTRUCTURED, new InternalQName[0], null);
++ executeConcurrentReadNWrite(con, readAction, writeAction, Mode.READ_FIRST, parentNode);
++ assertNotNull(cwdmNode1.getItemData(parentNode.getIdentifier()));
++ assertEquals(2, cwdmNode1.getItemData(parentNode.getIdentifier()).getPersistedVersion());
++ assertNotNull(cwdmNode2.getItemData(parentNode.getIdentifier()));
++ assertEquals(2, cwdmNode2.getItemData(parentNode.getIdentifier()).getPersistedVersion());
++ parentNode = new PersistedNodeData("parent-id8", QPath.makeChildPath(Constants.ROOT_PATH, new InternalQName(null, "parent-node8")), Constants.ROOT_UUID, 1, 0,
++ Constants.NT_UNSTRUCTURED, new InternalQName[0], null);
++ executeConcurrentReadNWrite(con, readAction, writeAction, Mode.WRITE_FIRST, parentNode);
++ assertNotNull(cwdmNode1.getItemData(parentNode.getIdentifier()));
++ assertEquals(2, cwdmNode1.getItemData(parentNode.getIdentifier()).getPersistedVersion());
++ assertNotNull(cwdmNode2.getItemData(parentNode.getIdentifier()));
++ assertEquals(2, cwdmNode2.getItemData(parentNode.getIdentifier()).getPersistedVersion());
++
++ // Test getItemData by Path
++ final QPathEntry qpe = new QPathEntry(null, "my-property", 1);
++ readAction = new Action(cwdmNode2)
++ {
++ public void execute(NodeData parentNode) throws Exception
++ {
++ cwdm.getItemData(parentNode, qpe, ItemType.PROPERTY);
++ }
++ };
++ writeAction = new Action(cwdmNode1)
++ {
++ public void execute(NodeData parentNode) throws Exception
++ {
++ PlainChangesLog chlog = new PlainChangesLogImpl();
++ cwdm.getItemData(parentNode, qpe, ItemType.PROPERTY);
++ chlog.add(ItemState.createUpdatedState(new PersistedPropertyData("property-by-path"
++ + parentNode.getIdentifier(), QPath.makeChildPath(parentNode.getQPath(), qpe), parentNode
++ .getIdentifier(), 2, PropertyType.STRING, false, Arrays
++ .asList((ValueData)new ByteArrayPersistedValueData(0, "some new data".getBytes("UTF-8"))))));
++ cwdm.save(chlog);
++ }
++ };
++ parentNode = new PersistedNodeData("parent-id9", QPath.makeChildPath(Constants.ROOT_PATH, new InternalQName(null, "parent-node9")), Constants.ROOT_UUID, 1, 0,
++ Constants.NT_UNSTRUCTURED, new InternalQName[0], null);
++ executeConcurrentReadNWrite(con, readAction, writeAction, Mode.READ_FIRST, parentNode);
++ assertNotNull(cwdmNode1.getItemData(parentNode, qpe, ItemType.PROPERTY));
++ assertEquals(2, cwdmNode1.getItemData(parentNode, qpe, ItemType.PROPERTY).getPersistedVersion());
++ assertNotNull(cwdmNode2.getItemData(parentNode, qpe, ItemType.PROPERTY));
++ assertEquals(2, cwdmNode2.getItemData(parentNode, qpe, ItemType.PROPERTY).getPersistedVersion());
++ parentNode = new PersistedNodeData("parent-id10", QPath.makeChildPath(Constants.ROOT_PATH, new InternalQName(null, "parent-node10")), Constants.ROOT_UUID, 1, 0,
++ Constants.NT_UNSTRUCTURED, new InternalQName[0], null);
++ executeConcurrentReadNWrite(con, readAction, writeAction, Mode.WRITE_FIRST, parentNode);
++ assertNotNull(cwdmNode1.getItemData(parentNode, qpe, ItemType.PROPERTY));
++ assertEquals(2, cwdmNode1.getItemData(parentNode, qpe, ItemType.PROPERTY).getPersistedVersion());
++ assertNotNull(cwdmNode2.getItemData(parentNode, qpe, ItemType.PROPERTY));
++ assertEquals(2, cwdmNode2.getItemData(parentNode, qpe, ItemType.PROPERTY).getPersistedVersion());
++ }
++ finally
++ {
++ if (cache1 != null)
++ {
++ try
++ {
++ cache1.cache.stop();
++ }
++ catch (Exception e)
++ {
++ // ignore me
++ }
++ }
++ if (cache2 != null)
++ {
++ try
++ {
++ cache2.cache.stop();
++ }
++ catch (Exception e)
++ {
++ // ignore me
++ }
++ }
++ }
++ }
++
++ /**
++ * @param con
++ * @param cwdm
++ * @param mode
++ * @param idNode
++ * @throws InterruptedException
++ */
++ private void executeConcurrentReadNWrite(final MyWorkspaceStorageConnection con, final Action readAction,
++ final Action writeAction, final Mode mode, final NodeData parentNode) throws InterruptedException
++ {
++ final CountDownLatch goSignal = con.initCountDownLatch();
++ con.setParentNode(parentNode);
++ final AtomicReference<Exception> ex = new AtomicReference<Exception>();
++ final CountDownLatch startSignal = new CountDownLatch(1);
++ final CountDownLatch doneSignal = new CountDownLatch(2);
++ Thread writer = new Thread()
++ {
++ public void run()
++ {
++ try
++ {
++ startSignal.await();
++ con.wait.set(mode != Mode.WRITE_FIRST);
++ writeAction.execute(parentNode);
++ }
++ catch (Exception e)
++ {
++ e.printStackTrace();
++ ex.set(e);
++ }
++ finally
++ {
++ if (mode == Mode.WRITE_FIRST) goSignal.countDown();
++ doneSignal.countDown();
++ }
++ }
++ };
++ writer.start();
++ Thread reader = new Thread()
++ {
++ public void run()
++ {
++ try
++ {
++ startSignal.await();
++ con.wait.set(mode != Mode.READ_FIRST);
++ readAction.execute(parentNode);
++ }
++ catch (Exception e)
++ {
++ e.printStackTrace();
++ ex.set(e);
++ }
++ finally
++ {
++ if (mode == Mode.READ_FIRST) goSignal.countDown();
++ doneSignal.countDown();
++ }
++ }
++ };
++ reader.start();
++ startSignal.countDown();
++ doneSignal.await();
++ assertNull(ex.get());
++ }
++
++ private abstract class Action
++ {
++
++ protected final CacheableWorkspaceDataManager cwdm;
++ public Action(CacheableWorkspaceDataManager cwdm)
++ {
++ this.cwdm = cwdm;
++ }
++ protected abstract void execute(NodeData parentNode) throws Exception;
++ }
++ private static enum Mode
++ {
++ READ_FIRST, WRITE_FIRST;
++ }
++ private static class MyWorkspaceStorageConnection implements WorkspaceStorageConnection
++ {
++ public ThreadLocal<Boolean> wait = new ThreadLocal<Boolean>();
++ private NodeData parentNode;
++ private CountDownLatch goSignal;
++
++ public CountDownLatch initCountDownLatch()
++ {
++ return this.goSignal = new CountDownLatch(1);
++ }
++
++ public void setParentNode(NodeData parentNode)
++ {
++ this.parentNode = parentNode;
++ }
++
++ public void add(NodeData data) throws RepositoryException, UnsupportedOperationException,
++ InvalidItemStateException, IllegalStateException
++ {
++ }
++
++ public void add(PropertyData data) throws RepositoryException, UnsupportedOperationException,
++ InvalidItemStateException, IllegalStateException
++ {
++ }
++
++ public void close() throws IllegalStateException, RepositoryException
++ {
++ }
++
++ public void commit() throws IllegalStateException, RepositoryException
++ {
++ if (wait.get() != null && wait.get())
++ {
++ try
++ {
++ goSignal.await();
++ }
++ catch (InterruptedException e)
++ {
++ Thread.currentThread().interrupt();
++ }
++ }
++ }
++
++ public void delete(NodeData data) throws RepositoryException, UnsupportedOperationException,
++ InvalidItemStateException, IllegalStateException
++ {
++ }
++
++ public void delete(PropertyData data) throws RepositoryException, UnsupportedOperationException,
++ InvalidItemStateException, IllegalStateException
++ {
++ }
++
++ public int getChildNodesCount(NodeData parent) throws RepositoryException
++ {
++ return -1;
++ }
++
++ public List<NodeData> getChildNodesData(NodeData parent) throws RepositoryException, IllegalStateException
++ {
++ if (wait.get() != null && wait.get())
++ {
++ try
++ {
++ goSignal.await();
++ }
++ catch (InterruptedException e)
++ {
++ Thread.currentThread().interrupt();
++ }
++ }
++ List<NodeData> children = new ArrayList<NodeData>();
++ children.add(new PersistedNodeData("id-node2" + parentNode.getIdentifier(), QPath.makeChildPath(parent.getQPath(), new InternalQName(null, "node2")), parent.getIdentifier(), 1, 0,
++ Constants.NT_UNSTRUCTURED, new InternalQName[0], null));
++ return children;
++ }
++
++ public List<PropertyData> getChildPropertiesData(NodeData parent) throws RepositoryException,
++ IllegalStateException
++ {
++ if (wait.get() != null && wait.get())
++ {
++ try
++ {
++ goSignal.await();
++ }
++ catch (InterruptedException e)
++ {
++ Thread.currentThread().interrupt();
++ }
++ }
++ List<PropertyData> children = new ArrayList<PropertyData>();
++ try
++ {
++ children.add(new PersistedPropertyData("id-property2" + parentNode.getIdentifier(), QPath.makeChildPath(
++ parentNode.getQPath(), new InternalQName(null, "property2")), parentNode.getIdentifier(), 0,
++ PropertyType.STRING, false, Arrays.asList((ValueData)new ByteArrayPersistedValueData(0, "some data".getBytes("UTF-8")))));
++ }
++ catch (UnsupportedEncodingException e)
++ {
++ e.printStackTrace();
++ }
++ return children;
++ }
++
++ /**
++ * {@inheritDoc}
++ */
++ public ItemData getItemData(NodeData parentData, QPathEntry name) throws RepositoryException,
++ IllegalStateException
++ {
++ return getItemData(parentData, name, ItemType.UNKNOWN);
++ }
++
++ public ItemData getItemData(NodeData parentData, QPathEntry name, ItemType itemType) throws RepositoryException,
++ IllegalStateException
++ {
++ if (wait.get() != null && wait.get())
++ {
++ try
++ {
++ goSignal.await();
++ }
++ catch (InterruptedException e)
++ {
++ Thread.currentThread().interrupt();
++ }
++ }
++ if (itemType == ItemType.NODE)
++ {
++ return new PersistedNodeData("my-node" + parentNode.getIdentifier(), QPath.makeChildPath(parentNode.getQPath(), name), Constants.ROOT_UUID, 1, 1,
++ Constants.NT_UNSTRUCTURED, new InternalQName[0], null);
++ }
++ try
++ {
++ return new PersistedPropertyData("property-by-path"
++ + parentNode.getIdentifier(), QPath.makeChildPath(parentNode.getQPath(), name), parentNode
++ .getIdentifier(), 1, PropertyType.STRING, false, Arrays
++ .asList((ValueData)new ByteArrayPersistedValueData(0, "some new data".getBytes("UTF-8"))));
++ }
++ catch (UnsupportedEncodingException e)
++ {
++ e.printStackTrace();
++ }
++ return null;
++ }
++
++ public ItemData getItemData(String identifier) throws RepositoryException, IllegalStateException
++ {
++ if (wait.get() != null && wait.get())
++ {
++ try
++ {
++ goSignal.await();
++ }
++ catch (InterruptedException e)
++ {
++ Thread.currentThread().interrupt();
++ }
++ }
++ return parentNode;
++ }
++
++ public List<PropertyData> getReferencesData(String nodeIdentifier) throws RepositoryException,
++ IllegalStateException, UnsupportedOperationException
++ {
++ if (wait.get() != null && wait.get())
++ {
++ try
++ {
++ goSignal.await();
++ }
++ catch (InterruptedException e)
++ {
++ Thread.currentThread().interrupt();
++ }
++ }
++ List<PropertyData> children = new ArrayList<PropertyData>();
++ try
++ {
++ children.add(new PersistedPropertyData("id-reference2" + parentNode.getIdentifier(), QPath.makeChildPath(
++ parentNode.getQPath(), new InternalQName(null, "reference2")), parentNode.getIdentifier(), 0,
++ PropertyType.REFERENCE, false, Arrays.asList((ValueData)new ByteArrayPersistedValueData(0, parentNode.getIdentifier().getBytes("UTF-8")))));
++ }
++ catch (UnsupportedEncodingException e)
++ {
++ e.printStackTrace();
++ }
++ return children;
++ }
++
++ public boolean isOpened()
++ {
++ return true;
++ }
++
++ public List<PropertyData> listChildPropertiesData(NodeData parent) throws RepositoryException,
++ IllegalStateException
++ {
++ return null;
++ }
++
++ public void rename(NodeData data) throws RepositoryException, UnsupportedOperationException,
++ InvalidItemStateException, IllegalStateException
++ {
++ }
++
++ public void rollback() throws IllegalStateException, RepositoryException
++ {
++ }
++
++ public void update(NodeData data) throws RepositoryException, UnsupportedOperationException,
++ InvalidItemStateException, IllegalStateException
++ {
++ }
++
++ public void update(PropertyData data) throws RepositoryException, UnsupportedOperationException,
++ InvalidItemStateException, IllegalStateException
++ {
++ }
++ };
++
++ private static class MyWorkspaceDataContainer extends WorkspaceDataContainerBase
++ {
++
++ private WorkspaceStorageConnection con;
++
++ public MyWorkspaceDataContainer(WorkspaceStorageConnection con)
++ {
++ this.con = con;
++ }
++
++ public boolean isCheckSNSNewConnection()
++ {
++ return false;
++ }
++
++ public boolean isSame(WorkspaceDataContainer another)
++ {
++ return false;
++ }
++
++ public WorkspaceStorageConnection openConnection() throws RepositoryException
++ {
++ return con;
++ }
++
++ public WorkspaceStorageConnection openConnection(boolean readOnly) throws RepositoryException
++ {
++ return con;
++ }
++
++ public WorkspaceStorageConnection reuseConnection(WorkspaceStorageConnection original) throws RepositoryException
++ {
++ return con;
++ }
++
++ public String getInfo()
++ {
++ return "MyWorkspaceDataContainer";
++ }
++
++ public String getName()
++ {
++ return "MyWorkspaceDataContainer";
++ }
++
++ public String getStorageVersion()
++ {
++ return "0";
++ }
++ };
++}
+\ No newline at end of file
+Index: exo.jcr.component.core/src/test/resources/conf/standalone/cluster/test-jbosscache-data-no-mux.xml
+===================================================================
+--- exo.jcr.component.core/src/test/resources/conf/standalone/cluster/test-jbosscache-data-no-mux.xml (revision 0)
++++ exo.jcr.component.core/src/test/resources/conf/standalone/cluster/test-jbosscache-data-no-mux.xml (revision 0)
+@@ -0,0 +1,24 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<jbosscache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:jboss:jbosscache-core:config:3.1">
++
++ <locking useLockStriping="false" concurrencyLevel="500" lockParentForChildInsertRemove="false"
++ lockAcquisitionTimeout="20000" />
++ <transaction syncRollbackPhase="true" syncCommitPhase="true" />
++
++ <clustering mode="replication" clusterName="${jbosscache-cluster-name}">
++ <stateRetrieval timeout="20000" fetchInMemoryState="false" />
++ <sync replTimeout="20000"/>
++ <jgroupsConfig configFile="udp.xml">
++ </jgroupsConfig>
++ </clustering>
++
++ <!-- Eviction configuration -->
++ <eviction wakeUpInterval="5000">
++ <default algorithmClass="org.jboss.cache.eviction.ExpirationAlgorithm"
++ actionPolicyClass="org.exoplatform.services.jcr.impl.dataflow.persistent.jbosscache.ParentNodeEvictionActionPolicy"
++ eventQueueSize="1000000">
++ <property name="maxNodes" value="1000000" />
++ <property name="warnNoExpirationKey" value="false" />
++ </default>
++ </eviction>
++</jbosscache>
+\ No newline at end of file
Index: exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/BufferedJBossCache.java
===================================================================
---- exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/BufferedJBossCache.java (revision 4235)
+--- exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/BufferedJBossCache.java (revision 4237)
+++ exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/BufferedJBossCache.java (working copy)
-@@ -471,6 +471,31 @@
+@@ -40,6 +40,7 @@
+ import java.util.Map;
+ import java.util.Set;
+
++import javax.transaction.Status;
+ import javax.transaction.TransactionManager;
+
+ /**
+@@ -64,6 +65,8 @@
+ private final boolean useExpiration;
+
+ private final long expirationTimeOut;
++
++ private final TransactionManager tm;
+
+ protected static final Log LOG =
+ ExoLogger.getLogger("org.exoplatform.services.jcr.impl.dataflow.persistent.jbosscache.BufferedJBossCache");
+@@ -71,6 +74,7 @@
+ public BufferedJBossCache(Cache<Serializable, Object> parentCache, boolean useExpiration, long expirationTimeOut)
+ {
+ super();
++ this.tm = ((CacheSPI<Serializable, Object>)parentCache).getTransactionManager();
+ this.parentCache = parentCache;
+ this.useExpiration = useExpiration;
+ this.expirationTimeOut = expirationTimeOut;
+@@ -109,7 +113,53 @@
+ //log.info("After=" + changesContainer.toString());
+ for (ChangesContainer cacheChange : containers)
+ {
+- cacheChange.apply();
++ boolean isTxCreated = false;
++ try
++ {
++ if (cacheChange.isTxRequired() && tm != null && tm.getStatus() == Status.STATUS_NO_TRANSACTION)
++ {
++ // No tx exists so we create a new tx
++ if (LOG.isTraceEnabled()) LOG.trace("No Tx is active we then create a new tx");
++ tm.begin();
++ isTxCreated = true;
++ }
++ }
++ catch (Exception e)
++ {
++ LOG.warn("Could not create a new tx", e);
++ }
++ try
++ {
++ cacheChange.apply();
++ }
++ catch (RuntimeException e)
++ {
++ if (isTxCreated)
++ {
++ try
++ {
++ if (LOG.isTraceEnabled()) LOG.trace("An error occurs the tx will be rollbacked");
++ tm.rollback();
++ }
++ catch (Exception e1)
++ {
++ LOG.warn("Could not rollback the tx", e1);
++ }
++ }
++ throw e;
++ }
++ if (isTxCreated)
++ {
++ try
++ {
++ if (LOG.isTraceEnabled()) LOG.trace("The tx will be committed");
++ tm.commit();
++ }
++ catch (Exception e)
++ {
++ LOG.warn("Could not commit the tx", e);
++ }
++ }
+ }
+ }
+ finally
+@@ -118,6 +168,7 @@
+ changesContainer = null;
+ }
+ }
++
+
+ /**
+ * Tries to get buffer and if it is null throws an exception otherwise returns buffer.
+@@ -471,6 +522,31 @@
return parentCache.get(fqn, key);
}
@@ -34,10 +806,22 @@
public Object putInBuffer(Fqn fqn, Serializable key, Object value)
{
CompressedChangesBuffer changesContainer = getChangesBufferSafe();
-@@ -789,6 +814,42 @@
+@@ -758,6 +834,11 @@
+ }
+
+ public abstract void apply();
++
++ public boolean isTxRequired()
++ {
++ return false;
++ }
}
/**
+@@ -789,6 +870,48 @@
+ }
+
+ /**
+ * PutIfAbsent container.
+ */
+ public static class PutIfAbsentKeyValueContainer extends ChangesContainer
@@ -71,15 +855,47 @@
+ setCacheLocalMode();
+ cache.put(fqn, key, value);
+ }
++
++ @Override
++ public boolean isTxRequired()
++ {
++ return true;
++ }
+ }
+
+ /**
* Put container.
*/
public static class PutKeyValueContainer extends ChangesContainer
+@@ -871,6 +994,12 @@
+ + existingObject.getClass().getName());
+ }
+ }
++
++ @Override
++ public boolean isTxRequired()
++ {
++ return true;
++ }
+ }
+
+ /**
+@@ -913,6 +1042,12 @@
+ cache.put(fqn, key, newSet);
+ }
+ }
++
++ @Override
++ public boolean isTxRequired()
++ {
++ return false;
++ }
+ }
+
+ /**
Index: exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/JBossCacheWorkspaceStorageCache.java
===================================================================
---- exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/JBossCacheWorkspaceStorageCache.java (revision 4235)
+--- exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/JBossCacheWorkspaceStorageCache.java (revision 4237)
+++ exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/JBossCacheWorkspaceStorageCache.java (working copy)
@@ -60,6 +60,7 @@
15 years
exo-jcr SVN: r4237 - jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr/backup.
by do-not-reply@jboss.org
Author: tolusha
Date: 2011-04-14 10:09:41 -0400 (Thu, 14 Apr 2011)
New Revision: 4237
Modified:
jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr/backup/use-external-backup-tool.xml
Log:
EXOJCR-1301: [DOC] Allow to use external backup tools in a secure manner
Modified: jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr/backup/use-external-backup-tool.xml
===================================================================
--- jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr/backup/use-external-backup-tool.xml 2011-04-14 11:04:28 UTC (rev 4236)
+++ jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr/backup/use-external-backup-tool.xml 2011-04-14 14:09:41 UTC (rev 4237)
@@ -31,6 +31,9 @@
<imagedata fileref="images/repository-suspend-controller-suspended.png" />
</imageobject>
</mediaobject>
+
+ <para>The result "undefined" means not all components successfully
+ suspended, check console to see stacktraces.</para>
</section>
<section>
@@ -57,8 +60,8 @@
<section>
<title>Repository resuming</title>
- <para>Once backup is done need to invoke resume() operation to resume
- repository. The returned result will be "online" </para>
+ <para>Once backup is done need to invoke resume() operation to switch
+ repository back to online. The returned result will be "online".</para>
<mediaobject>
<imageobject>
15 years
exo-jcr SVN: r4236 - jcr/branches/1.12.x/patch/1.12.9-GA/JCR-1604.
by do-not-reply@jboss.org
Author: tolusha
Date: 2011-04-14 07:04:28 -0400 (Thu, 14 Apr 2011)
New Revision: 4236
Modified:
jcr/branches/1.12.x/patch/1.12.9-GA/JCR-1604/JCR-1604.patch
Log:
JCR-1604: patch updateded
Modified: jcr/branches/1.12.x/patch/1.12.9-GA/JCR-1604/JCR-1604.patch
===================================================================
--- jcr/branches/1.12.x/patch/1.12.9-GA/JCR-1604/JCR-1604.patch 2011-04-13 15:51:44 UTC (rev 4235)
+++ jcr/branches/1.12.x/patch/1.12.9-GA/JCR-1604/JCR-1604.patch 2011-04-14 11:04:28 UTC (rev 4236)
@@ -1,8 +1,8 @@
-Index: exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/BufferedJBossCache.java
-===================================================================
---- exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/BufferedJBossCache.java (revision 4234)
-+++ exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/BufferedJBossCache.java (working copy)
-@@ -471,6 +471,31 @@
+Index: exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/BufferedJBossCache.java
+===================================================================
+--- exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/BufferedJBossCache.java (revision 4235)
++++ exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/BufferedJBossCache.java (working copy)
+@@ -471,6 +471,31 @@
return parentCache.get(fqn, key);
}
@@ -34,7 +34,7 @@
public Object putInBuffer(Fqn fqn, Serializable key, Object value)
{
CompressedChangesBuffer changesContainer = getChangesBufferSafe();
-@@ -789,6 +814,42 @@
+@@ -789,6 +814,42 @@
}
/**
@@ -77,11 +77,11 @@
* Put container.
*/
public static class PutKeyValueContainer extends ChangesContainer
-Index: exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/JBossCacheWorkspaceStorageCache.java
-===================================================================
---- exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/JBossCacheWorkspaceStorageCache.java (revision 4234)
-+++ exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/JBossCacheWorkspaceStorageCache.java (working copy)
-@@ -60,6 +60,7 @@
+Index: exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/JBossCacheWorkspaceStorageCache.java
+===================================================================
+--- exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/JBossCacheWorkspaceStorageCache.java (revision 4235)
++++ exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/JBossCacheWorkspaceStorageCache.java (working copy)
+@@ -60,6 +60,7 @@
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
@@ -89,7 +89,7 @@
import javax.transaction.TransactionManager;
/**
-@@ -417,7 +418,7 @@
+@@ -417,7 +418,7 @@
cache.setLocal(false);
if (!inTransaction)
{
@@ -98,7 +98,7 @@
}
}
}
-@@ -556,23 +557,20 @@
+@@ -556,23 +557,20 @@
cache.setLocal(true);
@@ -124,7 +124,7 @@
}
}
}
-@@ -592,8 +590,6 @@
+@@ -592,8 +590,6 @@
}
cache.setLocal(true);
@@ -133,7 +133,7 @@
if (childs.size() > 0)
{
-@@ -603,12 +599,13 @@
+@@ -603,12 +599,13 @@
putNode(child, ModifyChildOption.NOT_MODIFY);
set.add(child.getIdentifier());
}
@@ -149,7 +149,7 @@
}
}
finally
-@@ -616,7 +613,7 @@
+@@ -616,7 +613,7 @@
cache.setLocal(false);
if (!inTransaction)
{
@@ -158,7 +158,7 @@
}
}
}
-@@ -634,8 +631,6 @@
+@@ -634,8 +631,6 @@
cache.beginTransaction();
}
cache.setLocal(true);
@@ -167,7 +167,7 @@
if (childs.size() > 0)
{
// add all new
-@@ -645,7 +640,7 @@
+@@ -645,7 +640,7 @@
putProperty(child, ModifyChildOption.NOT_MODIFY);
set.add(child.getIdentifier());
}
@@ -176,7 +176,7 @@
}
else
-@@ -658,7 +653,7 @@
+@@ -658,7 +653,7 @@
cache.setLocal(false);
if (!inTransaction)
{
@@ -185,7 +185,7 @@
}
}
}
-@@ -669,17 +664,6 @@
+@@ -669,17 +664,6 @@
public void addChildPropertiesList(NodeData parent, List<PropertyData> childProperties)
{
// TODO not implemented, will force read from DB
@@ -203,7 +203,7 @@
}
/**
-@@ -945,18 +929,19 @@
+@@ -945,18 +929,19 @@
if (node.getParentIdentifier() != null)
{
// add in CHILD_NODES
@@ -229,7 +229,7 @@
}
protected ItemData putNodeInBufferedCache(NodeData node, ModifyChildOption modifyListsOfChild)
-@@ -965,14 +950,13 @@
+@@ -965,14 +950,13 @@
if (node.getParentIdentifier() != null)
{
// add in CHILD_NODES
@@ -248,7 +248,7 @@
}
}
// add in ITEMS
-@@ -988,9 +972,8 @@
+@@ -988,9 +972,8 @@
protected PropertyData putProperty(PropertyData prop, ModifyChildOption modifyListsOfChild)
{
// add in CHILD_PROPS
@@ -260,7 +260,7 @@
if (modifyListsOfChild != ModifyChildOption.NOT_MODIFY)
{
-@@ -1025,7 +1008,8 @@
+@@ -1025,7 +1008,8 @@
}
// add in ITEMS
@@ -270,7 +270,7 @@
}
protected void removeItem(ItemData item)
-@@ -1041,8 +1025,8 @@
+@@ -1041,8 +1025,8 @@
.getQPath().getEntries().length - 1]));
// remove from CHILD_NODES_LIST of parent
@@ -281,7 +281,7 @@
// remove from CHILD_NODES as parent
cache.removeNode(makeChildListFqn(childNodes, item.getIdentifier()));
-@@ -1066,8 +1050,8 @@
+@@ -1066,8 +1050,8 @@
.getQPath().getEntries().length - 1]));
// remove from CHILD_PROPS_LIST
@@ -292,7 +292,7 @@
}
// remove from ITEMS
cache.removeNode(makeItemFqn(item.getIdentifier()));
-@@ -1096,10 +1080,10 @@
+@@ -1096,10 +1080,10 @@
}
/**
@@ -307,7 +307,7 @@
* @param node NodeData
* @param prevNode NodeData
*/
-@@ -1205,9 +1189,9 @@
+@@ -1205,9 +1189,9 @@
NodeData prevNode = (NodeData)data;
TransientNodeData newNode =
@@ -320,7 +320,7 @@
// update this node
cache.put(makeItemFqn(newNode.getIdentifier()), ITEM_DATA, newNode);
}
-@@ -1225,8 +1209,8 @@
+@@ -1225,8 +1209,8 @@
}
TransientPropertyData newProp =
@@ -331,7 +331,7 @@
cache.put(makeItemFqn(newProp.getIdentifier()), ITEM_DATA, newProp);
}
}
-@@ -1260,8 +1244,8 @@
+@@ -1260,8 +1244,8 @@
QPath
.makeChildPath(rootPath, prevProp.getQPath().getEntries()[prevProp.getQPath().getEntries().length - 1]);
TransientPropertyData newProp =
@@ -342,7 +342,7 @@
cache.put(makeItemFqn(newProp.getIdentifier()), ITEM_DATA, newProp);
}
-@@ -1274,9 +1258,9 @@
+@@ -1274,9 +1258,9 @@
QPath
.makeChildPath(rootPath, prevNode.getQPath().getEntries()[prevNode.getQPath().getEntries().length - 1]);
TransientNodeData newNode =
@@ -355,7 +355,7 @@
// update this node
cache.put(makeItemFqn(newNode.getIdentifier()), ITEM_DATA, newNode);
// update childs recursive
-@@ -1292,22 +1276,22 @@
+@@ -1292,22 +1276,22 @@
*/
protected void updateChildsACL(final String parentId, final AccessControlList acl)
{
@@ -383,7 +383,7 @@
// update this node
cache.put(makeItemFqn(newNode.getIdentifier()), ITEM_DATA, newNode);
// update childs recursive
-@@ -1347,4 +1331,44 @@
+@@ -1347,4 +1331,44 @@
NOT_MODIFY, MODIFY, FORCE_MODIFY
}
15 years
exo-jcr SVN: r4235 - jcr/branches/1.12.x/patch/1.12.9-GA/JCR-1604.
by do-not-reply@jboss.org
Author: sergiykarpenko
Date: 2011-04-13 11:51:44 -0400 (Wed, 13 Apr 2011)
New Revision: 4235
Modified:
jcr/branches/1.12.x/patch/1.12.9-GA/JCR-1604/JCR-1604.patch
Log:
JCR-1604: new patch proposed
Modified: jcr/branches/1.12.x/patch/1.12.9-GA/JCR-1604/JCR-1604.patch
===================================================================
--- jcr/branches/1.12.x/patch/1.12.9-GA/JCR-1604/JCR-1604.patch 2011-04-13 13:47:01 UTC (rev 4234)
+++ jcr/branches/1.12.x/patch/1.12.9-GA/JCR-1604/JCR-1604.patch 2011-04-13 15:51:44 UTC (rev 4235)
@@ -1,6 +1,85 @@
+Index: exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/BufferedJBossCache.java
+===================================================================
+--- exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/BufferedJBossCache.java (revision 4234)
++++ exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/BufferedJBossCache.java (working copy)
+@@ -471,6 +471,31 @@
+ return parentCache.get(fqn, key);
+ }
+
++ /**
++ * in case putIfAbsent is set to <code>true</code> this method will call cache.putIfAbsent(Fqn fqn, Serializable key, Object value)
++ * otherwise it will call cache.put(Fqn fqn, Serializable key, Object value)
++ */
++ protected Object put(Fqn fqn, Serializable key, Object value, boolean putIfAbsent)
++ {
++ if (putIfAbsent)
++ {
++ putIfAbsent(fqn, key, value);
++ return null;
++ }
++ return put(fqn, key, value);
++ }
++
++ /**
++ * This method will create and add a ChangesContainer that will put the value only if no value has been added
++ */
++ protected Object putIfAbsent(Fqn fqn, Serializable key, Object value)
++ {
++ CompressedChangesBuffer changesContainer = getChangesBufferSafe();
++ changesContainer.add(new PutIfAbsentKeyValueContainer(fqn, key, value, parentCache, changesContainer
++ .getHistoryIndex(), local.get(), useExpiration, expirationTimeOut));
++ return null;
++ }
++
+ public Object putInBuffer(Fqn fqn, Serializable key, Object value)
+ {
+ CompressedChangesBuffer changesContainer = getChangesBufferSafe();
+@@ -789,6 +814,42 @@
+ }
+
+ /**
++ * PutIfAbsent container.
++ */
++ public static class PutIfAbsentKeyValueContainer extends ChangesContainer
++ {
++ private final Serializable key;
++
++ private final Object value;
++
++ public PutIfAbsentKeyValueContainer(Fqn fqn, Serializable key, Object value, Cache<Serializable, Object> cache,
++ int historicalIndex, boolean local, boolean useExpiration, long timeOut)
++ {
++ super(fqn, ChangesType.PUT_KEY, cache, historicalIndex, local, useExpiration, timeOut);
++ this.key = key;
++ this.value = value;
++ }
++
++ @Override
++ public void apply()
++ {
++ cache.getInvocationContext().getOptionOverrides().setForceWriteLock(true);
++ if (cache.get(fqn, key) != null)
++ {
++ // skip
++ return;
++ }
++ if (useExpiration)
++ {
++ putExpiration(fqn);
++ }
++
++ setCacheLocalMode();
++ cache.put(fqn, key, value);
++ }
++ }
++
++ /**
+ * Put container.
+ */
+ public static class PutKeyValueContainer extends ChangesContainer
Index: exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/JBossCacheWorkspaceStorageCache.java
===================================================================
---- exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/JBossCacheWorkspaceStorageCache.java (revision 4199)
+--- exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/JBossCacheWorkspaceStorageCache.java (revision 4234)
+++ exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/JBossCacheWorkspaceStorageCache.java (working copy)
@@ -60,6 +60,7 @@
@@ -19,7 +98,24 @@
}
}
}
-@@ -572,7 +573,7 @@
+@@ -556,23 +557,20 @@
+
+ cache.setLocal(true);
+
+- // remove previous all
+- cache.removeNode(makeRefFqn(identifier));
+-
+ Set<Object> set = new HashSet<Object>();
+ for (PropertyData prop : refProperties)
+ {
+ putProperty(prop, ModifyChildOption.NOT_MODIFY);
+ set.add(prop.getIdentifier());
+ }
+- cache.put(makeRefFqn(identifier), ITEM_LIST, set);
++ cache.putIfAbsent(makeRefFqn(identifier), ITEM_LIST, set);
+ }
+ finally
+ {
cache.setLocal(false);
if (!inTransaction)
{
@@ -28,7 +124,32 @@
}
}
}
-@@ -616,7 +617,7 @@
+@@ -592,8 +590,6 @@
+ }
+
+ cache.setLocal(true);
+- // remove previous all (to be sure about consistency)
+- cache.removeNode(makeChildListFqn(childNodesList, parent.getIdentifier()));
+
+ if (childs.size() > 0)
+ {
+@@ -603,12 +599,13 @@
+ putNode(child, ModifyChildOption.NOT_MODIFY);
+ set.add(child.getIdentifier());
+ }
+- cache.put(makeChildListFqn(childNodesList, parent.getIdentifier()), ITEM_LIST, set);
++ cache.putIfAbsent(makeChildListFqn(childNodesList, parent.getIdentifier()), ITEM_LIST, set);
+ }
+ else
+ {
+ // cache fact of empty childs list
+- cache.put(makeChildListFqn(childNodesList, parent.getIdentifier()), ITEM_LIST, new HashSet<Object>());
++ cache.putIfAbsent(makeChildListFqn(childNodesList, parent.getIdentifier()), ITEM_LIST,
++ new HashSet<Object>());
+ }
+ }
+ finally
+@@ -616,7 +613,7 @@
cache.setLocal(false);
if (!inTransaction)
{
@@ -37,7 +158,25 @@
}
}
}
-@@ -658,7 +659,7 @@
+@@ -634,8 +631,6 @@
+ cache.beginTransaction();
+ }
+ cache.setLocal(true);
+- // remove previous all (to be sure about consistency)
+- cache.removeNode(makeChildListFqn(childPropsList, parent.getIdentifier()));
+ if (childs.size() > 0)
+ {
+ // add all new
+@@ -645,7 +640,7 @@
+ putProperty(child, ModifyChildOption.NOT_MODIFY);
+ set.add(child.getIdentifier());
+ }
+- cache.put(makeChildListFqn(childPropsList, parent.getIdentifier()), ITEM_LIST, set);
++ cache.putIfAbsent(makeChildListFqn(childPropsList, parent.getIdentifier()), ITEM_LIST, set);
+
+ }
+ else
+@@ -658,7 +653,7 @@
cache.setLocal(false);
if (!inTransaction)
{
@@ -46,7 +185,205 @@
}
}
}
-@@ -1347,4 +1348,44 @@
+@@ -669,17 +664,6 @@
+ public void addChildPropertiesList(NodeData parent, List<PropertyData> childProperties)
+ {
+ // TODO not implemented, will force read from DB
+- // try
+- // {
+- // cache.beginTransaction();
+- // cache.setLocal(true);
+- //
+- // }
+- // finally
+- // {
+- // cache.setLocal(false);
+- // cache.commitTransaction();
+- // }
+ }
+
+ /**
+@@ -945,18 +929,19 @@
+ if (node.getParentIdentifier() != null)
+ {
+ // add in CHILD_NODES
+- cache.put(
+- makeChildFqn(childNodes, node.getParentIdentifier(), node.getQPath().getEntries()[node.getQPath()
+- .getEntries().length - 1]), ITEM_ID, node.getIdentifier());
++ cache.put(makeChildFqn(childNodes, node.getParentIdentifier(), node.getQPath().getEntries()[node.getQPath()
++ .getEntries().length - 1]), ITEM_ID, node.getIdentifier(),
++ modifyListsOfChild == ModifyChildOption.NOT_MODIFY);
+
+ if (modifyListsOfChild != ModifyChildOption.NOT_MODIFY)
+ {
+- cache.addToList(makeChildListFqn(childNodesList, node.getParentIdentifier()), ITEM_LIST,
+- node.getIdentifier(), modifyListsOfChild == ModifyChildOption.FORCE_MODIFY);
++ cache.addToList(makeChildListFqn(childNodesList, node.getParentIdentifier()), ITEM_LIST, node
++ .getIdentifier(), modifyListsOfChild == ModifyChildOption.FORCE_MODIFY);
+ }
+ }
+ // add in ITEMS
+- return (ItemData)cache.put(makeItemFqn(node.getIdentifier()), ITEM_DATA, node);
++ return (ItemData)cache.put(makeItemFqn(node.getIdentifier()), ITEM_DATA, node,
++ modifyListsOfChild == ModifyChildOption.NOT_MODIFY);
+ }
+
+ protected ItemData putNodeInBufferedCache(NodeData node, ModifyChildOption modifyListsOfChild)
+@@ -965,14 +950,13 @@
+ if (node.getParentIdentifier() != null)
+ {
+ // add in CHILD_NODES
+- cache.put(
+- makeChildFqn(childNodes, node.getParentIdentifier(), node.getQPath().getEntries()[node.getQPath()
+- .getEntries().length - 1]), ITEM_ID, node.getIdentifier());
++ cache.put(makeChildFqn(childNodes, node.getParentIdentifier(), node.getQPath().getEntries()[node.getQPath()
++ .getEntries().length - 1]), ITEM_ID, node.getIdentifier());
+
+ if (modifyListsOfChild != ModifyChildOption.NOT_MODIFY)
+ {
+- cache.addToList(makeChildListFqn(childNodesList, node.getParentIdentifier()), ITEM_LIST,
+- node.getIdentifier(), modifyListsOfChild == ModifyChildOption.FORCE_MODIFY);
++ cache.addToList(makeChildListFqn(childNodesList, node.getParentIdentifier()), ITEM_LIST, node
++ .getIdentifier(), modifyListsOfChild == ModifyChildOption.FORCE_MODIFY);
+ }
+ }
+ // add in ITEMS
+@@ -988,9 +972,8 @@
+ protected PropertyData putProperty(PropertyData prop, ModifyChildOption modifyListsOfChild)
+ {
+ // add in CHILD_PROPS
+- cache.put(
+- makeChildFqn(childProps, prop.getParentIdentifier(),
+- prop.getQPath().getEntries()[prop.getQPath().getEntries().length - 1]), ITEM_ID, prop.getIdentifier());
++ cache.put(makeChildFqn(childProps, prop.getParentIdentifier(), prop.getQPath().getEntries()[prop.getQPath()
++ .getEntries().length - 1]), ITEM_ID, prop.getIdentifier(), modifyListsOfChild == ModifyChildOption.NOT_MODIFY);
+
+ if (modifyListsOfChild != ModifyChildOption.NOT_MODIFY)
+ {
+@@ -1025,7 +1008,8 @@
+ }
+
+ // add in ITEMS
+- return (PropertyData)cache.put(makeItemFqn(prop.getIdentifier()), ITEM_DATA, prop);
++ return (PropertyData)cache.put(makeItemFqn(prop.getIdentifier()), ITEM_DATA, prop,
++ modifyListsOfChild == ModifyChildOption.NOT_MODIFY);
+ }
+
+ protected void removeItem(ItemData item)
+@@ -1041,8 +1025,8 @@
+ .getQPath().getEntries().length - 1]));
+
+ // remove from CHILD_NODES_LIST of parent
+- cache.removeFromList(makeChildListFqn(childNodesList, item.getParentIdentifier()), ITEM_LIST,
+- item.getIdentifier());
++ cache.removeFromList(makeChildListFqn(childNodesList, item.getParentIdentifier()), ITEM_LIST, item
++ .getIdentifier());
+
+ // remove from CHILD_NODES as parent
+ cache.removeNode(makeChildListFqn(childNodes, item.getIdentifier()));
+@@ -1066,8 +1050,8 @@
+ .getQPath().getEntries().length - 1]));
+
+ // remove from CHILD_PROPS_LIST
+- cache.removeFromList(makeChildListFqn(childPropsList, item.getParentIdentifier()), ITEM_LIST,
+- item.getIdentifier());
++ cache.removeFromList(makeChildListFqn(childPropsList, item.getParentIdentifier()), ITEM_LIST, item
++ .getIdentifier());
+ }
+ // remove from ITEMS
+ cache.removeNode(makeItemFqn(item.getIdentifier()));
+@@ -1096,10 +1080,10 @@
+ }
+
+ /**
+- * Update Node hierachy in case of same-name siblings reorder.
+- * Assumes the new (updated) nodes already putted in the cache. Previous name of updated nodes will be calculated
+- * and that node will be deleted (if has same id as the new node). Childs paths will be updated to a new node path.
+- *
++ * Update Node hierarchy in case of same-name siblings reorder.
++ * Assumes the new (updated) nodes already put in the cache. Previous name of updated nodes will be calculated
++ * and that node will be deleted (if has same id as the new node). Children paths will be updated to a new node path. *
++ *
+ * @param node NodeData
+ * @param prevNode NodeData
+ */
+@@ -1205,9 +1189,9 @@
+ NodeData prevNode = (NodeData)data;
+
+ TransientNodeData newNode =
+- new TransientNodeData(newPath, prevNode.getIdentifier(), prevNode.getPersistedVersion(),
+- prevNode.getPrimaryTypeName(), prevNode.getMixinTypeNames(), prevNode.getOrderNumber(),
+- prevNode.getParentIdentifier(), inheritACL ? acl : prevNode.getACL()); // TODO check ACL
++ new TransientNodeData(newPath, prevNode.getIdentifier(), prevNode.getPersistedVersion(), prevNode
++ .getPrimaryTypeName(), prevNode.getMixinTypeNames(), prevNode.getOrderNumber(), prevNode
++ .getParentIdentifier(), inheritACL ? acl : prevNode.getACL()); // TODO check ACL
+ // update this node
+ cache.put(makeItemFqn(newNode.getIdentifier()), ITEM_DATA, newNode);
+ }
+@@ -1225,8 +1209,8 @@
+ }
+
+ TransientPropertyData newProp =
+- new TransientPropertyData(newPath, prevProp.getIdentifier(), prevProp.getPersistedVersion(),
+- prevProp.getType(), prevProp.getParentIdentifier(), prevProp.isMultiValued(), prevProp.getValues());
++ new TransientPropertyData(newPath, prevProp.getIdentifier(), prevProp.getPersistedVersion(), prevProp
++ .getType(), prevProp.getParentIdentifier(), prevProp.isMultiValued(), prevProp.getValues());
+ cache.put(makeItemFqn(newProp.getIdentifier()), ITEM_DATA, newProp);
+ }
+ }
+@@ -1260,8 +1244,8 @@
+ QPath
+ .makeChildPath(rootPath, prevProp.getQPath().getEntries()[prevProp.getQPath().getEntries().length - 1]);
+ TransientPropertyData newProp =
+- new TransientPropertyData(newPath, prevProp.getIdentifier(), prevProp.getPersistedVersion(),
+- prevProp.getType(), prevProp.getParentIdentifier(), prevProp.isMultiValued(), prevProp.getValues());
++ new TransientPropertyData(newPath, prevProp.getIdentifier(), prevProp.getPersistedVersion(), prevProp
++ .getType(), prevProp.getParentIdentifier(), prevProp.isMultiValued(), prevProp.getValues());
+ cache.put(makeItemFqn(newProp.getIdentifier()), ITEM_DATA, newProp);
+ }
+
+@@ -1274,9 +1258,9 @@
+ QPath
+ .makeChildPath(rootPath, prevNode.getQPath().getEntries()[prevNode.getQPath().getEntries().length - 1]);
+ TransientNodeData newNode =
+- new TransientNodeData(newPath, prevNode.getIdentifier(), prevNode.getPersistedVersion(),
+- prevNode.getPrimaryTypeName(), prevNode.getMixinTypeNames(), prevNode.getOrderNumber(),
+- prevNode.getParentIdentifier(), inheritACL ? acl : prevNode.getACL()); // TODO check ACL
++ new TransientNodeData(newPath, prevNode.getIdentifier(), prevNode.getPersistedVersion(), prevNode
++ .getPrimaryTypeName(), prevNode.getMixinTypeNames(), prevNode.getOrderNumber(), prevNode
++ .getParentIdentifier(), inheritACL ? acl : prevNode.getACL()); // TODO check ACL
+ // update this node
+ cache.put(makeItemFqn(newNode.getIdentifier()), ITEM_DATA, newNode);
+ // update childs recursive
+@@ -1292,22 +1276,22 @@
+ */
+ protected void updateChildsACL(final String parentId, final AccessControlList acl)
+ {
+- for (Iterator<NodeData> iter = new ChildNodesIterator<NodeData>(parentId); iter.hasNext();)
++ loop : for (Iterator<NodeData> iter = new ChildNodesIterator<NodeData>(parentId); iter.hasNext();)
+ {
+ NodeData prevNode = iter.next();
+- // is ACL changes on this node (i.e. ACL inheritance brokes)
++ // is ACL changes on this node (i.e. ACL inheritance broken)
+ for (InternalQName mixin : prevNode.getMixinTypeNames())
+ {
+ if (mixin.equals(Constants.EXO_PRIVILEGEABLE) || mixin.equals(Constants.EXO_OWNEABLE))
+ {
+- continue;
++ continue loop;
+ }
+ }
+ // recreate with new path for child Nodes only
+ TransientNodeData newNode =
+ new TransientNodeData(prevNode.getQPath(), prevNode.getIdentifier(), prevNode.getPersistedVersion(),
+- prevNode.getPrimaryTypeName(), prevNode.getMixinTypeNames(), prevNode.getOrderNumber(),
+- prevNode.getParentIdentifier(), acl);
++ prevNode.getPrimaryTypeName(), prevNode.getMixinTypeNames(), prevNode.getOrderNumber(), prevNode
++ .getParentIdentifier(), acl);
+ // update this node
+ cache.put(makeItemFqn(newNode.getIdentifier()), ITEM_DATA, newNode);
+ // update childs recursive
+@@ -1347,4 +1331,44 @@
NOT_MODIFY, MODIFY, FORCE_MODIFY
}
15 years
exo-jcr SVN: r4234 - in jcr/trunk/exo.jcr.component.core/src: main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache and 1 other directories.
by do-not-reply@jboss.org
Author: sergiykarpenko
Date: 2011-04-13 09:47:01 -0400 (Wed, 13 Apr 2011)
New Revision: 4234
Added:
jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/TestISPNCacheWorkspaceStorageCache.java
Modified:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/infinispan/BufferedISPNCache.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/infinispan/ISPNCacheWorkspaceStorageCache.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/BufferedJBossCache.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/JBossCacheWorkspaceStorageCache.java
jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/TestJBossCacheWorkspaceStorageCache.java
Log:
EXOJCR-1302: Avoid overwrite data in cache in multi-thread environment.
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/infinispan/BufferedISPNCache.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/infinispan/BufferedISPNCache.java 2011-04-13 12:55:17 UTC (rev 4233)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/infinispan/BufferedISPNCache.java 2011-04-13 13:47:01 UTC (rev 4234)
@@ -29,7 +29,6 @@
import org.infinispan.manager.CacheContainer;
import org.infinispan.util.concurrent.NotifyingFuture;
-import java.io.Serializable;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Collection;
@@ -49,12 +48,12 @@
*
*/
@SuppressWarnings("unchecked")
-public class BufferedISPNCache implements Cache<Serializable, Object>
+public class BufferedISPNCache implements Cache<CacheKey, Object>
{
/**
* Parent cache.
*/
- private final AdvancedCache<Serializable, Object> parentCache;
+ private final AdvancedCache<CacheKey, Object> parentCache;
private final ThreadLocal<CompressedISPNChangesBuffer> changesList = new ThreadLocal<CompressedISPNChangesBuffer>();
@@ -80,7 +79,7 @@
protected final ChangesType changesType;
- protected final AdvancedCache<Serializable, Object> cache;
+ protected final AdvancedCache<CacheKey, Object> cache;
protected final int historicalIndex;
@@ -88,7 +87,7 @@
private final Boolean allowLocalChanges;
- public ChangesContainer(CacheKey key, ChangesType changesType, AdvancedCache<Serializable, Object> cache,
+ public ChangesContainer(CacheKey key, ChangesType changesType, AdvancedCache<CacheKey, Object> cache,
int historicalIndex, boolean localMode, Boolean allowLocalChanges)
{
this.key = key;
@@ -170,7 +169,7 @@
{
private final Object value;
- public PutObjectContainer(CacheKey key, Object value, AdvancedCache<Serializable, Object> cache,
+ public PutObjectContainer(CacheKey key, Object value, AdvancedCache<CacheKey, Object> cache,
int historicalIndex, boolean local, Boolean allowLocalChanges)
{
super(key, ChangesType.PUT, cache, historicalIndex, local, allowLocalChanges);
@@ -185,8 +184,32 @@
cache.put(key, value);
}
}
+
/**
+ * Put object if absent container
+ */
+ public static class PutObjectIfAbsentContainer extends ChangesContainer
+ {
+ private final Object value;
+
+ public PutObjectIfAbsentContainer(CacheKey key, Object value, AdvancedCache<CacheKey, Object> cache,
+ int historicalIndex, boolean local, Boolean allowLocalChanges)
+ {
+ super(key, ChangesType.PUT, cache, historicalIndex, local, allowLocalChanges);
+
+ this.value = value;
+ }
+
+ @Override
+ public void apply()
+ {
+ setCacheLocalMode();
+ cache.putIfAbsent(key, value);
+ }
+ }
+
+ /**
* It tries to get Set by given key. If it is Set then adds new value and puts new set back. If
* null found, then new Set created (ordinary cache does).
*/
@@ -196,7 +219,7 @@
private final boolean forceModify;
- public AddToListContainer(CacheKey key, Object value, AdvancedCache<Serializable, Object> cache,
+ public AddToListContainer(CacheKey key, Object value, AdvancedCache<CacheKey, Object> cache,
boolean forceModify, int historicalIndex, boolean local, Boolean allowLocalChanges)
{
super(key, ChangesType.PUT, cache, historicalIndex, local, allowLocalChanges);
@@ -242,7 +265,7 @@
{
private final Object value;
- public RemoveFromListContainer(CacheKey key, Object value, AdvancedCache<Serializable, Object> cache,
+ public RemoveFromListContainer(CacheKey key, Object value, AdvancedCache<CacheKey, Object> cache,
int historicalIndex, boolean local, Boolean allowLocalChanges)
{
super(key, ChangesType.REMOVE, cache, historicalIndex, local, allowLocalChanges);
@@ -275,7 +298,7 @@
*/
public static class RemoveObjectContainer extends ChangesContainer
{
- public RemoveObjectContainer(CacheKey key, AdvancedCache<Serializable, Object> cache, int historicalIndex,
+ public RemoveObjectContainer(CacheKey key, AdvancedCache<CacheKey, Object> cache, int historicalIndex,
boolean local, Boolean allowLocalChanges)
{
super(key, ChangesType.REMOVE, cache, historicalIndex, local, allowLocalChanges);
@@ -289,7 +312,7 @@
}
}
- public BufferedISPNCache(Cache<Serializable, Object> parentCache, Boolean allowLocalChanges)
+ public BufferedISPNCache(Cache<CacheKey, Object> parentCache, Boolean allowLocalChanges)
{
this.parentCache = parentCache.getAdvancedCache();
this.allowLocalChanges = allowLocalChanges;
@@ -322,7 +345,7 @@
/**
* {@inheritDoc}
*/
- public Set<java.util.Map.Entry<Serializable, Object>> entrySet()
+ public Set<java.util.Map.Entry<CacheKey, Object>> entrySet()
{
return parentCache.entrySet();
}
@@ -330,7 +353,7 @@
/**
* {@inheritDoc}
*/
- public void evict(Serializable key)
+ public void evict(CacheKey key)
{
parentCache.evict(key);
}
@@ -338,7 +361,7 @@
/**
* {@inheritDoc}
*/
- public AdvancedCache<Serializable, Object> getAdvancedCache()
+ public AdvancedCache<CacheKey, Object> getAdvancedCache()
{
return parentCache.getAdvancedCache();
}
@@ -386,7 +409,7 @@
/**
* {@inheritDoc}
*/
- public Set<Serializable> keySet()
+ public Set<CacheKey> keySet()
{
return parentCache.keySet();
}
@@ -394,7 +417,7 @@
/**
* {@inheritDoc}
*/
- public Object put(Serializable key, Object value, long lifespan, TimeUnit unit)
+ public Object put(CacheKey key, Object value, long lifespan, TimeUnit unit)
{
return parentCache.put(key, value, lifespan, unit);
}
@@ -402,7 +425,7 @@
/**
* {@inheritDoc}
*/
- public Object put(Serializable key, Object value, long lifespan, TimeUnit lifespanUnit, long maxIdleTime,
+ public Object put(CacheKey key, Object value, long lifespan, TimeUnit lifespanUnit, long maxIdleTime,
TimeUnit maxIdleTimeUnit)
{
return parentCache.put(key, value, lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit);
@@ -411,7 +434,7 @@
/**
* {@inheritDoc}
*/
- public void putAll(Map<? extends Serializable, ? extends Object> map, long lifespan, TimeUnit unit)
+ public void putAll(Map<? extends CacheKey, ? extends Object> map, long lifespan, TimeUnit unit)
{
parentCache.putAll(map, lifespan, unit);
}
@@ -419,7 +442,7 @@
/**
* {@inheritDoc}
*/
- public void putAll(Map<? extends Serializable, ? extends Object> map, long lifespan, TimeUnit lifespanUnit,
+ public void putAll(Map<? extends CacheKey, ? extends Object> map, long lifespan, TimeUnit lifespanUnit,
long maxIdleTime, TimeUnit maxIdleTimeUnit)
{
parentCache.putAll(map, lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit);
@@ -428,7 +451,7 @@
/**
* {@inheritDoc}
*/
- public NotifyingFuture<Void> putAllAsync(Map<? extends Serializable, ? extends Object> data)
+ public NotifyingFuture<Void> putAllAsync(Map<? extends CacheKey, ? extends Object> data)
{
return parentCache.putAllAsync(data);
}
@@ -436,7 +459,7 @@
/**
* {@inheritDoc}
*/
- public NotifyingFuture<Void> putAllAsync(Map<? extends Serializable, ? extends Object> data, long lifespan,
+ public NotifyingFuture<Void> putAllAsync(Map<? extends CacheKey, ? extends Object> data, long lifespan,
TimeUnit unit)
{
return parentCache.putAllAsync(data, lifespan, unit);
@@ -445,7 +468,7 @@
/**
* {@inheritDoc}
*/
- public NotifyingFuture<Void> putAllAsync(Map<? extends Serializable, ? extends Object> data, long lifespan,
+ public NotifyingFuture<Void> putAllAsync(Map<? extends CacheKey, ? extends Object> data, long lifespan,
TimeUnit lifespanUnit, long maxIdle, TimeUnit maxIdleUnit)
{
return parentCache.putAllAsync(data, lifespan, lifespanUnit, maxIdle, maxIdleUnit);
@@ -454,7 +477,7 @@
/**
* {@inheritDoc}
*/
- public NotifyingFuture<Object> putAsync(Serializable key, Object value)
+ public NotifyingFuture<Object> putAsync(CacheKey key, Object value)
{
return parentCache.putAsync(key, value);
}
@@ -462,7 +485,7 @@
/**
* {@inheritDoc}
*/
- public NotifyingFuture<Object> putAsync(Serializable key, Object value, long lifespan, TimeUnit unit)
+ public NotifyingFuture<Object> putAsync(CacheKey key, Object value, long lifespan, TimeUnit unit)
{
return parentCache.putAsync(key, value, lifespan, unit);
}
@@ -470,7 +493,7 @@
/**
* {@inheritDoc}
*/
- public NotifyingFuture<Object> putAsync(Serializable key, Object value, long lifespan, TimeUnit lifespanUnit,
+ public NotifyingFuture<Object> putAsync(CacheKey key, Object value, long lifespan, TimeUnit lifespanUnit,
long maxIdle, TimeUnit maxIdleUnit)
{
return parentCache.putAsync(key, value, lifespan, lifespanUnit, maxIdle, maxIdleUnit);
@@ -479,7 +502,7 @@
/**
* {@inheritDoc}
*/
- public void putForExternalRead(Serializable key, Object value)
+ public void putForExternalRead(CacheKey key, Object value)
{
parentCache.putForExternalRead(key, value);
}
@@ -487,7 +510,7 @@
/**
* {@inheritDoc}
*/
- public Object putIfAbsent(Serializable key, Object value, long lifespan, TimeUnit unit)
+ public Object putIfAbsent(CacheKey key, Object value, long lifespan, TimeUnit unit)
{
return parentCache.putIfAbsent(key, value, lifespan, unit);
}
@@ -495,7 +518,7 @@
/**
* {@inheritDoc}
*/
- public Object putIfAbsent(Serializable key, Object value, long lifespan, TimeUnit lifespanUnit, long maxIdleTime,
+ public Object putIfAbsent(CacheKey key, Object value, long lifespan, TimeUnit lifespanUnit, long maxIdleTime,
TimeUnit maxIdleTimeUnit)
{
return parentCache.putIfAbsent(key, value, lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit);
@@ -504,7 +527,7 @@
/**
* {@inheritDoc}
*/
- public NotifyingFuture<Object> putIfAbsentAsync(Serializable key, Object value)
+ public NotifyingFuture<Object> putIfAbsentAsync(CacheKey key, Object value)
{
return parentCache.putIfAbsentAsync(key, value);
}
@@ -512,7 +535,7 @@
/**
* {@inheritDoc}
*/
- public NotifyingFuture<Object> putIfAbsentAsync(Serializable key, Object value, long lifespan, TimeUnit unit)
+ public NotifyingFuture<Object> putIfAbsentAsync(CacheKey key, Object value, long lifespan, TimeUnit unit)
{
return parentCache.putIfAbsentAsync(key, value, lifespan, unit);
}
@@ -520,7 +543,7 @@
/**
* {@inheritDoc}
*/
- public NotifyingFuture<Object> putIfAbsentAsync(Serializable key, Object value, long lifespan,
+ public NotifyingFuture<Object> putIfAbsentAsync(CacheKey key, Object value, long lifespan,
TimeUnit lifespanUnit, long maxIdle, TimeUnit maxIdleUnit)
{
return parentCache.putIfAbsentAsync(key, value, lifespan, lifespanUnit, maxIdle, maxIdleUnit);
@@ -545,7 +568,7 @@
/**
* {@inheritDoc}
*/
- public Object replace(Serializable key, Object value, long lifespan, TimeUnit unit)
+ public Object replace(CacheKey key, Object value, long lifespan, TimeUnit unit)
{
return parentCache.replace(key, value, lifespan, unit);
}
@@ -553,7 +576,7 @@
/**
* {@inheritDoc}
*/
- public boolean replace(Serializable key, Object oldValue, Object value, long lifespan, TimeUnit unit)
+ public boolean replace(CacheKey key, Object oldValue, Object value, long lifespan, TimeUnit unit)
{
return parentCache.replace(key, oldValue, value, lifespan, unit);
}
@@ -561,7 +584,7 @@
/**
* {@inheritDoc}
*/
- public Object replace(Serializable key, Object value, long lifespan, TimeUnit lifespanUnit, long maxIdleTime,
+ public Object replace(CacheKey key, Object value, long lifespan, TimeUnit lifespanUnit, long maxIdleTime,
TimeUnit maxIdleTimeUnit)
{
return parentCache.replace(key, value, lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit);
@@ -570,7 +593,7 @@
/**
* {@inheritDoc}
*/
- public boolean replace(Serializable key, Object oldValue, Object value, long lifespan, TimeUnit lifespanUnit,
+ public boolean replace(CacheKey key, Object oldValue, Object value, long lifespan, TimeUnit lifespanUnit,
long maxIdleTime, TimeUnit maxIdleTimeUnit)
{
return parentCache.replace(key, oldValue, value, lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit);
@@ -579,7 +602,7 @@
/**
* {@inheritDoc}
*/
- public NotifyingFuture<Object> replaceAsync(Serializable key, Object value)
+ public NotifyingFuture<Object> replaceAsync(CacheKey key, Object value)
{
return parentCache.replaceAsync(key, value);
}
@@ -587,7 +610,7 @@
/**
* {@inheritDoc}
*/
- public NotifyingFuture<Boolean> replaceAsync(Serializable key, Object oldValue, Object newValue)
+ public NotifyingFuture<Boolean> replaceAsync(CacheKey key, Object oldValue, Object newValue)
{
return parentCache.replaceAsync(key, oldValue, newValue);
}
@@ -595,7 +618,7 @@
/**
* {@inheritDoc}
*/
- public NotifyingFuture<Object> replaceAsync(Serializable key, Object value, long lifespan, TimeUnit unit)
+ public NotifyingFuture<Object> replaceAsync(CacheKey key, Object value, long lifespan, TimeUnit unit)
{
return parentCache.replaceAsync(key, value, lifespan, unit);
}
@@ -603,7 +626,7 @@
/**
* {@inheritDoc}
*/
- public NotifyingFuture<Boolean> replaceAsync(Serializable key, Object oldValue, Object newValue, long lifespan,
+ public NotifyingFuture<Boolean> replaceAsync(CacheKey key, Object oldValue, Object newValue, long lifespan,
TimeUnit unit)
{
return parentCache.replaceAsync(key, oldValue, newValue, lifespan, unit);
@@ -612,7 +635,7 @@
/**
* {@inheritDoc}
*/
- public NotifyingFuture<Object> replaceAsync(Serializable key, Object value, long lifespan, TimeUnit lifespanUnit,
+ public NotifyingFuture<Object> replaceAsync(CacheKey key, Object value, long lifespan, TimeUnit lifespanUnit,
long maxIdle, TimeUnit maxIdleUnit)
{
return parentCache.replaceAsync(key, value, lifespan, lifespanUnit, maxIdle, maxIdleUnit);
@@ -621,7 +644,7 @@
/**
* {@inheritDoc}
*/
- public NotifyingFuture<Boolean> replaceAsync(Serializable key, Object oldValue, Object newValue, long lifespan,
+ public NotifyingFuture<Boolean> replaceAsync(CacheKey key, Object oldValue, Object newValue, long lifespan,
TimeUnit lifespanUnit, long maxIdle, TimeUnit maxIdleUnit)
{
return parentCache.replaceAsync(key, oldValue, newValue);
@@ -646,9 +669,12 @@
/**
* {@inheritDoc}
*/
- public Object putIfAbsent(Serializable key, Object value)
+ public Object putIfAbsent(CacheKey key, Object value)
{
- return parentCache.putIfAbsent(key, value);
+ CompressedISPNChangesBuffer changesContainer = getChangesBufferSafe();
+ changesContainer.add(new PutObjectIfAbsentContainer(key, value, parentCache, changesContainer.getHistoryIndex(), local
+ .get(), allowLocalChanges));
+ return null;
}
/**
@@ -662,7 +688,7 @@
/**
* {@inheritDoc}
*/
- public Object replace(Serializable key, Object value)
+ public Object replace(CacheKey key, Object value)
{
return parentCache.replace(key, value);
}
@@ -670,7 +696,7 @@
/**
* {@inheritDoc}
*/
- public boolean replace(Serializable key, Object oldValue, Object newValue)
+ public boolean replace(CacheKey key, Object oldValue, Object newValue)
{
return parentCache.replace(key, oldValue, newValue);
}
@@ -760,16 +786,8 @@
/**
* {@inheritDoc}
*/
- public Object put(Serializable key, Object value)
+ public void putAll(Map<? extends CacheKey, ? extends Object> m)
{
- throw new UnsupportedOperationException("Unexpected method call use put(CacheKey key, Object value)");
- }
-
- /**
- * {@inheritDoc}
- */
- public void putAll(Map<? extends Serializable, ? extends Object> m)
- {
parentCache.putAll(m);
}
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/infinispan/ISPNCacheWorkspaceStorageCache.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/infinispan/ISPNCacheWorkspaceStorageCache.java 2011-04-13 12:55:17 UTC (rev 4233)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/infinispan/ISPNCacheWorkspaceStorageCache.java 2011-04-13 13:47:01 UTC (rev 4234)
@@ -53,7 +53,6 @@
import java.io.File;
import java.io.IOException;
-import java.io.Serializable;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Collections;
@@ -223,11 +222,11 @@
this.enabled = wsConfig.getCache().isEnabled();
// create cache using custom factory
- ISPNCacheFactory<Serializable, Object> factory = new ISPNCacheFactory<Serializable, Object>(cfm);
+ ISPNCacheFactory<CacheKey, Object> factory = new ISPNCacheFactory<CacheKey, Object>(cfm);
// create parent Infinispan instance
CacheEntry cacheEntry = wsConfig.getCache();
- Cache<Serializable, Object> parentCache = factory.createCache("Data_" + wsConfig.getUniqueName(), cacheEntry);
+ Cache<CacheKey, Object> parentCache = factory.createCache("Data_" + wsConfig.getUniqueName(), cacheEntry);
Boolean allowLocalChanges = null;
try
@@ -369,10 +368,6 @@
}
cache.setLocal(true);
-
- // remove previous all (to be sure about consistency)
- cache.remove(new CacheNodesId(parent.getIdentifier()));
-
if (childs.size() > 0)
{
Set<Object> set = new HashSet<Object>();
@@ -381,12 +376,12 @@
putNode(child, ModifyChildOption.NOT_MODIFY);
set.add(child.getIdentifier());
}
- cache.put(new CacheNodesId(parent.getIdentifier()), set);
+ cache.putIfAbsent(new CacheNodesId(parent.getIdentifier()), set);
}
else
{
// cache fact of empty childs list
- cache.put(new CacheNodesId(parent.getIdentifier()), new HashSet<Object>());
+ cache.putIfAbsent(new CacheNodesId(parent.getIdentifier()), new HashSet<Object>());
}
}
finally
@@ -412,8 +407,6 @@
cache.beginTransaction();
}
cache.setLocal(true);
- // remove previous all (to be sure about consistency)
- cache.remove(new CachePropsId(parent.getIdentifier()));
if (childs.size() > 0)
{
// add all new
@@ -423,7 +416,7 @@
putProperty(child, ModifyChildOption.NOT_MODIFY);
set.add(child.getIdentifier());
}
- cache.put(new CachePropsId(parent.getIdentifier()), set);
+ cache.putIfAbsent(new CachePropsId(parent.getIdentifier()), set);
}
else
@@ -670,7 +663,14 @@
{
if (node.getParentIdentifier() != null)
{
- cache.put(new CacheQPath(node.getParentIdentifier(), node.getQPath(), ItemType.NODE), node.getIdentifier());
+ if (modifyListsOfChild == ModifyChildOption.NOT_MODIFY)
+ {
+ cache.putIfAbsent(new CacheQPath(node.getParentIdentifier(), node.getQPath(), ItemType.NODE), node.getIdentifier());
+ }
+ else
+ {
+ cache.put(new CacheQPath(node.getParentIdentifier(), node.getQPath(), ItemType.NODE), node.getIdentifier());
+ }
// if MODIFY and List present OR FORCE_MODIFY, then write
if (modifyListsOfChild != ModifyChildOption.NOT_MODIFY)
@@ -680,7 +680,14 @@
}
}
- return (ItemData)cache.put(new CacheId(node.getIdentifier()), node, true);
+ if (modifyListsOfChild == ModifyChildOption.NOT_MODIFY)
+ {
+ return (ItemData)cache.putIfAbsent(new CacheId(node.getIdentifier()), node);
+ }
+ else
+ {
+ return (ItemData)cache.put(new CacheId(node.getIdentifier()), node, true);
+ }
}
protected ItemData putNodeInBufferedCache(NodeData node, ModifyChildOption modifyListsOfChild)
@@ -720,11 +727,11 @@
if (!item.getIdentifier().equals(NullItemData.NULL_ID))
{
- cache.put(new CacheId(item.getIdentifier()), item);
+ cache.putIfAbsent(new CacheId(item.getIdentifier()), item);
}
else if (item.getName() != null && item.getParentIdentifier() != null)
{
- cache.put(new CacheQPath(item.getParentIdentifier(), item.getName(), ItemType.getItemType(item)),
+ cache.putIfAbsent(new CacheQPath(item.getParentIdentifier(), item.getName(), ItemType.getItemType(item)),
NullItemData.NULL_ID);
}
}
@@ -752,8 +759,15 @@
cache.addToList(new CachePropsId(prop.getParentIdentifier()), prop.getIdentifier(),
modifyListsOfChild == ModifyChildOption.FORCE_MODIFY);
}
+ if (modifyListsOfChild == ModifyChildOption.NOT_MODIFY)
+ {
+ cache.putIfAbsent(new CacheQPath(prop.getParentIdentifier(), prop.getQPath(), ItemType.PROPERTY), prop.getIdentifier());
+ }
+ else
+ {
+ cache.put(new CacheQPath(prop.getParentIdentifier(), prop.getQPath(), ItemType.PROPERTY), prop.getIdentifier());
+ }
- cache.put(new CacheQPath(prop.getParentIdentifier(), prop.getQPath(), ItemType.PROPERTY), prop.getIdentifier());
// add referenced property
if (modifyListsOfChild != ModifyChildOption.NOT_MODIFY && prop.getType() == PropertyType.REFERENCE)
@@ -780,7 +794,16 @@
}
}
// NullItemData must never be returned inside internal cache operations.
- PropertyData propData = (PropertyData)cache.put(new CacheId(prop.getIdentifier()), prop, true);
+ PropertyData propData;
+ if (modifyListsOfChild == ModifyChildOption.NOT_MODIFY)
+ {
+ propData = (PropertyData)cache.putIfAbsent(new CacheId(prop.getIdentifier()), prop);
+ }
+ else
+ {
+ propData = (PropertyData)cache.put(new CacheId(prop.getIdentifier()), prop, true);
+ }
+
return (propData instanceof NullPropertyData) ? null : propData;
}
@@ -871,7 +894,7 @@
boolean inheritACL = acl != null;
// check all ITEMS in cache
- Iterator<Serializable> keys = cache.keySet().iterator();
+ Iterator<CacheKey> keys = cache.keySet().iterator();
while (keys.hasNext())
{
@@ -947,7 +970,7 @@
*/
protected void updateChildsACL(final String parentId, final AccessControlList acl)
{
- for (Iterator<NodeData> iter = new ChildNodesIterator<NodeData>(parentId); iter.hasNext();)
+ loop: for (Iterator<NodeData> iter = new ChildNodesIterator<NodeData>(parentId); iter.hasNext();)
{
NodeData prevNode = iter.next();
@@ -956,7 +979,7 @@
{
if (mixin.equals(Constants.EXO_PRIVILEGEABLE) || mixin.equals(Constants.EXO_OWNEABLE))
{
- continue;
+ continue loop;
}
}
@@ -1074,8 +1097,6 @@
cache.beginTransaction();
}
cache.setLocal(true);
- // remove previous all (to be sure about consistency)
- cache.remove(new CacheRefsId(identifier));
Set<Object> set = new HashSet<Object>();
for (PropertyData prop : refProperties)
@@ -1083,7 +1104,7 @@
putProperty(prop, ModifyChildOption.NOT_MODIFY);
set.add(prop.getIdentifier());
}
- cache.put(new CacheRefsId(identifier), set);
+ cache.putIfAbsent(new CacheRefsId(identifier), set);
}
finally
{
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/BufferedJBossCache.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/BufferedJBossCache.java 2011-04-13 12:55:17 UTC (rev 4233)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/BufferedJBossCache.java 2011-04-13 13:47:01 UTC (rev 4234)
@@ -489,7 +489,32 @@
return parentCache.get(fqn, key);
}
+
+ /**
+ * in case putIfAbsent is set to <code>true</code> this method will call cache.putIfAbsent(Fqn fqn, Serializable key, Object value)
+ * otherwise it will call cache.put(Fqn fqn, Serializable key, Object value)
+ */
+ protected Object put(Fqn fqn, Serializable key, Object value, boolean putIfAbsent)
+ {
+ if (putIfAbsent)
+ {
+ putIfAbsent(fqn, key, value);
+ return null;
+ }
+ return put(fqn, key, value);
+ }
+ /**
+ * This method will create and add a ChangesContainer that will put the value only if no value has been added
+ */
+ protected Object putIfAbsent(Fqn fqn, Serializable key, Object value)
+ {
+ CompressedChangesBuffer changesContainer = getChangesBufferSafe();
+ changesContainer.add(new PutIfAbsentKeyValueContainer(fqn, key, value, parentCache, changesContainer.getHistoryIndex(),
+ local.get(), useExpiration, expirationTimeOut));
+ return null;
+ }
+
public Object putInBuffer(Fqn fqn, Serializable key, Object value)
{
CompressedChangesBuffer changesContainer = getChangesBufferSafe();
@@ -824,6 +849,42 @@
}
/**
+ * PutIfAbsent container.
+ */
+ public static class PutIfAbsentKeyValueContainer extends ChangesContainer
+ {
+ private final Serializable key;
+
+ private final Object value;
+
+ public PutIfAbsentKeyValueContainer(Fqn fqn, Serializable key, Object value, Cache<Serializable, Object> cache,
+ int historicalIndex, boolean local, boolean useExpiration, long timeOut)
+ {
+ super(fqn, ChangesType.PUT_KEY, cache, historicalIndex, local, useExpiration, timeOut);
+ this.key = key;
+ this.value = value;
+ }
+
+ @Override
+ public void apply()
+ {
+ cache.getInvocationContext().getOptionOverrides().setForceWriteLock(true);
+ if (cache.get(fqn, key) != null)
+ {
+ // skip
+ return;
+ }
+ if (useExpiration)
+ {
+ putExpiration(fqn);
+ }
+
+ setCacheLocalMode();
+ cache.put(fqn, key, value);
+ }
+ }
+
+ /**
* Put container.
*/
public static class PutKeyValueContainer extends ChangesContainer
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/JBossCacheWorkspaceStorageCache.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/JBossCacheWorkspaceStorageCache.java 2011-04-13 12:55:17 UTC (rev 4233)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/dataflow/persistent/jbosscache/JBossCacheWorkspaceStorageCache.java 2011-04-13 13:47:01 UTC (rev 4234)
@@ -594,10 +594,6 @@
}
cache.setLocal(true);
- // remove previous all (to be sure about consistency)
- //TODO do we need remove node, while we can replace node?
- cache.removeNode(makeChildListFqn(childNodesList, parent.getIdentifier()));
-
if (childs.size() > 0)
{
Set<Object> set = new HashSet<Object>();
@@ -606,12 +602,12 @@
putNode(child, ModifyChildOption.NOT_MODIFY);
set.add(child.getIdentifier());
}
- cache.put(makeChildListFqn(childNodesList, parent.getIdentifier()), ITEM_LIST, set);
+ cache.putIfAbsent(makeChildListFqn(childNodesList, parent.getIdentifier()), ITEM_LIST, set);
}
else
{
// cache fact of empty childs list
- cache.put(makeChildListFqn(childNodesList, parent.getIdentifier()), ITEM_LIST, new HashSet<Object>());
+ cache.putIfAbsent(makeChildListFqn(childNodesList, parent.getIdentifier()), ITEM_LIST, new HashSet<Object>());
}
}
finally
@@ -637,9 +633,6 @@
cache.beginTransaction();
}
cache.setLocal(true);
- // remove previous all (to be sure about consistency)
- //TODO do we need remove node, while we can replace node?
- cache.removeNode(makeChildListFqn(childPropsList, parent.getIdentifier()));
if (childs.size() > 0)
{
// add all new
@@ -649,7 +642,7 @@
putProperty(child, ModifyChildOption.NOT_MODIFY);
set.add(child.getIdentifier());
}
- cache.put(makeChildListFqn(childPropsList, parent.getIdentifier()), ITEM_LIST, set);
+ cache.putIfAbsent(makeChildListFqn(childPropsList, parent.getIdentifier()), ITEM_LIST, set);
}
else
@@ -872,16 +865,13 @@
cache.setLocal(true);
- // remove previous all
- cache.removeNode(makeRefFqn(identifier));
-
Set<Object> set = new HashSet<Object>();
for (PropertyData prop : refProperties)
{
putProperty(prop, ModifyChildOption.NOT_MODIFY);
set.add(prop.getIdentifier());
}
- cache.put(makeRefFqn(identifier), ITEM_LIST, set);
+ cache.putIfAbsent(makeRefFqn(identifier), ITEM_LIST, set);
}
finally
{
@@ -1077,8 +1067,10 @@
if (node.getParentIdentifier() != null)
{
// add in CHILD_NODES
- cache.put(makeChildFqn(childNodes, node.getParentIdentifier(), node.getQPath().getEntries()[node.getQPath()
- .getEntries().length - 1]), ITEM_ID, node.getIdentifier());
+ cache.put(
+ makeChildFqn(childNodes, node.getParentIdentifier(), node.getQPath().getEntries()[node.getQPath()
+ .getEntries().length - 1]), ITEM_ID, node.getIdentifier(),
+ modifyListsOfChild == ModifyChildOption.NOT_MODIFY);
if (modifyListsOfChild != ModifyChildOption.NOT_MODIFY)
{
@@ -1088,7 +1080,7 @@
}
// add in ITEMS
- return (ItemData)cache.put(makeItemFqn(node.getIdentifier()), ITEM_DATA, node);
+ return (ItemData)cache.put(makeItemFqn(node.getIdentifier()), ITEM_DATA, node, modifyListsOfChild == ModifyChildOption.NOT_MODIFY);
}
/**
@@ -1110,20 +1102,20 @@
if (!item.getIdentifier().equals(NullItemData.NULL_ID))
{
//put in $ITEMS
- cache.put(makeItemFqn(item.getIdentifier()), ITEM_DATA, item);
+ cache.putIfAbsent(makeItemFqn(item.getIdentifier()), ITEM_DATA, item);
}
else if (item.getName() != null && item.getParentIdentifier() != null)
{
if (item.isNode())
{
// put in $CHILD_NODES
- cache.put(makeChildFqn(childNodes, item.getParentIdentifier(), item.getName()), ITEM_ID,
+ cache.putIfAbsent(makeChildFqn(childNodes, item.getParentIdentifier(), item.getName()), ITEM_ID,
NullItemData.NULL_ID);
}
else
{
// put in $CHILD_PROPERTIES
- cache.put(makeChildFqn(childProps, item.getParentIdentifier(), item.getName()), ITEM_ID,
+ cache.putIfAbsent(makeChildFqn(childProps, item.getParentIdentifier(), item.getName()), ITEM_ID,
NullItemData.NULL_ID);
}
}
@@ -1170,7 +1162,7 @@
{
// add in CHILD_PROPS
cache.put(makeChildFqn(childProps, prop.getParentIdentifier(), prop.getQPath().getEntries()[prop.getQPath()
- .getEntries().length - 1]), ITEM_ID, prop.getIdentifier());
+ .getEntries().length - 1]), ITEM_ID, prop.getIdentifier(), modifyListsOfChild == ModifyChildOption.NOT_MODIFY);
if (modifyListsOfChild != ModifyChildOption.NOT_MODIFY)
{
@@ -1206,7 +1198,7 @@
// add in ITEMS
// NullItemData must never be returned inside internal cache operations.
- ItemData returnedData = (ItemData)cache.put(makeItemFqn(prop.getIdentifier()), ITEM_DATA, prop);
+ ItemData returnedData = (ItemData)cache.put(makeItemFqn(prop.getIdentifier()), ITEM_DATA, prop, modifyListsOfChild == ModifyChildOption.NOT_MODIFY);
return (returnedData instanceof NullItemData) ? null : (PropertyData)returnedData;
}
@@ -1279,9 +1271,9 @@
}
/**
- * Update Node hierachy in case of same-name siblings reorder.
- * Assumes the new (updated) nodes already putted in the cache. Previous name of updated nodes will be calculated
- * and that node will be deleted (if has same id as the new node). Childs paths will be updated to a new node path.
+ * Update Node hierarchy in case of same-name siblings reorder.
+ * Assumes the new (updated) nodes already put in the cache. Previous name of updated nodes will be calculated
+ * and that node will be deleted (if has same id as the new node). Children paths will be updated to a new node path.
*
* @param node NodeData
* @param prevNode NodeData
@@ -1477,15 +1469,15 @@
*/
protected void updateChildsACL(final String parentId, final AccessControlList acl)
{
- for (Iterator<NodeData> iter = new ChildNodesIterator<NodeData>(parentId); iter.hasNext();)
+ loop: for (Iterator<NodeData> iter = new ChildNodesIterator<NodeData>(parentId); iter.hasNext();)
{
NodeData prevNode = iter.next();
- // is ACL changes on this node (i.e. ACL inheritance brokes)
+ // is ACL changes on this node (i.e. ACL inheritance broken)
for (InternalQName mixin : prevNode.getMixinTypeNames())
{
if (mixin.equals(Constants.EXO_PRIVILEGEABLE) || mixin.equals(Constants.EXO_OWNEABLE))
{
- continue;
+ continue loop;
}
}
// recreate with new path for child Nodes only
Added: jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/TestISPNCacheWorkspaceStorageCache.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/TestISPNCacheWorkspaceStorageCache.java (rev 0)
+++ jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/TestISPNCacheWorkspaceStorageCache.java 2011-04-13 13:47:01 UTC (rev 4234)
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2003-2011 eXo Platform SAS.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see<http://www.gnu.org/licenses/>.
+ */
+package org.exoplatform.services.jcr.impl.dataflow.persistent;
+
+import org.exoplatform.container.configuration.ConfigurationManagerImpl;
+import org.exoplatform.services.jcr.config.CacheEntry;
+import org.exoplatform.services.jcr.config.SimpleParameterEntry;
+import org.exoplatform.services.jcr.config.WorkspaceEntry;
+import org.exoplatform.services.jcr.dataflow.persistent.WorkspaceStorageCache;
+import org.exoplatform.services.jcr.impl.dataflow.persistent.infinispan.ISPNCacheWorkspaceStorageCache;
+
+import java.util.ArrayList;
+
+/**
+ * Created by The eXo Platform SAS.
+ *
+ * <br/>Date:
+ *
+ * @author <a href="karpenko.sergiy(a)gmail.com">Karpenko Sergiy</a>
+ * @version $Id: TestISPNCacheWorkspaceStorageCache.java 111 2008-11-11 11:11:11Z serg $
+ */
+public class TestISPNCacheWorkspaceStorageCache extends TestJBossCacheWorkspaceStorageCache
+{
+ @Override
+ public WorkspaceStorageCache getCacheImpl() throws Exception
+ {
+ ArrayList<SimpleParameterEntry> list = new ArrayList<SimpleParameterEntry>();
+ list.add(new SimpleParameterEntry("infinispan-configuration", "jar:/conf/standalone/test-infinispan-config.xml"));
+
+ CacheEntry entry = new CacheEntry(list);
+ entry.setEnabled(true);
+ WorkspaceEntry workspaceEntry = new WorkspaceEntry();
+ workspaceEntry.setUniqueName("WS_UUID");
+ workspaceEntry.setCache(entry);
+ return new ISPNCacheWorkspaceStorageCache(workspaceEntry, new ConfigurationManagerImpl());
+ }
+}
\ No newline at end of file
Modified: jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/TestJBossCacheWorkspaceStorageCache.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/TestJBossCacheWorkspaceStorageCache.java 2011-04-13 12:55:17 UTC (rev 4233)
+++ jcr/trunk/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/impl/dataflow/persistent/TestJBossCacheWorkspaceStorageCache.java 2011-04-13 13:47:01 UTC (rev 4234)
@@ -22,12 +22,32 @@
import org.exoplatform.services.jcr.config.CacheEntry;
import org.exoplatform.services.jcr.config.SimpleParameterEntry;
import org.exoplatform.services.jcr.config.WorkspaceEntry;
+import org.exoplatform.services.jcr.dataflow.ItemState;
+import org.exoplatform.services.jcr.dataflow.PlainChangesLog;
+import org.exoplatform.services.jcr.dataflow.PlainChangesLogImpl;
+import org.exoplatform.services.jcr.dataflow.persistent.PersistedNodeData;
import org.exoplatform.services.jcr.dataflow.persistent.WorkspaceStorageCache;
+import org.exoplatform.services.jcr.datamodel.ItemData;
+import org.exoplatform.services.jcr.datamodel.ItemType;
+import org.exoplatform.services.jcr.datamodel.NodeData;
+import org.exoplatform.services.jcr.datamodel.PropertyData;
+import org.exoplatform.services.jcr.datamodel.QPathEntry;
+import org.exoplatform.services.jcr.impl.Constants;
import org.exoplatform.services.jcr.impl.dataflow.persistent.jbosscache.JBossCacheWorkspaceStorageCache;
+import org.exoplatform.services.jcr.impl.storage.SystemDataContainerHolder;
+import org.exoplatform.services.jcr.impl.storage.WorkspaceDataContainerBase;
+import org.exoplatform.services.jcr.storage.WorkspaceDataContainer;
+import org.exoplatform.services.jcr.storage.WorkspaceStorageConnection;
import org.exoplatform.services.transaction.TransactionService;
import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicReference;
+import javax.jcr.InvalidItemStateException;
+import javax.jcr.RepositoryException;
+
/**
* Created by The eXo Platform SAS.
*
@@ -48,10 +68,294 @@
"jar:/conf/standalone/test-jbosscache-config.xml"));
CacheEntry entry = new CacheEntry(list);
+ entry.setEnabled(true);
WorkspaceEntry workspaceEntry = new WorkspaceEntry();
workspaceEntry.setUniqueName("WS_UUID");
workspaceEntry.setCache(entry);
return new JBossCacheWorkspaceStorageCache(workspaceEntry,
transactionService == null ? null : transactionService, new ConfigurationManagerImpl());
}
+
+ public void testRaceConditions() throws Exception
+ {
+ MyWorkspaceStorageConnection con = new MyWorkspaceStorageConnection();
+ WorkspaceDataContainer wdc = new MyWorkspaceDataContainer(con);
+ final CacheableWorkspaceDataManager cwdm =
+ new CacheableWorkspaceDataManager(wdc, getCacheImpl(), new SystemDataContainerHolder(wdc));
+ String idNode = "foo1";
+ executeConcurrentReadNWrite(con, cwdm, Mode.READ_FIRST, idNode);
+ assertNotNull(cwdm.getItemData(idNode));
+ idNode = "foo2";
+ executeConcurrentReadNWrite(con, cwdm, Mode.WRITE_FIRST, idNode);
+ assertNotNull(cwdm.getItemData(idNode));
+ }
+
+ /**
+ * @param con
+ * @param cwdm
+ * @param mode
+ * @param idNode
+ * @throws InterruptedException
+ */
+ private void executeConcurrentReadNWrite(MyWorkspaceStorageConnection con, final CacheableWorkspaceDataManager cwdm,
+ final Mode mode, final String idNode) throws InterruptedException
+ {
+ final CountDownLatch goSignal = con.setMode(mode);
+ final AtomicReference<Exception> ex = new AtomicReference<Exception>();
+ final CountDownLatch startSignal = new CountDownLatch(1);
+ final CountDownLatch doneSignal = new CountDownLatch(2);
+ Thread writer = new Thread()
+ {
+ public void run()
+ {
+ try
+ {
+ startSignal.await();
+ PlainChangesLog chlog = new PlainChangesLogImpl();
+ chlog.add(ItemState.createAddedState(new PersistedNodeData(idNode, Constants.ROOT_PATH, "parent-id", 1, 0,
+ Constants.NT_UNSTRUCTURED, null, null)));
+ cwdm.save(chlog);
+ if (mode == Mode.WRITE_FIRST) goSignal.countDown();
+ }
+ catch (Exception e)
+ {
+ ex.set(e);
+ }
+ finally
+ {
+ doneSignal.countDown();
+ }
+ }
+ };
+ writer.start();
+ Thread reader = new Thread()
+ {
+ public void run()
+ {
+ try
+ {
+ startSignal.await();
+ cwdm.getItemData(idNode);
+ if (mode == Mode.READ_FIRST) goSignal.countDown();
+ }
+ catch (Exception e)
+ {
+ ex.set(e);
+ }
+ finally
+ {
+ doneSignal.countDown();
+ }
+ }
+ };
+ reader.start();
+ startSignal.countDown();
+ doneSignal.await();
+ assertNull(ex.get());
+ }
+
+ private static enum Mode
+ {
+ READ_FIRST, WRITE_FIRST;
+ }
+ private static class MyWorkspaceStorageConnection implements WorkspaceStorageConnection
+ {
+
+
+ private Mode mode;
+ private CountDownLatch goSignal;
+
+ public CountDownLatch setMode(Mode mode)
+ {
+ this.mode = mode;
+ this.goSignal = new CountDownLatch(1);
+ return goSignal;
+ }
+
+
+ public void add(NodeData data) throws RepositoryException, UnsupportedOperationException,
+ InvalidItemStateException, IllegalStateException
+ {
+ }
+
+ public void add(PropertyData data) throws RepositoryException, UnsupportedOperationException,
+ InvalidItemStateException, IllegalStateException
+ {
+ }
+
+ public void close() throws IllegalStateException, RepositoryException
+ {
+ }
+
+ public void commit() throws IllegalStateException, RepositoryException
+ {
+ if (mode == Mode.READ_FIRST)
+ {
+ try
+ {
+ goSignal.await();
+ }
+ catch (InterruptedException e)
+ {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ public void delete(NodeData data) throws RepositoryException, UnsupportedOperationException,
+ InvalidItemStateException, IllegalStateException
+ {
+ }
+
+ public void delete(PropertyData data) throws RepositoryException, UnsupportedOperationException,
+ InvalidItemStateException, IllegalStateException
+ {
+ }
+
+ public int getChildNodesCount(NodeData parent) throws RepositoryException
+ {
+ return -1;
+ }
+
+ public List<NodeData> getChildNodesData(NodeData parent) throws RepositoryException, IllegalStateException
+ {
+ return null;
+ }
+
+ public List<PropertyData> getChildPropertiesData(NodeData parent) throws RepositoryException,
+ IllegalStateException
+ {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ItemData getItemData(NodeData parentData, QPathEntry name) throws RepositoryException,
+ IllegalStateException
+ {
+ return getItemData(parentData, name, ItemType.UNKNOWN);
+ }
+
+ public ItemData getItemData(NodeData parentData, QPathEntry name, ItemType itemType) throws RepositoryException,
+ IllegalStateException
+ {
+ return null;
+ }
+
+ public ItemData getItemData(String identifier) throws RepositoryException, IllegalStateException
+ {
+ if (mode == Mode.WRITE_FIRST)
+ {
+ try
+ {
+ goSignal.await();
+ }
+ catch (InterruptedException e)
+ {
+ Thread.currentThread().interrupt();
+ }
+ }
+ return null;
+ }
+
+ public List<PropertyData> getReferencesData(String nodeIdentifier) throws RepositoryException,
+ IllegalStateException, UnsupportedOperationException
+ {
+ return null;
+ }
+
+ public boolean isOpened()
+ {
+ return true;
+ }
+
+ public List<PropertyData> listChildPropertiesData(NodeData parent) throws RepositoryException,
+ IllegalStateException
+ {
+ return null;
+ }
+
+ public void rename(NodeData data) throws RepositoryException, UnsupportedOperationException,
+ InvalidItemStateException, IllegalStateException
+ {
+ }
+
+ public void rollback() throws IllegalStateException, RepositoryException
+ {
+ }
+
+ public void update(NodeData data) throws RepositoryException, UnsupportedOperationException,
+ InvalidItemStateException, IllegalStateException
+ {
+ }
+
+ public void update(PropertyData data) throws RepositoryException, UnsupportedOperationException,
+ InvalidItemStateException, IllegalStateException
+ {
+ }
+
+ public int getLastOrderNumber(NodeData parent) throws RepositoryException
+ {
+ return -1;
+ }
+
+ };
+
+ private static class MyWorkspaceDataContainer extends WorkspaceDataContainerBase
+ {
+
+ private WorkspaceStorageConnection con;
+
+ public MyWorkspaceDataContainer(WorkspaceStorageConnection con)
+ {
+ this.con = con;
+ }
+
+ public boolean isCheckSNSNewConnection()
+ {
+ return false;
+ }
+
+ public boolean isSame(WorkspaceDataContainer another)
+ {
+ return false;
+ }
+
+ public WorkspaceStorageConnection openConnection() throws RepositoryException
+ {
+ return con;
+ }
+
+ public WorkspaceStorageConnection openConnection(boolean readOnly) throws RepositoryException
+ {
+ return con;
+ }
+
+ public WorkspaceStorageConnection reuseConnection(WorkspaceStorageConnection original) throws RepositoryException
+ {
+ return con;
+ }
+
+ public String getInfo()
+ {
+ return "MyWorkspaceDataContainer";
+ }
+
+ public String getName()
+ {
+ return "MyWorkspaceDataContainer";
+ }
+
+ public String getStorageVersion()
+ {
+ return "0";
+ }
+
+ public String getUniqueName()
+ {
+ return "MyWorkspaceDataContainer";
+ }
+ };
+
}
15 years
exo-jcr SVN: r4233 - in jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main: docbook/en-US/modules/jcr/backup and 1 other directories.
by do-not-reply@jboss.org
Author: tolusha
Date: 2011-04-13 08:55:17 -0400 (Wed, 13 Apr 2011)
New Revision: 4233
Added:
jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr/backup/use-external-backup-tool.xml
jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/resources/images/repository-suspend-controller-online.png
jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/resources/images/repository-suspend-controller-suspended.png
jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/resources/images/repository-suspend-controller.png
Removed:
jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr/backup/search-index-backup.xml
Modified:
jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr.xml
Log:
EXOJCR-1301: [DOC] Allow to use external backup tools in a secure manner
Deleted: jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr/backup/search-index-backup.xml
===================================================================
--- jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr/backup/search-index-backup.xml 2011-04-13 11:19:32 UTC (rev 4232)
+++ jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr/backup/search-index-backup.xml 2011-04-13 12:55:17 UTC (rev 4233)
@@ -1,84 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
-"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-<chapter id="JCR.SearchIndexBackup">
- <?dbhtml filename="ch-search-index-backup.html"?>
-
- <title>Searching index backup</title>
-
- <section>
- <title>Manual backup (file copy)</title>
-
- <para>It can be useful for some reasons. The backup may be performed
- manually or using third part software.</para>
-
- <para>You can make a copy of the search index ($AS_HOME/temp/jcrlucenedb)
- and use it to replace the current index by this copy in case of an index
- damaged or lost.</para>
-
- <para>All repository changes that are applied between the index backup and
- the point of time when the backup index is restored, are not in the index
- and those modifications will not be found when searching. The
- modifications exist in the repository, but do not exist in the search
- index. <emphasis role="bold">And those changes will not be automatically
- reindexed.</emphasis></para>
-
- <para>For example: You have configured the workspace index to be in the
- "/index/workspace" directory.<itemizedlist>
- <listitem>
- <para>Make a backup of the search index - copy the content of the
- "/index" directory;</para>
- </listitem>
-
- <listitem>
- <para>Add the node "/anynode" to the workspace. Now this node exists
- in the workspace database and the search index has information about
- this node, so you can find it using query <code>select * from
- nt:base where jcr:path="/anynode"</code>;</para>
- </listitem>
-
- <listitem>
- <para>Rollback to the last backup - replace current
- "/index/workspace" directory by the backup;</para>
- </listitem>
-
- <listitem>
- <para>Node "/anynode" still exists and is accessible in the
- workspace (Session.getItem("/anynode")), but you can't find it via
- the search query<code> select * from nt:base where
- jcr:path="/anynode"</code>;</para>
- </listitem>
- </itemizedlist></para>
-
- <para>If you want to find changes made after updating, you have to reindex
- the whole workspace content. The way to do this is to stop the repository
- container and delete the "/index/workspace" folder. The workspace database
- content will be reindexed on repository startup.</para>
- </section>
-
- <section>
- <title>Consistency Requirements</title>
-
- <para>To have the workspace content consistent with the search index, the
- workspace database and the index directory should correspond to the same
- state. In case of an external (manual) backup <emphasis>the database
- backup and the index directory backup should be performed on a
- stopped/unmodifiable repository</emphasis>.</para>
-
- <para><emphasis role="bold">Only in that case the repository content and
- the search index will be consistent.</emphasis></para>
- </section>
-
- <section>
- <title>JCR Backup Service</title>
-
- <para>To get a hot-backup, which is executed on the fly, it's possible to
- use the <link linkend="JCR.BackupService">Backup service</link> which is
- available as a JCR Extension.</para>
-
- <note>
- <para>Backup service supports full and incremental backup types. A
- Scheduler is available.</para>
- </note>
- </section>
-</chapter>
Added: jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr/backup/use-external-backup-tool.xml
===================================================================
--- jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr/backup/use-external-backup-tool.xml (rev 0)
+++ jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr/backup/use-external-backup-tool.xml 2011-04-13 12:55:17 UTC (rev 4233)
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+<chapter id="JCR.SearchIndexBackup">
+ <?dbhtml filename="ch-search-index-backup.html"?>
+
+ <title>Use external backup tool</title>
+
+ <section>
+ <title>Repository suspending</title>
+
+ <para>To have the repository content consistent with the search index and
+ value storate, the repository should be suspened. It means all working
+ threads are suspended until resume operation performed. Index will be
+ flushed.</para>
+
+ <para>JCR provides ability to suspend repository via JMX.</para>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/repository-suspend-controller.png" />
+ </imageobject>
+ </mediaobject>
+
+ <para>To suspend repository just need to invoke suspend() operation. The
+ returned result will be "suspended" if everything passed
+ successfully.</para>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/repository-suspend-controller-suspended.png" />
+ </imageobject>
+ </mediaobject>
+ </section>
+
+ <section>
+ <title>Backup</title>
+
+ <para>Now we can backup content manually or using third part software. We
+ need to backup:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>Database</para>
+ </listitem>
+
+ <listitem>
+ <para>Lucene index</para>
+ </listitem>
+
+ <listitem>
+ <para>Value storage (if configured)</para>
+ </listitem>
+ </itemizedlist>
+ </section>
+
+ <section>
+ <title>Repository resuming</title>
+
+ <para>Once backup is done need to invoke resume() operation to resume
+ repository. The returned result will be "online" </para>
+
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="images/repository-suspend-controller-online.png" />
+ </imageobject>
+ </mediaobject>
+ </section>
+</chapter>
Modified: jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr.xml
===================================================================
--- jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr.xml 2011-04-13 11:19:32 UTC (rev 4232)
+++ jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/jcr.xml 2011-04-13 12:55:17 UTC (rev 4233)
@@ -121,7 +121,7 @@
<xi:include href="jcr/backup/backup-client.xml"
xmlns:xi="http://www.w3.org/2001/XInclude" />
- <xi:include href="jcr/backup/search-index-backup.xml"
+ <xi:include href="jcr/backup/use-external-backup-tool.xml"
xmlns:xi="http://www.w3.org/2001/XInclude" />
<!-- other -->
Added: jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/resources/images/repository-suspend-controller-online.png
===================================================================
(Binary files differ)
Property changes on: jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/resources/images/repository-suspend-controller-online.png
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/resources/images/repository-suspend-controller-suspended.png
===================================================================
(Binary files differ)
Property changes on: jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/resources/images/repository-suspend-controller-suspended.png
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/resources/images/repository-suspend-controller.png
===================================================================
(Binary files differ)
Property changes on: jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/resources/images/repository-suspend-controller.png
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
15 years
exo-jcr SVN: r4232 - jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/backup.
by do-not-reply@jboss.org
Author: tolusha
Date: 2011-04-13 07:19:32 -0400 (Wed, 13 Apr 2011)
New Revision: 4232
Modified:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/backup/RepositorySuspendController.java
Log:
EXOJCR-1301: Allow to use external backup tools in a secure manner
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/backup/RepositorySuspendController.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/backup/RepositorySuspendController.java 2011-04-13 11:16:17 UTC (rev 4231)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/backup/RepositorySuspendController.java 2011-04-13 11:19:32 UTC (rev 4232)
@@ -23,6 +23,7 @@
import org.exoplatform.management.jmx.annotations.NameTemplate;
import org.exoplatform.management.jmx.annotations.Property;
import org.exoplatform.services.jcr.core.ManageableRepository;
+import org.exoplatform.services.jcr.core.security.JCRRuntimePermissions;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.picocontainer.Startable;
@@ -54,7 +55,7 @@
/**
* Undefined state.
*/
- public final String UNDEFINED = "undefined";
+ private final String UNDEFINED = "undefined";
private final ManageableRepository repository;
@@ -80,6 +81,13 @@
@ManagedDescription("Suspend repository which means that allow only read operations. All writing threads will wait until resume operations invoked.")
public String suspend()
{
+ // Need privileges to manage repository.
+ SecurityManager security = System.getSecurityManager();
+ if (security != null)
+ {
+ security.checkPermission(JCRRuntimePermissions.MANAGE_REPOSITORY_PERMISSION);
+ }
+
for (Suspendable component : getSuspendableComponents())
{
try
@@ -104,6 +112,13 @@
@ManagedDescription("Resume repository. All previously suspended threads continue working.")
public String resume()
{
+ // Need privileges to manage repository.
+ SecurityManager security = System.getSecurityManager();
+ if (security != null)
+ {
+ security.checkPermission(JCRRuntimePermissions.MANAGE_REPOSITORY_PERMISSION);
+ }
+
List<Suspendable> components = getSuspendableComponents();
Collections.reverse(components);
15 years
exo-jcr SVN: r4231 - in jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr: impl/backup and 1 other directory.
by do-not-reply@jboss.org
Author: tolusha
Date: 2011-04-13 07:16:17 -0400 (Wed, 13 Apr 2011)
New Revision: 4231
Modified:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/core/ManageableRepository.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/backup/RepositorySuspendController.java
Log:
EXOJCR-1301: Allow to use external backup tools in a secure manner
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/core/ManageableRepository.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/core/ManageableRepository.java 2011-04-13 10:47:04 UTC (rev 4230)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/core/ManageableRepository.java 2011-04-13 11:16:17 UTC (rev 4231)
@@ -60,16 +60,6 @@
final int READONLY = 2;
/**
- * Repository SUSPENDED state.
- */
- public final int SUSPENDED = 3;
-
- /**
- * Undefined state.
- */
- public final int UNDEFINED = 4;
-
- /**
* Add the items persistence listener to the named workspace.
*
* @param workspaceName - name of workspace
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/backup/RepositorySuspendController.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/backup/RepositorySuspendController.java 2011-04-13 10:47:04 UTC (rev 4230)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/backup/RepositorySuspendController.java 2011-04-13 11:16:17 UTC (rev 4231)
@@ -41,6 +41,21 @@
@NameTemplate(@Property(key = "service", value = "RepositorySuspendController"))
public class RepositorySuspendController implements Startable
{
+ /**
+ * Repository ONLINE status.
+ */
+ private final String ONLINE = "online";
+
+ /**
+ * Repository SUSPENDED state.
+ */
+ private final String SUSPENDED = "suspended";
+
+ /**
+ * Undefined state.
+ */
+ public final String UNDEFINED = "undefined";
+
private final ManageableRepository repository;
/**
@@ -63,7 +78,7 @@
*/
@Managed
@ManagedDescription("Suspend repository which means that allow only read operations. All writing threads will wait until resume operations invoked.")
- public int suspend()
+ public String suspend()
{
for (Suspendable component : getSuspendableComponents())
{
@@ -87,7 +102,7 @@
*/
@Managed
@ManagedDescription("Resume repository. All previously suspended threads continue working.")
- public int resume()
+ public String resume()
{
List<Suspendable> components = getSuspendableComponents();
Collections.reverse(components);
@@ -115,9 +130,9 @@
*/
@Managed
@ManagedDescription("Returns repository state.")
- public int getState()
+ public String getState()
{
- int state = ManageableRepository.ONLINE;
+ String state = ONLINE;
boolean hasSuspendedComponents = false;
boolean hasOnlineComponents = false;
@@ -130,17 +145,17 @@
if (hasOnlineComponents)
{
- return ManageableRepository.UNDEFINED;
+ return UNDEFINED;
}
- state = ManageableRepository.SUSPENDED;
+ state = SUSPENDED;
}
else
{
hasOnlineComponents = true;
if (hasSuspendedComponents)
{
- return ManageableRepository.UNDEFINED;
+ return UNDEFINED;
}
}
}
15 years