exo-jcr SVN: r1153 - jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene.
by do-not-reply@jboss.org
Author: nzamosenchuk
Date: 2009-12-23 08:11:55 -0500 (Wed, 23 Dec 2009)
New Revision: 1153
Modified:
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/MultiIndex.java
Log:
EXOJCR-327: Fixed NPE, in deprecated method MultiIndex.refreshIndexesList().
Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/MultiIndex.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/MultiIndex.java 2009-12-23 12:58:25 UTC (rev 1152)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/MultiIndex.java 2009-12-23 13:11:55 UTC (rev 1153)
@@ -2436,6 +2436,7 @@
// get new indexInfo
IndexInfos newIndexNames = new IndexInfos(indexNames.isSystem(), ioMode);
newIndexNames.setMultiIndex(this);
+ newIndexNames.setDirectory(indexDir);
if (newIndexNames.exists())
{
newIndexNames.read();
16 years, 7 months
exo-jcr SVN: r1152 - in jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query: jbosscache and 1 other directories.
by do-not-reply@jboss.org
Author: nzamosenchuk
Date: 2009-12-23 07:58:25 -0500 (Wed, 23 Dec 2009)
New Revision: 1152
Modified:
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/AbstractQueryHandler.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/DefaultChangesFilter.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandler.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/JbossCacheIndexChangesFilter.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/JbossCacheIndexInfos.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/IndexInfos.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/MultiIndex.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java
Log:
EXOJCR-327: IndexInfos now gets IoMode and flag whether it is system. Changed fields and methods visibility policy, updated JBossCacheIndexInfos.
Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/AbstractQueryHandler.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/AbstractQueryHandler.java 2009-12-23 10:44:33 UTC (rev 1151)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/AbstractQueryHandler.java 2009-12-23 12:58:25 UTC (rev 1152)
@@ -70,7 +70,7 @@
/**
* {@link IndexInfos} instance that is passed to {@link MultiIndex}
*/
- protected IndexInfos indexInfos;
+ private IndexInfos indexInfos;
public boolean isInitialized()
{
@@ -220,4 +220,12 @@
this.indexInfos = indexInfos;
}
+ /**
+ * @see org.exoplatform.services.jcr.impl.core.query.QueryHandler#getIndexInfos()
+ */
+ public IndexInfos getIndexInfos()
+ {
+ return indexInfos;
+ }
+
}
Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/DefaultChangesFilter.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/DefaultChangesFilter.java 2009-12-23 10:44:33 UTC (rev 1151)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/DefaultChangesFilter.java 2009-12-23 12:58:25 UTC (rev 1152)
@@ -59,12 +59,12 @@
if (!parentHandler.isInitialized())
{
- parentHandler.setIndexInfos(new IndexInfos());
+ parentHandler.setIndexInfos(new IndexInfos(true, IndexerIoMode.READ_WRITE));
parentHandler.init();
}
if (!handler.isInitialized())
{
- parentHandler.setIndexInfos(new IndexInfos());
+ handler.setIndexInfos(new IndexInfos(false, IndexerIoMode.READ_WRITE));
handler.init();
}
}
Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandler.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandler.java 2009-12-23 10:44:33 UTC (rev 1151)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandler.java 2009-12-23 12:58:25 UTC (rev 1152)
@@ -155,10 +155,16 @@
public QueryHits executeQuery(Query query) throws IOException;
/**
- * Sets {@link IndexInfos} instance to QueryHandler, which is later passed to {@link MultiIndex}.
+ * Sets {@link IndexInfos} instance into QueryHandler, which is later passed to {@link MultiIndex}.
*
* @param indexInfos
*/
public void setIndexInfos(IndexInfos indexInfos);
+
+ /**
+ * Returns {@link IndexInfos} instance that was set into QueryHandler.
+ * @return
+ */
+ public IndexInfos getIndexInfos();
}
Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/JbossCacheIndexChangesFilter.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/JbossCacheIndexChangesFilter.java 2009-12-23 10:44:33 UTC (rev 1151)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/JbossCacheIndexChangesFilter.java 2009-12-23 12:58:25 UTC (rev 1152)
@@ -26,7 +26,6 @@
import org.exoplatform.services.jcr.impl.core.query.IndexingTree;
import org.exoplatform.services.jcr.impl.core.query.QueryHandler;
import org.exoplatform.services.jcr.impl.core.query.SearchManager;
-import org.exoplatform.services.jcr.impl.core.query.lucene.IndexInfos;
import org.exoplatform.services.jcr.util.IdGenerator;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
@@ -59,16 +58,8 @@
private final Cache<Serializable, Object> cache;
- public static String ADDED = "$add".intern();
+ public static final String LISTWRAPPER = "$lists".intern();
- public static String REMOVED = "$remove".intern();
-
- public static String PARENT_ADDED = "$padd".intern();
-
- public static String PARENT_REMOVED = "$premove".intern();
-
- public static String LISTWRAPPER = "$lists".intern();
-
/**
* @param searchManager
* @param config
@@ -127,12 +118,12 @@
if (!parentHandler.isInitialized())
{
- parentHandler.setIndexInfos(new JbossCacheIndexInfos(cache));
+ parentHandler.setIndexInfos(new JbossCacheIndexInfos(cache, true, ioMode));
parentHandler.init();
}
if (!handler.isInitialized())
{
- handler.setIndexInfos(new JbossCacheIndexInfos(cache));
+ handler.setIndexInfos(new JbossCacheIndexInfos(cache, false, ioMode));
handler.init();
}
Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/JbossCacheIndexInfos.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/JbossCacheIndexInfos.java 2009-12-23 10:44:33 UTC (rev 1151)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/JbossCacheIndexInfos.java 2009-12-23 12:58:25 UTC (rev 1152)
@@ -18,49 +18,113 @@
*/
package org.exoplatform.services.jcr.impl.core.query.jbosscache;
-import org.apache.lucene.store.Directory;
+import org.exoplatform.services.jcr.impl.core.query.IndexerIoMode;
import org.exoplatform.services.jcr.impl.core.query.lucene.IndexInfos;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
import org.jboss.cache.Cache;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.notifications.annotation.CacheListener;
+import org.jboss.cache.notifications.annotation.NodeModified;
+import org.jboss.cache.notifications.event.NodeModifiedEvent;
+
import java.io.IOException;
import java.io.Serializable;
+import java.util.Set;
/**
* @author <a href="mailto:nikolazius@gmail.com">Nikolay Zamosenchuk</a>
* @version $Id: JbossCacheIndexInfos.java 34360 2009-07-22 23:58:59Z nzamosenchuk $
*
*/
+@CacheListener
public class JbossCacheIndexInfos extends IndexInfos
{
+ private final Log log = ExoLogger.getLogger(this.getClass().getName());
+
+ public static final String INDEX_NAMES = "$names".intern();
+
+ public static final String SYSINDEX_NAMES = "$sysNames".intern();
+
+ public static final String LIST = "$list".intern();
+
private final Cache<Serializable, Object> cache;
/**
+ * This FQN points to cache node, where list of indexes for this {@link IndexInfos} instance is stored.
+ */
+ private final Fqn namesFqn;
+
+ /**
* @param cache instance of JbossCache that is used to deliver index names
*/
- public JbossCacheIndexInfos(Cache<Serializable, Object> cache)
+ public JbossCacheIndexInfos(Cache<Serializable, Object> cache, boolean system, IndexerIoMode ioMode)
{
- this(DEFALUT_NAME, cache);
+ this(DEFALUT_NAME, cache, system, ioMode);
}
/**
* @param fileName where index names are stored.
* @param cache instance of JbossCache that is used to deliver index names
*/
- public JbossCacheIndexInfos(String fileName, Cache<Serializable, Object> cache)
+ public JbossCacheIndexInfos(String fileName, Cache<Serializable, Object> cache, boolean system, IndexerIoMode ioMode)
{
- super(fileName);
+ super(fileName, system, ioMode);
this.cache = cache;
+ namesFqn = Fqn.fromString(system ? SYSINDEX_NAMES : INDEX_NAMES);
}
@Override
public void write() throws IOException
{
- boolean dirty = this.dirty;
+ boolean dirty = isDirty();
+ // write to FS
super.write();
+ // write to cache
if (dirty)
{
// send to cache new list.
}
}
+ @NodeModified
+ public void cacheNodeModified(NodeModifiedEvent event)
+ {
+ if (!event.isPre() && event.equals(namesFqn))
+ {
+ // update lists
+ setNames((Set<String>)cache.get(namesFqn, LIST));
+ // callback multiIndex to refresh lists
+ try
+ {
+ getMultiIndex().refreshIndexList();
+ }
+ catch (IOException e)
+ {
+ log.error("Failed to update indexes! " + e.getMessage(), e);
+ }
+ }
+ }
+
+ @Override
+ public void setIoMode(IndexerIoMode ioMode) throws IOException
+ {
+ if (getIoMode() != ioMode)
+ {
+ super.setIoMode(ioMode);
+ if (ioMode == IndexerIoMode.READ_WRITE)
+ {
+ // Now is read-write. Index list is actual and shouldn't be refreshed.
+ // Remove listener to avoid asserting if ioMode is RO on each cache event
+ cache.removeCacheListener(this);
+ }
+ else
+ {
+ // Currently READ_ONLY is set, so new lists should be fired to multiIndex.
+ cache.addCacheListener(this);
+ }
+ }
+ }
+
}
Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/IndexInfos.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/IndexInfos.java 2009-12-23 10:44:33 UTC (rev 1151)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/IndexInfos.java 2009-12-23 12:58:25 UTC (rev 1152)
@@ -16,6 +16,11 @@
*/
package org.exoplatform.services.jcr.impl.core.query.lucene;
+import org.apache.lucene.store.Directory;
+import org.exoplatform.services.jcr.impl.core.query.IndexerIoMode;
+import org.exoplatform.services.jcr.impl.core.query.lucene.directory.IndexInputStream;
+import org.exoplatform.services.jcr.impl.core.query.lucene.directory.IndexOutputStream;
+
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
@@ -26,10 +31,6 @@
import java.util.List;
import java.util.Set;
-import org.apache.lucene.store.Directory;
-import org.exoplatform.services.jcr.impl.core.query.lucene.directory.IndexInputStream;
-import org.exoplatform.services.jcr.impl.core.query.lucene.directory.IndexOutputStream;
-
/**
* Stores a sequence of index names.
*/
@@ -44,39 +45,51 @@
/**
* For new segment names.
*/
- protected int counter = 0;
+ private int counter = 0;
/**
* Flag that indicates if index infos needs to be written to disk.
*/
- protected boolean dirty = false;
+ private boolean dirty = false;
/**
* List of index names
*/
- protected List indexes = new ArrayList();
+ private List<String> indexes = new ArrayList<String>();
/**
* Set of names for quick lookup.
*/
- protected Set names = new HashSet();
+ private Set<String> names = new HashSet<String>();
/**
* Name of the file where the infos are stored.
*/
- protected final String name;
+ private final String name;
/**
* Directory, where index names file is stored.
*/
- protected Directory dir;
+ private Directory dir;
/**
+ * {@link MultiIndex} instance for callbacking when list of indexes changed
+ */
+ private MultiIndex multiIndex;
+
+ /**
+ * {@link IndexerIoMode} is used to define current mode.
+ */
+ private IndexerIoMode ioMode;
+
+ private final boolean system;
+
+ /**
* Creates a new IndexInfos using <code>"indexes"</code> as a filename.
*/
- public IndexInfos()
+ public IndexInfos(boolean system, IndexerIoMode ioMode)
{
- this(DEFALUT_NAME);
+ this(DEFALUT_NAME, system, ioMode);
}
/**
@@ -84,9 +97,11 @@
*
* @param fileName the name of the file where infos are stored.
*/
- public IndexInfos(String fileName)
+ public IndexInfos(String fileName, boolean system, IndexerIoMode ioMode)
{
this.name = fileName;
+ this.system = system;
+ this.ioMode = ioMode;
}
/**
@@ -265,11 +280,89 @@
}
/**
- * Sets direcotry, where file with index names is stored.
+ * Sets directory, where file with index names is stored.
* @param dir
*/
- public void setDir(Directory dir)
+ public void setDirectory(Directory dir)
{
this.dir = dir;
}
+
+ /**
+ * Sets {@link IndexerIoMode} to indexInfos;
+ * @param ioMode
+ * @throws IOException
+ */
+ public void setIoMode(IndexerIoMode ioMode) throws IOException
+ {
+ if (this.ioMode != ioMode)
+ {
+ this.ioMode = ioMode;
+ if (ioMode == IndexerIoMode.READ_WRITE)
+ {
+ names.clear();
+ indexes.clear();
+ read();
+ }
+ }
+ }
+
+ /**
+ * Returns current mode.
+ * @return
+ */
+ public IndexerIoMode getIoMode()
+ {
+ return ioMode;
+ }
+
+ /**
+ * Sets new names, clearing existing.
+ * @param names
+ */
+ protected void setNames(Set<String> names)
+ {
+ this.names.clear();
+ this.indexes.clear();
+ this.names.addAll(names);
+ this.indexes.addAll(names);
+ // new list of indexes if thought to be up to date
+ dirty = false;
+ }
+
+ /**
+ * Sets {@link MultiIndex} instance.
+ * @param multiIndex
+ */
+ public void setMultiIndex(MultiIndex multiIndex)
+ {
+ this.multiIndex = multiIndex;
+ }
+
+ /**
+ * Returns multiIndex instance
+ * @return
+ */
+ public MultiIndex getMultiIndex()
+ {
+ return multiIndex;
+ }
+
+ /**
+ * Returns true if this {@link IndexInfos} corresponds to SystemSearchManager
+ * @return
+ */
+ public boolean isSystem()
+ {
+ return system;
+ }
+
+ /**
+ * Returns true, if changes weren't saved to FS.
+ * @return
+ */
+ protected boolean isDirty()
+ {
+ return dirty;
+ }
}
Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/MultiIndex.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/MultiIndex.java 2009-12-23 10:44:33 UTC (rev 1151)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/MultiIndex.java 2009-12-23 12:58:25 UTC (rev 1152)
@@ -237,7 +237,7 @@
this.nsMappings = handler.getNamespaceMappings();
this.flushTask = null;
this.indexNames = indexInfos;
- this.indexNames.setDir(indexDir);
+ this.indexNames.setDirectory(indexDir);
if (indexNames.exists())
{
indexNames.read();
@@ -2355,6 +2355,7 @@
if (!this.ioMode.equals(ioMode))
{
this.ioMode = ioMode;
+ indexNames.setIoMode(ioMode);
switch (ioMode)
{
case READ_ONLY :
@@ -2433,7 +2434,8 @@
// release reader if any
releaseMultiReader();
// get new indexInfo
- IndexInfos newIndexNames = new IndexInfos();
+ IndexInfos newIndexNames = new IndexInfos(indexNames.isSystem(), ioMode);
+ newIndexNames.setMultiIndex(this);
if (newIndexNames.exists())
{
newIndexNames.read();
Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java 2009-12-23 10:44:33 UTC (rev 1151)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java 2009-12-23 12:58:25 UTC (rev 1152)
@@ -515,8 +515,7 @@
indexingConfig = createIndexingConfiguration(nsMappings);
analyzer.setIndexingConfig(indexingConfig);
- index =
- new MultiIndex(this, context.getIndexingTree(), ioMode, indexInfos == null ? new IndexInfos() : indexInfos);
+ index = new MultiIndex(this, context.getIndexingTree(), ioMode, getIndexInfos());
// if RW mode, create initial index and start check
if (ioMode == IndexerIoMode.READ_WRITE)
{
16 years, 7 months
exo-jcr SVN: r1151 - in jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query: jbosscache and 1 other directories.
by do-not-reply@jboss.org
Author: nzamosenchuk
Date: 2009-12-23 05:44:33 -0500 (Wed, 23 Dec 2009)
New Revision: 1151
Added:
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/JbossCacheIndexInfos.java
Modified:
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/AbstractQueryHandler.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/DefaultChangesFilter.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandler.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/JbossCacheIndexChangesFilter.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/IndexInfos.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/MultiIndex.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java
Log:
EXOJCR-327: IndexInfos class gets Directory by setter now, and methods read(), write(), exists() doesn't get a directory as parameter. Changed IndexInfos lifecycle, it is now created by Changes filter and passed to QueryHandler and then passed to MultiIndex.
Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/AbstractQueryHandler.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/AbstractQueryHandler.java 2009-12-23 08:59:41 UTC (rev 1150)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/AbstractQueryHandler.java 2009-12-23 10:44:33 UTC (rev 1151)
@@ -23,6 +23,8 @@
import org.exoplatform.services.jcr.config.RepositoryConfigurationException;
import org.exoplatform.services.jcr.datamodel.NodeData;
+import org.exoplatform.services.jcr.impl.core.query.lucene.IndexInfos;
+import org.exoplatform.services.jcr.impl.core.query.lucene.MultiIndex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -65,6 +67,11 @@
*/
protected IndexerIoMode ioMode = IndexerIoMode.READ_ONLY;
+ /**
+ * {@link IndexInfos} instance that is passed to {@link MultiIndex}
+ */
+ protected IndexInfos indexInfos;
+
public boolean isInitialized()
{
return initialized;
@@ -205,4 +212,12 @@
return idleTime;
}
+ /**
+ * @see org.exoplatform.services.jcr.impl.core.query.QueryHandler#setIndexInfos(org.exoplatform.services.jcr.impl.core.query.lucene.IndexInfos)
+ */
+ public void setIndexInfos(IndexInfos indexInfos)
+ {
+ this.indexInfos = indexInfos;
+ }
+
}
Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/DefaultChangesFilter.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/DefaultChangesFilter.java 2009-12-23 08:59:41 UTC (rev 1150)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/DefaultChangesFilter.java 2009-12-23 10:44:33 UTC (rev 1151)
@@ -20,6 +20,7 @@
import org.exoplatform.services.jcr.config.QueryHandlerEntry;
import org.exoplatform.services.jcr.config.RepositoryConfigurationException;
+import org.exoplatform.services.jcr.impl.core.query.lucene.IndexInfos;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
@@ -58,10 +59,12 @@
if (!parentHandler.isInitialized())
{
+ parentHandler.setIndexInfos(new IndexInfos());
parentHandler.init();
}
if (!handler.isInitialized())
{
+ parentHandler.setIndexInfos(new IndexInfos());
handler.init();
}
}
Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandler.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandler.java 2009-12-23 08:59:41 UTC (rev 1150)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandler.java 2009-12-23 10:44:33 UTC (rev 1151)
@@ -21,6 +21,8 @@
import org.exoplatform.services.jcr.datamodel.NodeData;
import org.exoplatform.services.jcr.impl.core.SessionDataManager;
import org.exoplatform.services.jcr.impl.core.SessionImpl;
+import org.exoplatform.services.jcr.impl.core.query.lucene.IndexInfos;
+import org.exoplatform.services.jcr.impl.core.query.lucene.MultiIndex;
import org.exoplatform.services.jcr.impl.core.query.lucene.QueryHits;
import java.io.IOException;
@@ -152,4 +154,11 @@
*/
public QueryHits executeQuery(Query query) throws IOException;
+ /**
+ * Sets {@link IndexInfos} instance to QueryHandler, which is later passed to {@link MultiIndex}.
+ *
+ * @param indexInfos
+ */
+ public void setIndexInfos(IndexInfos indexInfos);
+
}
Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/JbossCacheIndexChangesFilter.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/JbossCacheIndexChangesFilter.java 2009-12-23 08:59:41 UTC (rev 1150)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/JbossCacheIndexChangesFilter.java 2009-12-23 10:44:33 UTC (rev 1151)
@@ -26,6 +26,7 @@
import org.exoplatform.services.jcr.impl.core.query.IndexingTree;
import org.exoplatform.services.jcr.impl.core.query.QueryHandler;
import org.exoplatform.services.jcr.impl.core.query.SearchManager;
+import org.exoplatform.services.jcr.impl.core.query.lucene.IndexInfos;
import org.exoplatform.services.jcr.util.IdGenerator;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
@@ -126,10 +127,12 @@
if (!parentHandler.isInitialized())
{
+ parentHandler.setIndexInfos(new JbossCacheIndexInfos(cache));
parentHandler.init();
}
if (!handler.isInitialized())
{
+ handler.setIndexInfos(new JbossCacheIndexInfos(cache));
handler.init();
}
Added: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/JbossCacheIndexInfos.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/JbossCacheIndexInfos.java (rev 0)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/JbossCacheIndexInfos.java 2009-12-23 10:44:33 UTC (rev 1151)
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2009 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.core.query.jbosscache;
+
+import org.apache.lucene.store.Directory;
+import org.exoplatform.services.jcr.impl.core.query.lucene.IndexInfos;
+import org.jboss.cache.Cache;
+import java.io.IOException;
+import java.io.Serializable;
+
+/**
+ * @author <a href="mailto:nikolazius@gmail.com">Nikolay Zamosenchuk</a>
+ * @version $Id: JbossCacheIndexInfos.java 34360 2009-07-22 23:58:59Z nzamosenchuk $
+ *
+ */
+public class JbossCacheIndexInfos extends IndexInfos
+{
+
+ private final Cache<Serializable, Object> cache;
+
+ /**
+ * @param cache instance of JbossCache that is used to deliver index names
+ */
+ public JbossCacheIndexInfos(Cache<Serializable, Object> cache)
+ {
+ this(DEFALUT_NAME, cache);
+ }
+
+ /**
+ * @param fileName where index names are stored.
+ * @param cache instance of JbossCache that is used to deliver index names
+ */
+ public JbossCacheIndexInfos(String fileName, Cache<Serializable, Object> cache)
+ {
+ super(fileName);
+ this.cache = cache;
+ }
+
+ @Override
+ public void write() throws IOException
+ {
+ boolean dirty = this.dirty;
+ super.write();
+ if (dirty)
+ {
+ // send to cache new list.
+ }
+ }
+
+}
Property changes on: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/JbossCacheIndexInfos.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/IndexInfos.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/IndexInfos.java 2009-12-23 08:59:41 UTC (rev 1150)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/IndexInfos.java 2009-12-23 10:44:33 UTC (rev 1151)
@@ -33,10 +33,15 @@
/**
* Stores a sequence of index names.
*/
-class IndexInfos
+public class IndexInfos
{
/**
+ * Default file name, that is used if not defined;
+ */
+ public final static String DEFALUT_NAME = "indexes";
+
+ /**
* For new segment names.
*/
protected int counter = 0;
@@ -62,11 +67,19 @@
protected final String name;
/**
- * Used to call-back, when index list is changed
+ * Directory, where index names file is stored.
*/
- protected MultiIndex multiIndex = null;
+ protected Directory dir;
/**
+ * Creates a new IndexInfos using <code>"indexes"</code> as a filename.
+ */
+ public IndexInfos()
+ {
+ this(DEFALUT_NAME);
+ }
+
+ /**
* Creates a new IndexInfos using <code>fileName</code>.
*
* @param fileName the name of the file where infos are stored.
@@ -84,7 +97,7 @@
* @return <code>true</code> if it exists; <code>false</code> otherwise.
* @throws IOException if an error occurs while reading from the directory.
*/
- public boolean exists(Directory dir) throws IOException
+ public boolean exists() throws IOException
{
return dir.fileExists(name);
}
@@ -105,7 +118,7 @@
* @param dir the directory from where to read the index infos.
* @throws IOException if an error occurs.
*/
- public void read(Directory dir) throws IOException
+ public void read() throws IOException
{
InputStream in = new IndexInputStream(dir.openInput(name));
try
@@ -131,7 +144,7 @@
* @param dir the directory where to write the index infos.
* @throws IOException if an error occurs.
*/
- public void write(Directory dir) throws IOException
+ public void write() throws IOException
{
// do not write if not dirty
if (!dirty)
@@ -252,12 +265,11 @@
}
/**
- * Injects MultiIndex instance that is used to callback, when list of indexes if changed.
- * Default implementation (IndexInfos class) actually doesn't use it.
- * @param multiIndex
+ * Sets direcotry, where file with index names is stored.
+ * @param dir
*/
- public void setMultiIndex(MultiIndex multiIndex)
+ public void setDir(Directory dir)
{
- this.multiIndex = multiIndex;
+ this.dir = dir;
}
}
Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/MultiIndex.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/MultiIndex.java 2009-12-23 08:59:41 UTC (rev 1150)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/MultiIndex.java 2009-12-23 10:44:33 UTC (rev 1151)
@@ -86,7 +86,7 @@
/**
* Names of active persistent index directories.
*/
- private IndexInfos indexNames = new IndexInfos("indexes");
+ private IndexInfos indexNames;
/**
* Names of index directories that can be deleted.
@@ -225,7 +225,8 @@
* @throws IOException
* if an error occurs
*/
- MultiIndex(SearchIndex handler, IndexingTree indexingTree, IndexerIoMode ioMode) throws IOException
+ MultiIndex(SearchIndex handler, IndexingTree indexingTree, IndexerIoMode ioMode, IndexInfos indexInfos)
+ throws IOException
{
this.ioMode = ioMode;
this.directoryManager = handler.getDirectoryManager();
@@ -235,9 +236,11 @@
this.indexingTree = indexingTree;
this.nsMappings = handler.getNamespaceMappings();
this.flushTask = null;
- if (indexNames.exists(indexDir))
+ this.indexNames = indexInfos;
+ this.indexNames.setDir(indexDir);
+ if (indexNames.exists())
{
- indexNames.read(indexDir);
+ indexNames.read();
}
// as of 1.5 deletable file is not used anymore
@@ -1053,7 +1056,7 @@
}
executeAndLog(new Commit(getTransactionId()));
- indexNames.write(indexDir);
+ indexNames.write();
// reset redo log
redoLog.clear();
@@ -2430,10 +2433,10 @@
// release reader if any
releaseMultiReader();
// get new indexInfo
- IndexInfos newIndexNames = new IndexInfos("indexes");
- if (newIndexNames.exists(indexDir))
+ IndexInfos newIndexNames = new IndexInfos();
+ if (newIndexNames.exists())
{
- newIndexNames.read(indexDir);
+ newIndexNames.read();
}
// prepare added/removed sets
Set<String> removed = new HashSet<String>(indexNames.getNames());
@@ -2478,7 +2481,7 @@
}
/**
- * Refresh list of indexes. Used to be called from IndexInfos. New, actual list is read from
+ * Refresh list of indexes. Used to be called from CacheLoader. New, actual list is read from
* IndexInfos.
* @throws IOException
*/
Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java 2009-12-23 08:59:41 UTC (rev 1150)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java 2009-12-23 10:44:33 UTC (rev 1151)
@@ -515,7 +515,8 @@
indexingConfig = createIndexingConfiguration(nsMappings);
analyzer.setIndexingConfig(indexingConfig);
- index = new MultiIndex(this, context.getIndexingTree(), ioMode);
+ index =
+ new MultiIndex(this, context.getIndexingTree(), ioMode, indexInfos == null ? new IndexInfos() : indexInfos);
// if RW mode, create initial index and start check
if (ioMode == IndexerIoMode.READ_WRITE)
{
16 years, 7 months
exo-jcr SVN: r1150 - in jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/lab: cluster and 2 other directories.
by do-not-reply@jboss.org
Author: nzamosenchuk
Date: 2009-12-23 03:59:41 -0500 (Wed, 23 Dec 2009)
New Revision: 1150
Added:
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/lab/cluster/
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/lab/cluster/prepare/
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/lab/cluster/prepare/TestFullSearchPrepare.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/lab/cluster/prepare/TestLoadIndexerWriter.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/lab/cluster/prepare/TestQueryPrepare.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/lab/cluster/test/
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/lab/cluster/test/TestFullSearchAssert.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/lab/cluster/test/TestLoadIndexerQuery.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/lab/cluster/test/TestQueryAssert.java
Log:
EXOJCR-325: Manual tests for indexer in cluster ported from JBC branch.
Added: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/lab/cluster/prepare/TestFullSearchPrepare.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/lab/cluster/prepare/TestFullSearchPrepare.java (rev 0)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/lab/cluster/prepare/TestFullSearchPrepare.java 2009-12-23 08:59:41 UTC (rev 1150)
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2009 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.lab.cluster.prepare;
+
+import org.exoplatform.services.jcr.JcrAPIBaseTest;
+import org.exoplatform.services.jcr.impl.core.NodeImpl;
+
+import java.util.Calendar;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+/**
+ * @author <a href="mailto:nikolazius@gmail.com">Nikolay Zamosenchuk</a>
+ * @version $Id: TestFullSearchPrepare.java 34360 2009-07-22 23:58:59Z nzamosenchuk $
+ *
+ */
+public class TestFullSearchPrepare extends JcrAPIBaseTest
+{
+
+ public void testFullSearch() throws RepositoryException
+ {
+ Node doc1 = root.addNode("document1", "nt:file");
+ NodeImpl cont1 = (NodeImpl)doc1.addNode("jcr:content", "nt:resource");
+ cont1.setProperty("jcr:mimeType", "text/plain");
+ cont1.setProperty("jcr:lastModified", Calendar.getInstance());
+ cont1.setProperty("jcr:data", "The quick brown fox jump over the lazy dog");
+ session.save();
+
+ Node doc2 = root.addNode("document2", "nt:file");
+ NodeImpl cont2 = (NodeImpl)doc2.addNode("jcr:content", "nt:resource");
+ cont2.setProperty("jcr:mimeType", "text/plain");
+ cont2.setProperty("jcr:lastModified", Calendar.getInstance());
+ cont2.setProperty("jcr:data", "Dogs do not like cats.");
+
+ Node doc3 = root.addNode("document3", "nt:file");
+ NodeImpl cont3 = (NodeImpl)doc3.addNode("jcr:content", "nt:resource");
+ cont3.setProperty("jcr:mimeType", "text/plain");
+ cont3.setProperty("jcr:lastModified", Calendar.getInstance());
+ cont3.setProperty("jcr:data", "Cats jumping high.");
+ session.save();
+ System.out.println("Done!");
+ try
+ {
+ Thread.sleep(60000);
+ }
+ catch (InterruptedException e)
+ {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ protected void tearDown() throws Exception
+ {
+ // do noting
+ }
+}
Property changes on: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/lab/cluster/prepare/TestFullSearchPrepare.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/lab/cluster/prepare/TestLoadIndexerWriter.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/lab/cluster/prepare/TestLoadIndexerWriter.java (rev 0)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/lab/cluster/prepare/TestLoadIndexerWriter.java 2009-12-23 08:59:41 UTC (rev 1150)
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2009 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.lab.cluster.prepare;
+
+import org.exoplatform.services.jcr.JcrAPIBaseTest;
+import org.exoplatform.services.jcr.core.CredentialsImpl;
+import org.exoplatform.services.jcr.impl.core.SessionImpl;
+
+import java.util.Random;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+/**
+ * @author <a href="mailto:nikolazius@gmail.com">Nikolay Zamosenchuk</a>
+ * @version $Id: TestLoadIndexerWriter.java 34360 2009-07-22 23:58:59Z nzamosenchuk $
+ *
+ */
+public class TestLoadIndexerWriter extends JcrAPIBaseTest
+{
+ public static final String COUNT = "count";
+
+ public static final String CONTENT = "Content";
+
+ public static final String STATISTIC = "Statistic";
+
+ private boolean stop = false;
+
+ private int threadCount = 1;
+
+ private static final String[] words =
+ new String[]{"private", "branch", "final", "string", "logging", "bottle", "property", "node", "repository",
+ "exception", "cycle", "value", "index", "meaning", "strange", "words", "hello", "outline", "finest",
+ "basetest", "writer"};
+
+ public void testWrite() throws RepositoryException
+ {
+ log.info("Creating threads...");
+ for (int i = 0; i < threadCount; i++)
+ {
+ // create new thread and start it
+ new Thread(new WriterTask(i)).start();
+ log.info("Thread#" + i + " created and started.");
+ }
+
+ // wait 4 minutes
+ try
+ {
+ Thread.sleep(60000 * 4);
+ }
+ catch (InterruptedException e)
+ {
+ log.error(e);
+ }
+
+ stop = true;
+ }
+
+ private class WriterTask implements Runnable
+ {
+
+ private int id;
+
+ private SessionImpl sessionLocal;
+
+ private Node statisticNode;
+
+ private Node contentNode;
+
+ private Random random;
+
+ public WriterTask(int id) throws RepositoryException
+ {
+ this.id = id;
+ // login
+ CredentialsImpl credentials = new CredentialsImpl("admin", "admin".toCharArray());
+ sessionLocal = (SessionImpl)repository.login(credentials, "ws");
+ // prepare nodes
+ Node root = sessionLocal.getRootNode();
+ Node threadNode = root.addNode("Thread" + id);
+ statisticNode = threadNode.addNode(STATISTIC);
+ contentNode = threadNode.addNode(CONTENT);
+ random = new Random();
+ sessionLocal.save();
+ }
+
+ /**
+ * @see java.lang.Runnable#run()
+ */
+ public void run()
+ {
+ try
+ {
+ while (!stop)
+ {
+ // get any word
+ int i = random.nextInt(words.length);
+ String word = words[i] + id; // "hello12" if thread#12 is creating it
+ // update statistic
+ updateStatistic(word);
+ // add actual node
+ createTree().addNode(word);
+ sessionLocal.save();
+ System.out.print("#");
+
+ try
+ {
+ Thread.sleep(300);
+ }
+ catch (InterruptedException e)
+ {
+ }
+ }
+ }
+ catch (RepositoryException e)
+ {
+ log.error(e);
+ }
+ }
+
+ /**
+ * increments property in JCR: "./statistic/[word].count"
+ *
+ * @param word
+ * @throws RepositoryException
+ */
+ private void updateStatistic(String word) throws RepositoryException
+ {
+ Node wordNode;
+ long count = 0;
+ if (statisticNode.hasNode(word))
+ {
+ wordNode = statisticNode.getNode(word);
+ count = wordNode.getProperty(COUNT).getLong();
+ }
+ else
+ {
+ wordNode = statisticNode.addNode(word);
+ }
+ wordNode.setProperty(COUNT, count + 1);
+ }
+
+ /**
+ * Created node tree like: "./content/n123456/n1234567/n12345678"
+ * based on current time
+ *
+ * @return
+ * @throws RepositoryException
+ */
+ private Node createTree() throws RepositoryException
+ {
+ // created node tree like: "./content/n123456/n1234567/n12345678"
+ Node end;
+ long time = System.currentTimeMillis();
+ long child1 = time / 100000; // each 100s new node
+ long child2 = time / 10000; // each 10s new node
+ long child3 = time / 1000; // each 1s new node
+ end = addOrCreate("n" + child1, contentNode);
+ end = addOrCreate("n" + child2, end);
+ end = addOrCreate("n" + child3, end);
+ return end;
+ }
+
+ /**
+ * Gets or creates node
+ *
+ * @param name
+ * @param parent
+ * @return
+ * @throws RepositoryException
+ */
+ private Node addOrCreate(String name, Node parent) throws RepositoryException
+ {
+ if (parent.hasNode(name))
+ {
+ return parent.getNode(name);
+ }
+ else
+ return parent.addNode(name);
+ }
+ }
+
+}
Property changes on: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/lab/cluster/prepare/TestLoadIndexerWriter.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/lab/cluster/prepare/TestQueryPrepare.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/lab/cluster/prepare/TestQueryPrepare.java (rev 0)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/lab/cluster/prepare/TestQueryPrepare.java 2009-12-23 08:59:41 UTC (rev 1150)
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2009 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.lab.cluster.prepare;
+
+import org.exoplatform.services.jcr.JcrAPIBaseTest;
+import org.exoplatform.services.jcr.impl.core.NodeImpl;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.Calendar;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+/**
+ * @author <a href="mailto:nikolazius@gmail.com">Nikolay Zamosenchuk</a>
+ * @version $Id: TestQueryPrepare.java 34360 2009-07-22 23:58:59Z nzamosenchuk $
+ *
+ */
+public class TestQueryPrepare extends JcrAPIBaseTest
+{
+ public void testPrepareNodes() throws RepositoryException, IOException
+ {
+ System.out.println("preparing....");
+
+ root.addNode("simplenode", "nt:unstructured");
+
+ Node doc1 = root.addNode("document1", "nt:file");
+ NodeImpl cont = (NodeImpl)doc1.addNode("jcr:content", "nt:resource");
+ cont.setProperty("jcr:mimeType", "text/plain");
+ cont.setProperty("jcr:lastModified", Calendar.getInstance());
+ cont.setProperty("jcr:encoding", "UTF-8");
+ cont.setProperty("jcr:data", new ByteArrayInputStream("".getBytes()));
+
+ Node doc2 = root.addNode("document2", "nt:file");
+ cont = (NodeImpl)doc2.addNode("jcr:content", "nt:resource");
+ cont.setProperty("jcr:mimeType", "text/plain");
+ cont.setProperty("jcr:lastModified", Calendar.getInstance());
+ cont.setProperty("jcr:encoding", "UTF-8");
+ cont.setProperty("jcr:data", new ByteArrayInputStream("".getBytes()));
+ session.save();
+ System.out.println("Done!");
+ try
+ {
+ Thread.sleep(60000);
+ }
+ catch (InterruptedException e)
+ {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ protected void tearDown() throws Exception
+ {
+ // do noting
+ }
+}
Property changes on: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/lab/cluster/prepare/TestQueryPrepare.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/lab/cluster/test/TestFullSearchAssert.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/lab/cluster/test/TestFullSearchAssert.java (rev 0)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/lab/cluster/test/TestFullSearchAssert.java 2009-12-23 08:59:41 UTC (rev 1150)
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2009 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.lab.cluster.test;
+
+import org.exoplatform.services.jcr.JcrAPIBaseTest;
+import org.exoplatform.services.jcr.impl.core.NodeImpl;
+
+import java.util.Calendar;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryManager;
+import javax.jcr.query.QueryResult;
+import javax.jcr.query.Row;
+import javax.jcr.query.RowIterator;
+
+/**
+ * @author <a href="mailto:nikolazius@gmail.com">Nikolay Zamosenchuk</a>
+ * @version $Id: TestFullSearchAssert.java 34360 2009-07-22 23:58:59Z nzamosenchuk $
+ *
+ */
+public class TestFullSearchAssert extends JcrAPIBaseTest
+{
+
+ public void testFullSearch() throws RepositoryException
+ {
+ Node cont1 = root.getNode("document1/jcr:content");
+ Node cont2 = root.getNode("document2/jcr:content");
+ Node cont3 = root.getNode("document3/jcr:content");
+
+ // make SQL query
+ QueryManager qman = this.workspace.getQueryManager();
+
+ Query q = qman.createQuery("SELECT * FROM nt:resource WHERE CONTAINS(*,'do')", Query.SQL);
+ QueryResult res = q.execute();
+ long sqlsize = res.getNodes().getSize();
+ assertEquals(1, sqlsize);
+ checkResult(res, new Node[]{cont2});
+
+ //make XPath query
+ Query xq = qman.createQuery("//element(*,nt:resource)[jcr:contains(.,'cats')]", Query.XPATH);
+ QueryResult xres = xq.execute();
+ long xpathsize = xres.getNodes().getSize();
+ assertEquals(2, xpathsize);
+ checkResult(xres, new Node[]{cont2, cont3});
+ System.out.println("Done!");
+ try
+ {
+ Thread.sleep(60000);
+ }
+ catch (InterruptedException e)
+ {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ protected void checkResult(QueryResult result, Node[] nodes) throws RepositoryException
+ {
+ // collect paths
+
+ String[] columnNames = result.getColumnNames();
+ String[][] vals = new String[(int)result.getNodes().getSize()][result.getColumnNames().length];
+
+ RowIterator rit = result.getRows();
+ int j = 0;
+ while (rit.hasNext())
+ {
+ Row r = rit.nextRow();
+ Value[] v = r.getValues();
+ for (int i = 0; i < v.length; i++)
+ {
+ vals[j][i] = (v[i] != null) ? v[i].getString() : "null";
+ }
+ j++;
+ }
+
+ Set<String> expectedPaths = new HashSet<String>();
+ for (int i = 0; i < nodes.length; i++)
+ {
+ expectedPaths.add(nodes[i].getPath());
+ }
+ Set<String> resultPaths = new HashSet<String>();
+ for (NodeIterator it = result.getNodes(); it.hasNext();)
+ {
+ resultPaths.add(it.nextNode().getPath());
+ }
+
+ comparePaths(expectedPaths, resultPaths, false);
+ }
+
+ private void comparePaths(Set<String> expectedPaths, Set<String> resultPaths, boolean canContainMore)
+ {
+ // check if all expected are in result
+ for (Iterator<String> it = expectedPaths.iterator(); it.hasNext();)
+ {
+ String path = it.next();
+ assertTrue(path + " is not part of the result set", resultPaths.contains(path));
+ }
+
+ if (!canContainMore)
+ {
+ // check result does not contain more than expected
+
+ for (Iterator<String> it = resultPaths.iterator(); it.hasNext();)
+ {
+ String path = it.next();
+ assertTrue(path + " is not expected to be part of the result set. " + " Total size:" + resultPaths.size(),
+ expectedPaths.contains(path));
+ }
+ }
+ }
+
+ @Override
+ protected void tearDown() throws Exception
+ {
+ // do noting
+ }
+}
Property changes on: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/lab/cluster/test/TestFullSearchAssert.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/lab/cluster/test/TestLoadIndexerQuery.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/lab/cluster/test/TestLoadIndexerQuery.java (rev 0)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/lab/cluster/test/TestLoadIndexerQuery.java 2009-12-23 08:59:41 UTC (rev 1150)
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2009 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.lab.cluster.test;
+
+import junit.framework.AssertionFailedError;
+
+import org.exoplatform.services.jcr.JcrAPIBaseTest;
+import org.exoplatform.services.jcr.core.CredentialsImpl;
+import org.exoplatform.services.jcr.impl.core.SessionImpl;
+import org.exoplatform.services.jcr.lab.cluster.prepare.TestLoadIndexerWriter;
+
+import java.util.Random;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryManager;
+import javax.jcr.query.QueryResult;
+
+/**
+ * @author <a href="mailto:nikolazius@gmail.com">Nikolay Zamosenchuk</a>
+ * @version $Id: TestLoadIndexerQuery.java 34360 2009-07-22 23:58:59Z nzamosenchuk $
+ *
+ */
+public class TestLoadIndexerQuery extends JcrAPIBaseTest
+{
+ private boolean stop = false;
+
+ private int threadCount = 1;
+
+ public void testQuery() throws RepositoryException
+ {
+ log.info("Creating threads...");
+ for (int i = 0; i < threadCount; i++)
+ {
+ // create new thread and start it
+ new Thread(new QueryTask()).start();
+ log.info("Thread#" + i + " created and started.");
+ }
+
+ // wait 4 minutes
+ try
+ {
+ Thread.sleep(60000 * 4);
+ }
+ catch (InterruptedException e)
+ {
+ log.error(e);
+ }
+
+ stop = true;
+ }
+
+ private class QueryTask implements Runnable
+ {
+ private SessionImpl sessionLocal;
+
+ private Node rootLocal;
+
+ private Random random;
+
+ public QueryTask() throws RepositoryException
+ {
+ // login
+ CredentialsImpl credentials = new CredentialsImpl("admin", "admin".toCharArray());
+ sessionLocal = (SessionImpl)repository.login(credentials, "ws");
+ // prepare nodes
+ rootLocal = sessionLocal.getRootNode();
+ random = new Random();
+ }
+
+ /**
+ * @see java.lang.Runnable#run()
+ */
+ public void run()
+ {
+ try
+ {
+ while (!stop)
+ {
+ Node threadNode = getRandomChild(rootLocal, "Thread*");
+ if (threadNode != null)
+ {
+ Node statisticNode = threadNode.getNode(TestLoadIndexerWriter.STATISTIC);
+ Node wordNode = getRandomChild(statisticNode, "*");
+ if (wordNode != null)
+ {
+ String word = wordNode.getName();
+ Long count = wordNode.getProperty(TestLoadIndexerWriter.COUNT).getLong();
+
+ QueryManager qman = sessionLocal.getWorkspace().getQueryManager();
+
+ Query q = qman.createQuery("SELECT * FROM nt:base WHERE fn:name() = '" + word + "'", Query.SQL);
+ QueryResult res = q.execute();
+ long sqlsize = res.getNodes().getSize();
+ try
+ {
+ assertTrue("Exp: "+count+"\t found:"+sqlsize, sqlsize >= count);
+ System.out.print("+("+sqlsize+")");
+ }
+ catch (AssertionFailedError e)
+ {
+ System.out.println("-"+e.getMessage());
+ }
+ }
+ }
+ }
+
+ }
+ catch (RepositoryException e)
+ {
+ log.error(e);
+ }
+ }
+
+ private Node getRandomChild(Node parent, String pattern) throws RepositoryException
+ {
+ NodeIterator iterator = parent.getNodes(pattern);
+ if (iterator.getSize() < 1)
+ {
+ return null;
+ }
+ int i = random.nextInt((int)iterator.getSize());
+ iterator.skip(i);
+ return iterator.nextNode();
+ }
+ }
+}
Property changes on: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/lab/cluster/test/TestLoadIndexerQuery.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/lab/cluster/test/TestQueryAssert.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/lab/cluster/test/TestQueryAssert.java (rev 0)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/lab/cluster/test/TestQueryAssert.java 2009-12-23 08:59:41 UTC (rev 1150)
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2009 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.lab.cluster.test;
+
+import org.exoplatform.services.jcr.JcrAPIBaseTest;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryManager;
+import javax.jcr.query.QueryResult;
+import javax.jcr.query.Row;
+import javax.jcr.query.RowIterator;
+
+/**
+ * @author <a href="mailto:nikolazius@gmail.com">Nikolay Zamosenchuk</a>
+ * @version $Id: TestQueryAssert.java 34360 2009-07-22 23:58:59Z nzamosenchuk $
+ *
+ */
+public class TestQueryAssert extends JcrAPIBaseTest
+{
+ public void testAssert() throws RepositoryException, IOException
+ {
+ System.out.println("Start asserting....");
+
+ Node doc1 = root.getNode("document1");
+ Node doc2 = root.getNode("document2");
+
+ // make SQL query
+ QueryManager qman = this.workspace.getQueryManager();
+
+ Query q = qman.createQuery("SELECT * FROM nt:file ", Query.SQL);
+ QueryResult res = q.execute();
+ long sqlsize = res.getNodes().getSize();
+ assertEquals(2, sqlsize);
+ checkResult(res, new Node[]{doc1, doc2});
+
+ //make XPath query
+
+ Query xq = qman.createQuery("//element(*,nt:file)", Query.XPATH);
+ QueryResult xres = xq.execute();
+ long xpathsize = xres.getNodes().getSize();
+ assertEquals(2, xpathsize);
+ checkResult(xres, new Node[]{doc1, doc2});
+ System.out.println("Done!");
+ try
+ {
+ Thread.sleep(60000);
+ }
+ catch (InterruptedException e)
+ {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ protected void checkResult(QueryResult result, Node[] nodes) throws RepositoryException
+ {
+ // collect paths
+
+ String[] columnNames = result.getColumnNames();
+ String[][] vals = new String[(int)result.getNodes().getSize()][result.getColumnNames().length];
+
+ RowIterator rit = result.getRows();
+ int j = 0;
+ while (rit.hasNext())
+ {
+ Row r = rit.nextRow();
+ Value[] v = r.getValues();
+ for (int i = 0; i < v.length; i++)
+ {
+ vals[j][i] = (v[i] != null) ? v[i].getString() : "null";
+ }
+ j++;
+ }
+
+ Set<String> expectedPaths = new HashSet<String>();
+ for (int i = 0; i < nodes.length; i++)
+ {
+ expectedPaths.add(nodes[i].getPath());
+ }
+ Set<String> resultPaths = new HashSet<String>();
+ for (NodeIterator it = result.getNodes(); it.hasNext();)
+ {
+ resultPaths.add(it.nextNode().getPath());
+ }
+
+ comparePaths(expectedPaths, resultPaths, false);
+ }
+
+ private void comparePaths(Set<String> expectedPaths, Set<String> resultPaths, boolean canContainMore)
+ {
+ // check if all expected are in result
+ for (Iterator<String> it = expectedPaths.iterator(); it.hasNext();)
+ {
+ String path = it.next();
+ assertTrue(path + " is not part of the result set", resultPaths.contains(path));
+ }
+
+ if (!canContainMore)
+ {
+ // check result does not contain more than expected
+
+ for (Iterator<String> it = resultPaths.iterator(); it.hasNext();)
+ {
+ String path = it.next();
+ assertTrue(path + " is not expected to be part of the result set. " + " Total size:" + resultPaths.size(),
+ expectedPaths.contains(path));
+ }
+ }
+ }
+
+ @Override
+ protected void tearDown() throws Exception
+ {
+ // do noting
+ }
+}
Property changes on: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/lab/cluster/test/TestQueryAssert.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
16 years, 7 months
exo-jcr SVN: r1148 - in jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation: db and 1 other directory.
by do-not-reply@jboss.org
Author: sergiykarpenko
Date: 2009-12-22 11:44:55 -0500 (Tue, 22 Dec 2009)
New Revision: 1148
Modified:
jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/DBConstants.java
jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/NewJDBCStorageConnection.java
jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/MultiDbJDBCConnection.java
jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/SingleDbJDBCConnection.java
Log:
EXOJCR-302: GET_PROPERTIES_BY_PARENTID fixed and FIND_REFERENCE_PROPERTIES query added
Modified: jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/DBConstants.java
===================================================================
--- jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/DBConstants.java 2009-12-22 16:31:07 UTC (rev 1147)
+++ jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/DBConstants.java 2009-12-22 16:44:55 UTC (rev 1148)
@@ -119,6 +119,8 @@
*/
protected String FIND_REFERENCES;
+ protected String FIND_REFERENCE_PROPERTIES;
+
/**
* FIND_VALUES_BY_PROPERTYID.
*/
Modified: jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/NewJDBCStorageConnection.java
===================================================================
--- jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/NewJDBCStorageConnection.java 2009-12-22 16:31:07 UTC (rev 1147)
+++ jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/NewJDBCStorageConnection.java 2009-12-22 16:44:55 UTC (rev 1148)
@@ -636,21 +636,17 @@
checkIfOpened();
try
{
- ResultSet prop = findChildPropertiesByParentIdentifier(getInternalId(parent.getIdentifier()));
+
+ ResultSet resultSet = getChildPropertiesByParentIdentifier(getInternalId(parent.getIdentifier()));
List<PropertyData> children = new ArrayList<PropertyData>();
- while (prop.next())
- children.add((PropertyData)itemData(parent.getQPath(), prop, I_CLASS_PROPERTY, null));
+ if (resultSet.next())
+ {
+ while (!resultSet.isAfterLast())
+ children.add(loadPropertyRecord(resultSet, parent.getQPath()));
+ }
return children;
- //TODO mine
- // ResultSet prop = getChildPropertiesByParentIdentifier(getInternalId(parent.getIdentifier()));
- // List<PropertyData> children = new ArrayList<PropertyData>();
- // while (prop.next())
- // children.add(loadPropertyRecord(prop, parent.getQPath()));
- //
- // return children;
-
}
catch (SQLException e)
{
@@ -723,6 +719,15 @@
{
references.add((PropertyData)itemData(null, refProps, I_CLASS_PROPERTY, null));
}
+
+ ResultSet resultSet = findReferenceProperties(getInternalId(nodeIdentifier));
+ references = new ArrayList<PropertyData>(); //List<PropertyData>
+ if (resultSet.next())
+ {
+ while (!resultSet.isAfterLast())
+ references.add(loadPropertyRecord(resultSet, null));
+ }
+
return references;
}
catch (SQLException e)
@@ -2262,4 +2267,6 @@
protected abstract ResultSet findChildNodesByParentIdentifierNew(String parentIdentifier) throws SQLException;
protected abstract ResultSet getChildPropertiesByParentIdentifier(String parentIdentifier) throws SQLException;
+
+ protected abstract ResultSet findReferenceProperties(String parentIdentifier) throws SQLException;
}
Modified: jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/MultiDbJDBCConnection.java
===================================================================
--- jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/MultiDbJDBCConnection.java 2009-12-22 16:31:07 UTC (rev 1147)
+++ jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/MultiDbJDBCConnection.java 2009-12-22 16:44:55 UTC (rev 1148)
@@ -71,6 +71,8 @@
protected PreparedStatement findReferences;
+ protected PreparedStatement findReferenceProperties;
+
protected PreparedStatement findValuesByPropertyId;
protected PreparedStatement findValuesDataByPropertyId;
@@ -206,6 +208,11 @@
"select P.ID, P.PARENT_ID, P.VERSION, P.P_TYPE, P.P_MULTIVALUED, P.NAME" + " from JCR_MREF R, JCR_MITEM P"
+ " where R.NODE_ID=? and P.ID=R.PROPERTY_ID and P.I_CLASS=2";
+ FIND_REFERENCE_PROPERTIES =
+ "select P.ID, P.PARENT_ID, P.VERSION, P.P_TYPE, P.P_MULTIVALUED, P.NAME, V.ORDER_NUM, V.DATA, V.STORAGE_DESC"
+ + " from JCR_MREF R, JCR_MITEM P, JCR_MVALUE V"
+ + " where R.NODE_ID=? and P.ID=R.PROPERTY_ID and P.I_CLASS=2 and V.PROPERTY_ID=P.ID order by P.ID, V.ORDER_NUM";
+
FIND_VALUES_BY_PROPERTYID =
"select PROPERTY_ID, ORDER_NUM, DATA, STORAGE_DESC from JCR_MVALUE where PROPERTY_ID=? order by ORDER_NUM";
@@ -226,9 +233,14 @@
FIND_PROPERTIES_BY_PARENTID = "select * from JCR_MITEM" + " where I_CLASS=2 and PARENT_ID=?" + " order by ID";
+ //TODO this query is incorrect because property may have not value
+ // GET_PROPERTIES_BY_PARENTID =
+ // "select I.*, V.ORDER_NUM, V.DATA, V.STORAGE_DESC from JCR_MITEM I, JCR_MVALUE V"
+ // + " where I.I_CLASS=2 and I.PARENT_ID=? and V.PROPERTY_ID=I.ID order by I.ID";
+
GET_PROPERTIES_BY_PARENTID =
- "select I.*, V.ORDER_NUM, V.DATA, V.STORAGE_DESC from JCR_MITEM I, JCR_MVALUE V"
- + " where I.I_CLASS=2 and I.PARENT_ID=? and V.PROPERTY_ID=I.ID order by I.ID";
+ "select I.*, V.ORDER_NUM, V.DATA, V.STORAGE_DESC from JCR_MITEM I LEFT OUTER JOIN JCR_MVALUE V ON (V.PROPERTY_ID=I.ID)"
+ + " where I.I_CLASS=2 and I.PARENT_ID=? order by ID, ORDER_NUM";
INSERT_NODE =
"insert into JCR_MITEM(ID, PARENT_ID, NAME, VERSION, I_CLASS, I_INDEX, N_ORDER_NUM) VALUES(?,?,?,?,"
@@ -662,4 +674,16 @@
getPropertiesByParentId.setString(1, parentIdentifier);
return getPropertiesByParentId.executeQuery();
}
+
+ @Override
+ protected ResultSet findReferenceProperties(String nodeIdentifier) throws SQLException
+ {
+ if (findReferenceProperties == null)
+ findReferenceProperties = dbConnection.prepareStatement(FIND_REFERENCE_PROPERTIES);
+ else
+ findReferenceProperties.clearParameters();
+
+ findReferenceProperties.setString(1, nodeIdentifier);
+ return findReferenceProperties.executeQuery();
+ }
}
Modified: jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/SingleDbJDBCConnection.java
===================================================================
--- jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/SingleDbJDBCConnection.java 2009-12-22 16:31:07 UTC (rev 1147)
+++ jcr/branches/1.12.0-OPT/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/SingleDbJDBCConnection.java 2009-12-22 16:44:55 UTC (rev 1148)
@@ -634,4 +634,11 @@
return null;
}
+ @Override
+ protected ResultSet findReferenceProperties(String parentIdentifier) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
}
16 years, 7 months
exo-jcr SVN: r1147 - jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene.
by do-not-reply@jboss.org
Author: nzamosenchuk
Date: 2009-12-22 11:31:07 -0500 (Tue, 22 Dec 2009)
New Revision: 1147
Modified:
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/IndexInfos.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/MultiIndex.java
Log:
EXOJCR-327: changed visibility of IndexInfos's methods from "default" to public because other implementations may be situated in other packages. MultiIndex class is extended with new method, used to update indexLists.
Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/IndexInfos.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/IndexInfos.java 2009-12-22 16:01:28 UTC (rev 1146)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/IndexInfos.java 2009-12-22 16:31:07 UTC (rev 1147)
@@ -33,191 +33,231 @@
/**
* Stores a sequence of index names.
*/
-class IndexInfos {
+class IndexInfos
+{
- /**
- * For new segment names.
- */
- private int counter = 0;
+ /**
+ * For new segment names.
+ */
+ protected int counter = 0;
- /**
- * Flag that indicates if index infos needs to be written to disk.
- */
- private boolean dirty = false;
+ /**
+ * Flag that indicates if index infos needs to be written to disk.
+ */
+ protected boolean dirty = false;
- /**
- * List of index names
- */
- private List indexes = new ArrayList();
+ /**
+ * List of index names
+ */
+ protected List indexes = new ArrayList();
- /**
- * Set of names for quick lookup.
- */
- private Set names = new HashSet();
+ /**
+ * Set of names for quick lookup.
+ */
+ protected Set names = new HashSet();
- /**
- * Name of the file where the infos are stored.
- */
- private final String name;
+ /**
+ * Name of the file where the infos are stored.
+ */
+ protected final String name;
- /**
- * Creates a new IndexInfos using <code>fileName</code>.
- *
- * @param fileName the name of the file where infos are stored.
- */
- IndexInfos(String fileName) {
- this.name = fileName;
- }
+ /**
+ * Used to call-back, when index list is changed
+ */
+ protected MultiIndex multiIndex = null;
- /**
- * Returns <code>true</code> if this index infos exists in
- * <code>dir</code>.
- *
- * @param dir the directory where to look for the index infos.
- * @return <code>true</code> if it exists; <code>false</code> otherwise.
- * @throws IOException if an error occurs while reading from the directory.
- */
- boolean exists(Directory dir) throws IOException {
- return dir.fileExists(name);
- }
+ /**
+ * Creates a new IndexInfos using <code>fileName</code>.
+ *
+ * @param fileName the name of the file where infos are stored.
+ */
+ public IndexInfos(String fileName)
+ {
+ this.name = fileName;
+ }
- /**
- * Returns the name of the file where infos are stored.
- *
- * @return the name of the file where infos are stored.
- */
- String getFileName() {
- return name;
- }
+ /**
+ * Returns <code>true</code> if this index infos exists in
+ * <code>dir</code>.
+ *
+ * @param dir the directory where to look for the index infos.
+ * @return <code>true</code> if it exists; <code>false</code> otherwise.
+ * @throws IOException if an error occurs while reading from the directory.
+ */
+ public boolean exists(Directory dir) throws IOException
+ {
+ return dir.fileExists(name);
+ }
- /**
- * Reads the index infos.
- *
- * @param dir the directory from where to read the index infos.
- * @throws IOException if an error occurs.
- */
- void read(Directory dir) throws IOException {
- InputStream in = new IndexInputStream(dir.openInput(name));
- try {
- DataInputStream di = new DataInputStream(in);
- counter = di.readInt();
- for (int i = di.readInt(); i > 0; i--) {
- String indexName = di.readUTF();
- indexes.add(indexName);
- names.add(indexName);
- }
- } finally {
- in.close();
- }
- }
+ /**
+ * Returns the name of the file where infos are stored.
+ *
+ * @return the name of the file where infos are stored.
+ */
+ public String getFileName()
+ {
+ return name;
+ }
- /**
- * Writes the index infos to disk if they are dirty.
- *
- * @param dir the directory where to write the index infos.
- * @throws IOException if an error occurs.
- */
- void write(Directory dir) throws IOException {
- // do not write if not dirty
- if (!dirty) {
- return;
- }
+ /**
+ * Reads the index infos.
+ *
+ * @param dir the directory from where to read the index infos.
+ * @throws IOException if an error occurs.
+ */
+ public void read(Directory dir) throws IOException
+ {
+ InputStream in = new IndexInputStream(dir.openInput(name));
+ try
+ {
+ DataInputStream di = new DataInputStream(in);
+ counter = di.readInt();
+ for (int i = di.readInt(); i > 0; i--)
+ {
+ String indexName = di.readUTF();
+ indexes.add(indexName);
+ names.add(indexName);
+ }
+ }
+ finally
+ {
+ in.close();
+ }
+ }
- OutputStream out = new IndexOutputStream(dir.createOutput(name + ".new"));
- try {
- DataOutputStream dataOut = new DataOutputStream(out);
- dataOut.writeInt(counter);
- dataOut.writeInt(indexes.size());
- for (int i = 0; i < indexes.size(); i++) {
- dataOut.writeUTF(getName(i));
- }
- } finally {
- out.close();
- }
- // delete old
- if (dir.fileExists(name)) {
- dir.deleteFile(name);
- }
- dir.renameFile(name + ".new", name);
- dirty = false;
- }
+ /**
+ * Writes the index infos to disk if they are dirty.
+ *
+ * @param dir the directory where to write the index infos.
+ * @throws IOException if an error occurs.
+ */
+ public void write(Directory dir) throws IOException
+ {
+ // do not write if not dirty
+ if (!dirty)
+ {
+ return;
+ }
- /**
- * Returns the index name at position <code>i</code>.
- * @param i the position.
- * @return the index name.
- */
- String getName(int i) {
- return (String) indexes.get(i);
- }
+ OutputStream out = new IndexOutputStream(dir.createOutput(name + ".new"));
+ try
+ {
+ DataOutputStream dataOut = new DataOutputStream(out);
+ dataOut.writeInt(counter);
+ dataOut.writeInt(indexes.size());
+ for (int i = 0; i < indexes.size(); i++)
+ {
+ dataOut.writeUTF(getName(i));
+ }
+ }
+ finally
+ {
+ out.close();
+ }
+ // delete old
+ if (dir.fileExists(name))
+ {
+ dir.deleteFile(name);
+ }
+ dir.renameFile(name + ".new", name);
+ dirty = false;
+ }
- /**
- * Returns the index name at position <code>i</code>.
- * @param i the position.
- * @return the index name.
- */
- Set<String> getNames() {
- return new HashSet<String>(indexes);
- }
-
- /**
- * Returns the number of index names.
- * @return the number of index names.
- */
- int size() {
- return indexes.size();
- }
+ /**
+ * Returns the index name at position <code>i</code>.
+ * @param i the position.
+ * @return the index name.
+ */
+ public String getName(int i)
+ {
+ return (String)indexes.get(i);
+ }
- /**
- * Adds a name to the index infos.
- * @param name the name to add.
- */
- void addName(String name) {
- if (names.contains(name)) {
- throw new IllegalArgumentException("already contains: " + name);
- }
- indexes.add(name);
- names.add(name);
- dirty = true;
- }
+ /**
+ * Returns the index name at position <code>i</code>.
+ * @param i the position.
+ * @return the index name.
+ */
+ public Set<String> getNames()
+ {
+ return new HashSet<String>(indexes);
+ }
- /**
- * Removes the name from the index infos.
- * @param name the name to remove.
- */
- void removeName(String name) {
- indexes.remove(name);
- names.remove(name);
- dirty = true;
- }
+ /**
+ * Returns the number of index names.
+ * @return the number of index names.
+ */
+ public int size()
+ {
+ return indexes.size();
+ }
- /**
- * Removes the name from the index infos.
- * @param i the position.
- */
- void removeName(int i) {
- Object name = indexes.remove(i);
- names.remove(name);
- dirty = true;
- }
+ /**
+ * Adds a name to the index infos.
+ * @param name the name to add.
+ */
+ public void addName(String name)
+ {
+ if (names.contains(name))
+ {
+ throw new IllegalArgumentException("already contains: " + name);
+ }
+ indexes.add(name);
+ names.add(name);
+ dirty = true;
+ }
- /**
- * Returns <code>true</code> if <code>name</code> exists in this
- * <code>IndexInfos</code>; <code>false</code> otherwise.
- *
- * @param name the name to test existence.
- * @return <code>true</code> it is exists in this <code>IndexInfos</code>.
- */
- boolean contains(String name) {
- return names.contains(name);
- }
+ /**
+ * Removes the name from the index infos.
+ * @param name the name to remove.
+ */
+ public void removeName(String name)
+ {
+ indexes.remove(name);
+ names.remove(name);
+ dirty = true;
+ }
- /**
- * Returns a new unique name for an index folder.
- * @return a new unique name for an index folder.
- */
- String newName() {
- dirty = true;
- return "_" + Integer.toString(counter++, Character.MAX_RADIX);
- }
+ /**
+ * Removes the name from the index infos.
+ * @param i the position.
+ */
+ public void removeName(int i)
+ {
+ Object name = indexes.remove(i);
+ names.remove(name);
+ dirty = true;
+ }
+
+ /**
+ * Returns <code>true</code> if <code>name</code> exists in this
+ * <code>IndexInfos</code>; <code>false</code> otherwise.
+ *
+ * @param name the name to test existence.
+ * @return <code>true</code> it is exists in this <code>IndexInfos</code>.
+ */
+ public boolean contains(String name)
+ {
+ return names.contains(name);
+ }
+
+ /**
+ * Returns a new unique name for an index folder.
+ * @return a new unique name for an index folder.
+ */
+ public String newName()
+ {
+ dirty = true;
+ return "_" + Integer.toString(counter++, Character.MAX_RADIX);
+ }
+
+ /**
+ * Injects MultiIndex instance that is used to callback, when list of indexes if changed.
+ * Default implementation (IndexInfos class) actually doesn't use it.
+ * @param multiIndex
+ */
+ public void setMultiIndex(MultiIndex multiIndex)
+ {
+ this.multiIndex = multiIndex;
+ }
}
Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/MultiIndex.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/MultiIndex.java 2009-12-22 16:01:28 UTC (rev 1146)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/MultiIndex.java 2009-12-22 16:31:07 UTC (rev 1147)
@@ -835,7 +835,7 @@
for (int i = 0; i < indexes.size(); i++)
{
PersistentIndex pIdx = (PersistentIndex)indexes.get(i);
-
+
if (indexNames.contains(pIdx.getName()))
{
try
@@ -844,9 +844,10 @@
}
catch (FileNotFoundException e)
{
- if(directoryManager.hasDirectory(pIdx.getName())){
- throw e;
- }
+ if (directoryManager.hasDirectory(pIdx.getName()))
+ {
+ throw e;
+ }
}
}
}
@@ -2417,8 +2418,12 @@
/**
* Temporary solution for indexer in cluster. This method re-reads list of indexes from FS.
- * @throws IOException
+ * @Deprecated, because new implementation is in the development. IndexInfos class will now callback
+ * method {@link MultiIndex#refreshIndexList()}. Will be removed, when jBossCacheIndexInfos is
+ * introduced.
+ * @throws IOException
*/
+ @Deprecated
protected void refreshIndexesList() throws IOException
{
log.info("Refreshing list of indexes...");
@@ -2436,7 +2441,7 @@
Set<String> added = new HashSet<String>(newIndexNames.getNames());
added.removeAll(indexNames.getNames());
-
+
// remove removed indexes
Iterator<PersistentIndex> iterator = indexes.iterator();
while (iterator.hasNext())
@@ -2471,4 +2476,63 @@
}
indexNames = newIndexNames;
}
+
+ /**
+ * Refresh list of indexes. Used to be called from IndexInfos. New, actual list is read from
+ * IndexInfos.
+ * @throws IOException
+ */
+ public void refreshIndexList() throws IOException
+ {
+ // TODO: re-study synchronization here.
+ synchronized (updateMonitor)
+ {
+ log.info("Refreshing list of indexes...");
+ // release reader if any
+ releaseMultiReader();
+ // prepare added/removed sets
+ Set<String> newList = new HashSet<String>(indexNames.getNames());
+
+ // remove removed indexes
+ Iterator<PersistentIndex> iterator = indexes.iterator();
+ while (iterator.hasNext())
+ {
+ PersistentIndex index = iterator.next();
+ String name = ((PersistentIndex)index).getName();
+ // if current index not in new list, close it, cause it is deleted.
+ if (!newList.contains(name))
+ {
+ ((PersistentIndex)index).close();
+ iterator.remove();
+ }
+ else
+ {
+ // remove from list, cause this segment of index still present and indexes list contains
+ // PersistentIndex instance related to this index..
+ newList.remove(name);
+ }
+ }
+ // now newList contains ONLY new, added indexes, deleted indexes, are removed from list.
+ for (String name : newList)
+ {
+ // only open if it still exists
+ // it is possible that indexNames still contains a name for
+ // an index that has been deleted, but indexNames has not been
+ // written to disk.
+ if (!directoryManager.hasDirectory(name))
+ {
+ log.debug("index does not exist anymore: " + name);
+ // move on to next index
+ continue;
+ }
+ PersistentIndex index =
+ new PersistentIndex(name, handler.getTextAnalyzer(), handler.getSimilarity(), cache, indexingQueue,
+ directoryManager);
+ index.setMaxFieldLength(handler.getMaxFieldLength());
+ index.setUseCompoundFile(handler.getUseCompoundFile());
+ index.setTermInfosIndexDivisor(handler.getTermInfosIndexDivisor());
+ indexes.add(index);
+ }
+ }
+ }
}
16 years, 7 months
exo-jcr SVN: r1146 - jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene.
by do-not-reply@jboss.org
Author: nzamosenchuk
Date: 2009-12-22 11:01:28 -0500 (Tue, 22 Dec 2009)
New Revision: 1146
Modified:
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/LuceneQueryBuilder.java
Log:
EXOJCR-325: merge with JBC branch. THIS COMMIT RESTORES FIXED VERSION OF LUCENEQUERYBUILDER, WHICH WAS REWRITTEN BY OLDER VERSION FROM JBC BRANCH.
Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/LuceneQueryBuilder.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/LuceneQueryBuilder.java 2009-12-22 15:42:52 UTC (rev 1145)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/LuceneQueryBuilder.java 2009-12-22 16:01:28 UTC (rev 1146)
@@ -775,18 +775,27 @@
}, null);
QPath relPath = node.getRelativePath();
+
+ InternalQName propName;
+
if (node.getOperation() == QueryConstants.OPERATION_SIMILAR)
{
// this is a bit ugly:
// add the name of a dummy property because relPath actually
// references a property. whereas the relPath of the similar
// operation references a node
- relPath = QPath.makeChildPath(relPath, Constants.JCR_PRIMARYTYPE);
+ //relPath = QPath.makeChildPath(relPath, Constants.JCR_PRIMARYTYPE);
+ propName = Constants.JCR_PRIMARYTYPE;
}
+ else
+ {
+ propName = relPath.getName();
+ }
+
String field = "";
try
{
- field = resolver.createJCRName(relPath.getName()).getAsString();
+ field = resolver.createJCRName(propName).getAsString();
}
catch (NamespaceException e)
{
@@ -795,7 +804,7 @@
}
// support for fn:name()
- InternalQName propName = relPath.getName();
+ //InternalQName propName = relPath.getName();
if (propName.getNamespace().equals(NS_FN_URI) && propName.getName().equals("name()"))
{
if (node.getValueType() != QueryConstants.TYPE_STRING)
@@ -1053,7 +1062,7 @@
}
}
- if (relPath.getEntries().length > 1)
+ if (relPath != null && relPath.getEntries().length > 1)
{
// child axis in relation
QPathEntry[] elements = relPath.getEntries();
16 years, 7 months
exo-jcr SVN: r1145 - jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene.
by do-not-reply@jboss.org
Author: skabashnyuk
Date: 2009-12-22 10:42:52 -0500 (Tue, 22 Dec 2009)
New Revision: 1145
Modified:
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/AbstractIndex.java
Log:
EXOJCR-325: merge with JBC branch
Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/AbstractIndex.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/AbstractIndex.java 2009-12-22 13:29:21 UTC (rev 1144)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/AbstractIndex.java 2009-12-22 15:42:52 UTC (rev 1145)
@@ -49,575 +49,682 @@
* Concurrent access by <b>one</b> modifying thread and multiple read-only
* threads is safe!
*/
-abstract class AbstractIndex {
+abstract class AbstractIndex
+{
- /** The logger instance for this class */
- private static final Logger log = LoggerFactory.getLogger(AbstractIndex.class);
+ /** The logger instance for this class */
+ private static final Logger log = LoggerFactory.getLogger(AbstractIndex.class);
- /** PrintStream that pipes all calls to println(String) into log.info() */
- private static final LoggingPrintStream STREAM_LOGGER = new LoggingPrintStream();
+ /** PrintStream that pipes all calls to println(String) into log.info() */
+ private static final LoggingPrintStream STREAM_LOGGER = new LoggingPrintStream();
- /** Executor with a pool size equal to the number of available processors */
- private static final DynamicPooledExecutor EXECUTOR = new DynamicPooledExecutor();
+ /** Executor with a pool size equal to the number of available processors */
+ private static final DynamicPooledExecutor EXECUTOR = new DynamicPooledExecutor();
- /** The currently set IndexWriter or <code>null</code> if none is set */
- private IndexWriter indexWriter;
+ /** The currently set IndexWriter or <code>null</code> if none is set */
+ private IndexWriter indexWriter;
- /** The currently set IndexReader or <code>null</code> if none is set */
- private CommittableIndexReader indexReader;
+ /** The currently set IndexReader or <code>null</code> if none is set */
+ private CommittableIndexReader indexReader;
- /** The underlying Directory where the index is stored */
- private Directory directory;
+ /** The underlying Directory where the index is stored */
+ private Directory directory;
- /** Analyzer we use to tokenize text */
- private Analyzer analyzer;
+ /** Analyzer we use to tokenize text */
+ private Analyzer analyzer;
- /** The similarity in use for indexing and searching. */
- private final Similarity similarity;
+ /** The similarity in use for indexing and searching. */
+ private final Similarity similarity;
- /** Compound file flag */
- private boolean useCompoundFile = true;
+ /** Compound file flag */
+ private boolean useCompoundFile = true;
- /** maxFieldLength config parameter */
- private int maxFieldLength = SearchIndex.DEFAULT_MAX_FIELD_LENGTH;
+ /** maxFieldLength config parameter */
+ private int maxFieldLength = SearchIndex.DEFAULT_MAX_FIELD_LENGTH;
- /** termInfosIndexDivisor config parameter */
- private int termInfosIndexDivisor = SearchIndex.DEFAULT_TERM_INFOS_INDEX_DIVISOR;
+ /** termInfosIndexDivisor config parameter */
+ private int termInfosIndexDivisor = SearchIndex.DEFAULT_TERM_INFOS_INDEX_DIVISOR;
- /**
- * The document number cache if this index may use one.
- */
- private DocNumberCache cache;
+ /**
+ * The document number cache if this index may use one.
+ */
+ private DocNumberCache cache;
- /** The shared IndexReader for all read-only IndexReaders */
- private SharedIndexReader sharedReader;
+ /** The shared IndexReader for all read-only IndexReaders */
+ private SharedIndexReader sharedReader;
- /**
- * The most recent read-only reader if there is any.
- */
- private ReadOnlyIndexReader readOnlyReader;
+ /**
+ * The most recent read-only reader if there is any.
+ */
+ private ReadOnlyIndexReader readOnlyReader;
- /**
- * The indexing queue.
- */
- private IndexingQueue indexingQueue;
+ /**
+ * The indexing queue.
+ */
+ private IndexingQueue indexingQueue;
- /**
- * Flag that indicates whether there was an index present in the directory
- * when this AbstractIndex was created.
- */
- private boolean isExisting;
+ /**
+ * Flag that indicates whether there was an index present in the directory
+ * when this AbstractIndex was created.
+ */
+ private boolean isExisting;
- /**
- * Constructs an index with an <code>analyzer</code> and a
- * <code>directory</code>.
- *
- * @param analyzer the analyzer for text tokenizing.
- * @param similarity the similarity implementation.
- * @param directory the underlying directory.
- * @param cache the document number cache if this index should use
- * one; otherwise <code>cache</code> is
- * <code>null</code>.
- * @param indexingQueue the indexing queue.
- * @throws IOException if the index cannot be initialized.
- */
- AbstractIndex(Analyzer analyzer,
- Similarity similarity,
- Directory directory,
- DocNumberCache cache,
- IndexingQueue indexingQueue) throws IOException {
- this.analyzer = analyzer;
- this.similarity = similarity;
- this.directory = directory;
- this.cache = cache;
- this.indexingQueue = indexingQueue;
- this.isExisting = IndexReader.indexExists(directory);
+ /**
+ * Constructs an index with an <code>analyzer</code> and a
+ * <code>directory</code>.
+ *
+ * @param analyzer the analyzer for text tokenizing.
+ * @param similarity the similarity implementation.
+ * @param directory the underlying directory.
+ * @param cache the document number cache if this index should use
+ * one; otherwise <code>cache</code> is
+ * <code>null</code>.
+ * @param indexingQueue the indexing queue.
+ * @throws IOException if the index cannot be initialized.
+ */
+ AbstractIndex(Analyzer analyzer, Similarity similarity, Directory directory, DocNumberCache cache,
+ IndexingQueue indexingQueue) throws IOException
+ {
+ this.analyzer = analyzer;
+ this.similarity = similarity;
+ this.directory = directory;
+ this.cache = cache;
+ this.indexingQueue = indexingQueue;
+ this.isExisting = IndexReader.indexExists(directory);
- if (!isExisting) {
- indexWriter = new IndexWriter(directory, analyzer,
- IndexWriter.MaxFieldLength.LIMITED);
- // immediately close, now that index has been created
- indexWriter.close();
- indexWriter = null;
- }
- }
+ if (!isExisting)
+ {
+ indexWriter = new IndexWriter(directory, analyzer, IndexWriter.MaxFieldLength.LIMITED);
+ // immediately close, now that index has been created
+ indexWriter.close();
+ indexWriter = null;
+ }
+ }
- /**
- * Default implementation returns the same instance as passed
- * in the constructor.
- *
- * @return the directory instance passed in the constructor
- */
- Directory getDirectory() {
- return directory;
- }
+ /**
+ * Default implementation returns the same instance as passed
+ * in the constructor.
+ *
+ * @return the directory instance passed in the constructor
+ */
+ Directory getDirectory()
+ {
+ return directory;
+ }
- /**
- * Returns <code>true</code> if this index was openend on a directory with
- * an existing index in it; <code>false</code> otherwise.
- *
- * @return <code>true</code> if there was an index present when this index
- * was created; <code>false</code> otherwise.
- */
- boolean isExisting() {
- return isExisting;
- }
+ /**
+ * Returns <code>true</code> if this index was openend on a directory with
+ * an existing index in it; <code>false</code> otherwise.
+ *
+ * @return <code>true</code> if there was an index present when this index
+ * was created; <code>false</code> otherwise.
+ */
+ boolean isExisting()
+ {
+ return isExisting;
+ }
- /**
- * Adds documents to this index and invalidates the shared reader.
- *
- * @param docs the documents to add.
- * @throws IOException if an error occurs while writing to the index.
- */
- void addDocuments(Document[] docs) throws IOException {
- final IndexWriter writer = getIndexWriter();
- DynamicPooledExecutor.Command[] commands =
- new DynamicPooledExecutor.Command[docs.length];
- for (int i = 0; i < docs.length; i++) {
- // check if text extractor completed its work
- final Document doc = getFinishedDocument(docs[i]);
- // create a command for inverting the document
- commands[i] = new DynamicPooledExecutor.Command() {
- public Object call() throws Exception {
- long time = System.currentTimeMillis();
- writer.addDocument(doc);
- return new Long(System.currentTimeMillis() - time);
- }
- };
- }
- DynamicPooledExecutor.Result[] results = EXECUTOR.executeAndWait(commands);
- invalidateSharedReader();
- IOException ex = null;
- for (int i = 0; i < results.length; i++) {
- if (results[i].getException() != null) {
- Throwable cause = results[i].getException().getCause();
- if (ex == null) {
- // only throw the first exception
- if (cause instanceof IOException) {
- ex = (IOException) cause;
- } else {
- throw Util.createIOException(cause);
- }
- } else {
- // all others are logged
- log.warn("Exception while inverting document", cause);
- }
- } else {
- log.debug("Inverted document in {} ms", results[i].get());
+ /**
+ * Adds documents to this index and invalidates the shared reader.
+ *
+ * @param docs the documents to add.
+ * @throws IOException if an error occurs while writing to the index.
+ */
+ void addDocuments(Document[] docs) throws IOException
+ {
+ final IndexWriter writer = getIndexWriter();
+ DynamicPooledExecutor.Command[] commands = new DynamicPooledExecutor.Command[docs.length];
+ for (int i = 0; i < docs.length; i++)
+ {
+ // check if text extractor completed its work
+ final Document doc = getFinishedDocument(docs[i]);
+ // create a command for inverting the document
+ commands[i] = new DynamicPooledExecutor.Command()
+ {
+ public Object call() throws Exception
+ {
+ long time = System.currentTimeMillis();
+ writer.addDocument(doc);
+ return new Long(System.currentTimeMillis() - time);
}
- }
- if (ex != null) {
- throw ex;
- }
- }
+ };
+ }
+ DynamicPooledExecutor.Result[] results = EXECUTOR.executeAndWait(commands);
+ invalidateSharedReader();
+ IOException ex = null;
+ for (int i = 0; i < results.length; i++)
+ {
+ if (results[i].getException() != null)
+ {
+ Throwable cause = results[i].getException().getCause();
+ if (ex == null)
+ {
+ // only throw the first exception
+ if (cause instanceof IOException)
+ {
+ ex = (IOException)cause;
+ }
+ else
+ {
+ throw Util.createIOException(cause);
+ }
+ }
+ else
+ {
+ // all others are logged
+ log.warn("Exception while inverting document", cause);
+ }
+ }
+ else
+ {
+ log.debug("Inverted document in {} ms", results[i].get());
+ }
+ }
+ if (ex != null)
+ {
+ throw ex;
+ }
+ }
- /**
- * Removes the document from this index. This call will not invalidate
- * the shared reader. If a subclass whishes to do so, it should overwrite
- * this method and call {@link #invalidateSharedReader()}.
- *
- * @param idTerm the id term of the document to remove.
- * @throws IOException if an error occurs while removing the document.
- * @return number of documents deleted
- */
- int removeDocument(Term idTerm) throws IOException {
- return getIndexReader().deleteDocuments(idTerm);
- }
+ /**
+ * Removes the document from this index. This call will not invalidate
+ * the shared reader. If a subclass whishes to do so, it should overwrite
+ * this method and call {@link #invalidateSharedReader()}.
+ *
+ * @param idTerm the id term of the document to remove.
+ * @throws IOException if an error occurs while removing the document.
+ * @return number of documents deleted
+ */
+ int removeDocument(Term idTerm) throws IOException
+ {
+ return getIndexReader().deleteDocuments(idTerm);
+ }
- /**
- * Returns an <code>IndexReader</code> on this index. This index reader
- * may be used to delete documents.
- *
- * @return an <code>IndexReader</code> on this index.
- * @throws IOException if the reader cannot be obtained.
- */
- protected synchronized CommittableIndexReader getIndexReader() throws IOException {
- if (indexWriter != null) {
- indexWriter.close();
- log.debug("closing IndexWriter.");
- indexWriter = null;
- }
- if (indexReader == null) {
- IndexReader reader = IndexReader.open(getDirectory());
- reader.setTermInfosIndexDivisor(termInfosIndexDivisor);
- indexReader = new CommittableIndexReader(reader);
- }
- return indexReader;
- }
+ /**
+ * Returns an <code>IndexReader</code> on this index. This index reader
+ * may be used to delete documents.
+ *
+ * @return an <code>IndexReader</code> on this index.
+ * @throws IOException if the reader cannot be obtained.
+ */
+ protected synchronized CommittableIndexReader getIndexReader() throws IOException
+ {
+ if (indexWriter != null)
+ {
+ indexWriter.close();
+ log.debug("closing IndexWriter.");
+ indexWriter = null;
+ }
+
+ if (indexReader == null || !indexReader.isCurrent())
+ {
+ IndexReader reader = IndexReader.open(getDirectory());
+ reader.setTermInfosIndexDivisor(termInfosIndexDivisor);
+ indexReader = new CommittableIndexReader(reader);
+ }
+ return indexReader;
+ }
- /**
- * Returns a read-only index reader, that can be used concurrently with
- * other threads writing to this index. The returned index reader is
- * read-only, that is, any attempt to delete a document from the index
- * will throw an <code>UnsupportedOperationException</code>.
- *
- * @param initCache if the caches in the index reader should be initialized
- * before the index reader is returned.
- * @return a read-only index reader.
- * @throws IOException if an error occurs while obtaining the index reader.
- */
- synchronized ReadOnlyIndexReader getReadOnlyIndexReader(boolean initCache)
- throws IOException {
- // get current modifiable index reader
- CommittableIndexReader modifiableReader = getIndexReader();
- long modCount = modifiableReader.getModificationCount();
- if (readOnlyReader != null) {
- if (readOnlyReader.getDeletedDocsVersion() == modCount) {
- // reader up-to-date
- readOnlyReader.acquire();
- return readOnlyReader;
- } else {
- // reader outdated
- if (readOnlyReader.getRefCount() == 1) {
- // not in use, except by this index
- // update the reader
- readOnlyReader.updateDeletedDocs(modifiableReader);
- readOnlyReader.acquire();
- return readOnlyReader;
- } else {
- // cannot update reader, it is still in use
- // need to create a new instance
- readOnlyReader.release();
- readOnlyReader = null;
- }
+ /**
+ * Returns a read-only index reader, that can be used concurrently with
+ * other threads writing to this index. The returned index reader is
+ * read-only, that is, any attempt to delete a document from the index
+ * will throw an <code>UnsupportedOperationException</code>.
+ *
+ * @param initCache if the caches in the index reader should be initialized
+ * before the index reader is returned.
+ * @return a read-only index reader.
+ * @throws IOException if an error occurs while obtaining the index reader.
+ */
+ synchronized ReadOnlyIndexReader getReadOnlyIndexReader(boolean initCache) throws IOException
+ {
+ // get current modifiable index reader
+ CommittableIndexReader modifiableReader = getIndexReader();
+ long modCount = modifiableReader.getModificationCount();
+ if (readOnlyReader != null)
+ {
+ if (readOnlyReader.getDeletedDocsVersion() == modCount)
+ {
+ // reader up-to-date
+ readOnlyReader.acquire();
+ return readOnlyReader;
+ }
+ else
+ {
+ // reader outdated
+ if (readOnlyReader.getRefCount() == 1)
+ {
+ // not in use, except by this index
+ // update the reader
+ readOnlyReader.updateDeletedDocs(modifiableReader);
+ readOnlyReader.acquire();
+ return readOnlyReader;
}
- }
- // if we get here there is no up-to-date read-only reader
- // capture snapshot of deleted documents
- BitSet deleted = new BitSet(modifiableReader.maxDoc());
- for (int i = 0; i < modifiableReader.maxDoc(); i++) {
- if (modifiableReader.isDeleted(i)) {
- deleted.set(i);
+ else
+ {
+ // cannot update reader, it is still in use
+ // need to create a new instance
+ readOnlyReader.release();
+ readOnlyReader = null;
}
- }
- if (sharedReader == null) {
- // create new shared reader
- IndexReader reader = IndexReader.open(getDirectory(), true);
- reader.setTermInfosIndexDivisor(termInfosIndexDivisor);
- CachingIndexReader cr = new CachingIndexReader(
- reader, cache, initCache);
- sharedReader = new SharedIndexReader(cr);
- }
- readOnlyReader = new ReadOnlyIndexReader(sharedReader, deleted, modCount);
- readOnlyReader.acquire();
- return readOnlyReader;
- }
+ }
+ }
+ // if we get here there is no up-to-date read-only reader
+ // capture snapshot of deleted documents
+ BitSet deleted = new BitSet(modifiableReader.maxDoc());
+ for (int i = 0; i < modifiableReader.maxDoc(); i++)
+ {
+ if (modifiableReader.isDeleted(i))
+ {
+ deleted.set(i);
+ }
+ }
+ if (sharedReader == null)
+ {
+ // create new shared reader
+ IndexReader reader = IndexReader.open(getDirectory(), true);
+ reader.setTermInfosIndexDivisor(termInfosIndexDivisor);
+ CachingIndexReader cr = new CachingIndexReader(reader, cache, initCache);
+ sharedReader = new SharedIndexReader(cr);
+ }
+ readOnlyReader = new ReadOnlyIndexReader(sharedReader, deleted, modCount);
+ readOnlyReader.acquire();
+ return readOnlyReader;
+ }
- /**
- * Returns a read-only index reader, that can be used concurrently with
- * other threads writing to this index. The returned index reader is
- * read-only, that is, any attempt to delete a document from the index
- * will throw an <code>UnsupportedOperationException</code>.
- *
- * @return a read-only index reader.
- * @throws IOException if an error occurs while obtaining the index reader.
- */
- protected ReadOnlyIndexReader getReadOnlyIndexReader()
- throws IOException {
- return getReadOnlyIndexReader(false);
- }
+ /**
+ * Returns a read-only index reader, that can be used concurrently with
+ * other threads writing to this index. The returned index reader is
+ * read-only, that is, any attempt to delete a document from the index
+ * will throw an <code>UnsupportedOperationException</code>.
+ *
+ * @return a read-only index reader.
+ * @throws IOException if an error occurs while obtaining the index reader.
+ */
+ protected ReadOnlyIndexReader getReadOnlyIndexReader() throws IOException
+ {
+ return getReadOnlyIndexReader(false);
+ }
- /**
- * Returns an <code>IndexWriter</code> on this index.
- * @return an <code>IndexWriter</code> on this index.
- * @throws IOException if the writer cannot be obtained.
- */
- protected synchronized IndexWriter getIndexWriter() throws IOException {
- if (indexReader != null) {
- indexReader.close();
- log.debug("closing IndexReader.");
- indexReader = null;
- }
- if (indexWriter == null) {
- indexWriter = new IndexWriter(getDirectory(), analyzer,
- new IndexWriter.MaxFieldLength(maxFieldLength));
- indexWriter.setSimilarity(similarity);
- indexWriter.setUseCompoundFile(useCompoundFile);
- indexWriter.setInfoStream(STREAM_LOGGER);
- }
- return indexWriter;
- }
+ /**
+ * Returns an <code>IndexWriter</code> on this index.
+ * @return an <code>IndexWriter</code> on this index.
+ * @throws IOException if the writer cannot be obtained.
+ */
+ protected synchronized IndexWriter getIndexWriter() throws IOException
+ {
+ if (indexReader != null)
+ {
+ indexReader.close();
+ log.debug("closing IndexReader.");
+ indexReader = null;
+ }
+ if (indexWriter == null)
+ {
+ indexWriter = new IndexWriter(getDirectory(), analyzer, new IndexWriter.MaxFieldLength(maxFieldLength));
+ indexWriter.setSimilarity(similarity);
+ indexWriter.setUseCompoundFile(useCompoundFile);
+ indexWriter.setInfoStream(STREAM_LOGGER);
+ }
+ return indexWriter;
+ }
- /**
- * Commits all pending changes to the underlying <code>Directory</code>.
- * @throws IOException if an error occurs while commiting changes.
- */
- protected void commit() throws IOException {
- commit(false);
- }
+ /**
+ * Commits all pending changes to the underlying <code>Directory</code>.
+ * @throws IOException if an error occurs while commiting changes.
+ */
+ protected void commit() throws IOException
+ {
+ commit(false);
+ }
- /**
- * Commits all pending changes to the underlying <code>Directory</code>.
- *
- * @param optimize if <code>true</code> the index is optimized after the
- * commit.
- * @throws IOException if an error occurs while commiting changes.
- */
- protected synchronized void commit(boolean optimize) throws IOException {
- if (indexReader != null) {
- log.debug("committing IndexReader.");
- indexReader.flush();
- }
- if (indexWriter != null) {
- log.debug("committing IndexWriter.");
- indexWriter.commit();
- }
- // optimize if requested
- if (optimize) {
- IndexWriter writer = getIndexWriter();
- writer.optimize();
- writer.close();
- indexWriter = null;
- }
- }
+ /**
+ * Commits all pending changes to the underlying <code>Directory</code>.
+ *
+ * @param optimize if <code>true</code> the index is optimized after the
+ * commit.
+ * @throws IOException if an error occurs while commiting changes.
+ */
+ protected synchronized void commit(boolean optimize) throws IOException
+ {
+ if (indexReader != null)
+ {
+ log.debug("committing IndexReader.");
+ indexReader.flush();
+ }
+ if (indexWriter != null)
+ {
+ log.debug("committing IndexWriter.");
+ indexWriter.commit();
+ }
+ // optimize if requested
+ if (optimize)
+ {
+ IndexWriter writer = getIndexWriter();
+ writer.optimize();
+ writer.close();
+ indexWriter = null;
+ }
+ }
- /**
- * Closes this index, releasing all held resources.
- */
- synchronized void close() {
- releaseWriterAndReaders();
- if (directory != null) {
- try {
- directory.close();
- } catch (IOException e) {
- directory = null;
- }
- }
- }
+ /**
+ * Closes this index, releasing all held resources.
+ */
+ synchronized void close()
+ {
+ releaseWriterAndReaders();
+ if (directory != null)
+ {
+ try
+ {
+ directory.close();
+ }
+ catch (IOException e)
+ {
+ directory = null;
+ }
+ }
+ }
- /**
- * Releases all potentially held index writer and readers.
- */
- protected void releaseWriterAndReaders() {
- if (indexWriter != null) {
- try {
- indexWriter.close();
- } catch (IOException e) {
- log.warn("Exception closing index writer: " + e.toString());
- }
- indexWriter = null;
- }
- if (indexReader != null) {
- try {
- indexReader.close();
- } catch (IOException e) {
- log.warn("Exception closing index reader: " + e.toString());
- }
- indexReader = null;
- }
- if (readOnlyReader != null) {
- try {
- readOnlyReader.release();
- } catch (IOException e) {
- log.warn("Exception closing index reader: " + e.toString());
- }
- readOnlyReader = null;
- }
- if (sharedReader != null) {
- try {
- sharedReader.release();
- } catch (IOException e) {
- log.warn("Exception closing index reader: " + e.toString());
- }
- sharedReader = null;
- }
- }
-
- /**
- * @return the number of bytes this index occupies in memory.
- */
- synchronized long getRamSizeInBytes() {
- if (indexWriter != null) {
- return indexWriter.ramSizeInBytes();
- } else {
- return 0;
- }
- }
-
- /**
- * Closes the shared reader.
- *
- * @throws IOException if an error occurs while closing the reader.
- */
- protected synchronized void invalidateSharedReader() throws IOException {
- // also close the read-only reader
- if (readOnlyReader != null) {
+ /**
+ * Releases all potentially held index writer and readers.
+ */
+ protected void releaseWriterAndReaders()
+ {
+ if (indexWriter != null)
+ {
+ try
+ {
+ indexWriter.close();
+ }
+ catch (IOException e)
+ {
+ log.warn("Exception closing index writer: " + e.toString());
+ }
+ indexWriter = null;
+ }
+ if (indexReader != null)
+ {
+ try
+ {
+ indexReader.close();
+ }
+ catch (IOException e)
+ {
+ log.warn("Exception closing index reader: " + e.toString());
+ }
+ indexReader = null;
+ }
+ if (readOnlyReader != null)
+ {
+ try
+ {
readOnlyReader.release();
- readOnlyReader = null;
- }
- // invalidate shared reader
- if (sharedReader != null) {
+ }
+ catch (IOException e)
+ {
+ log.warn("Exception closing index reader: " + e.toString());
+ }
+ readOnlyReader = null;
+ }
+ if (sharedReader != null)
+ {
+ try
+ {
sharedReader.release();
- sharedReader = null;
- }
- }
+ }
+ catch (IOException e)
+ {
+ log.warn("Exception closing index reader: " + e.toString());
+ }
+ sharedReader = null;
+ }
+ }
- /**
- * Returns a document that is finished with text extraction and is ready to
- * be added to the index.
- *
- * @param doc the document to check.
- * @return <code>doc</code> if it is finished already or a stripped down
- * copy of <code>doc</code> without text extractors.
- * @throws IOException if the document cannot be added to the indexing
- * queue.
- */
- private Document getFinishedDocument(Document doc) throws IOException {
- if (!Util.isDocumentReady(doc)) {
- Document copy = new Document();
- // mark the document that reindexing is required
- copy.add(new Field(FieldNames.REINDEXING_REQUIRED, "",
- Field.Store.NO, Field.Index.NOT_ANALYZED_NO_NORMS));
- Iterator fields = doc.getFields().iterator();
- while (fields.hasNext()) {
- Fieldable f = (Fieldable) fields.next();
- Fieldable field = null;
- Field.TermVector tv = getTermVectorParameter(f);
- Field.Store stored = getStoreParameter(f);
- Field.Index indexed = getIndexParameter(f);
- if (f instanceof LazyTextExtractorField || f.readerValue() != null) {
- // replace all readers with empty string reader
- field = new Field(f.name(), new StringReader(""), tv);
- } else if (f.stringValue() != null) {
- field = new Field(f.name(), f.stringValue(),
- stored, indexed, tv);
- } else if (f.isBinary()) {
- field = new Field(f.name(), f.binaryValue(), stored);
- }
- if (field != null) {
- field.setOmitNorms(f.getOmitNorms());
- copy.add(field);
- }
+ /**
+ * @return the number of bytes this index occupies in memory.
+ */
+ synchronized long getRamSizeInBytes()
+ {
+ if (indexWriter != null)
+ {
+ return indexWriter.ramSizeInBytes();
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ /**
+ * Closes the shared reader.
+ *
+ * @throws IOException if an error occurs while closing the reader.
+ */
+ protected synchronized void invalidateSharedReader() throws IOException
+ {
+ // also close the read-only reader
+ if (readOnlyReader != null)
+ {
+ readOnlyReader.release();
+ readOnlyReader = null;
+ }
+ // invalidate shared reader
+ if (sharedReader != null)
+ {
+ sharedReader.release();
+ sharedReader = null;
+ }
+ }
+
+ /**
+ * Returns a document that is finished with text extraction and is ready to
+ * be added to the index.
+ *
+ * @param doc the document to check.
+ * @return <code>doc</code> if it is finished already or a stripped down
+ * copy of <code>doc</code> without text extractors.
+ * @throws IOException if the document cannot be added to the indexing
+ * queue.
+ */
+ private Document getFinishedDocument(Document doc) throws IOException
+ {
+ if (!Util.isDocumentReady(doc))
+ {
+ Document copy = new Document();
+ // mark the document that reindexing is required
+ copy.add(new Field(FieldNames.REINDEXING_REQUIRED, "", Field.Store.NO, Field.Index.NOT_ANALYZED_NO_NORMS));
+ Iterator fields = doc.getFields().iterator();
+ while (fields.hasNext())
+ {
+ Fieldable f = (Fieldable)fields.next();
+ Fieldable field = null;
+ Field.TermVector tv = getTermVectorParameter(f);
+ Field.Store stored = getStoreParameter(f);
+ Field.Index indexed = getIndexParameter(f);
+ if (f instanceof LazyTextExtractorField || f.readerValue() != null)
+ {
+ // replace all readers with empty string reader
+ field = new Field(f.name(), new StringReader(""), tv);
}
- // schedule the original document for later indexing
- Document existing = indexingQueue.addDocument(doc);
- if (existing != null) {
- // the queue already contained a pending document for this
- // node. -> dispose the document
- Util.disposeDocument(existing);
+ else if (f.stringValue() != null)
+ {
+ field = new Field(f.name(), f.stringValue(), stored, indexed, tv);
}
- // use the stripped down copy for now
- doc = copy;
- }
- return doc;
- }
+ else if (f.isBinary())
+ {
+ field = new Field(f.name(), f.binaryValue(), stored);
+ }
+ if (field != null)
+ {
+ field.setOmitNorms(f.getOmitNorms());
+ copy.add(field);
+ }
+ }
+ // schedule the original document for later indexing
+ Document existing = indexingQueue.addDocument(doc);
+ if (existing != null)
+ {
+ // the queue already contained a pending document for this
+ // node. -> dispose the document
+ Util.disposeDocument(existing);
+ }
+ // use the stripped down copy for now
+ doc = copy;
+ }
+ return doc;
+ }
- //-------------------------< properties >-----------------------------------
+ //-------------------------< properties >-----------------------------------
- /**
- * The lucene index writer property: useCompountFile
- */
- void setUseCompoundFile(boolean b) {
- useCompoundFile = b;
- if (indexWriter != null) {
- indexWriter.setUseCompoundFile(b);
- }
- }
+ /**
+ * The lucene index writer property: useCompountFile
+ */
+ void setUseCompoundFile(boolean b)
+ {
+ useCompoundFile = b;
+ if (indexWriter != null)
+ {
+ indexWriter.setUseCompoundFile(b);
+ }
+ }
- /**
- * The lucene index writer property: maxFieldLength
- */
- void setMaxFieldLength(int maxFieldLength) {
- this.maxFieldLength = maxFieldLength;
- if (indexWriter != null) {
- indexWriter.setMaxFieldLength(maxFieldLength);
- }
- }
+ /**
+ * The lucene index writer property: maxFieldLength
+ */
+ void setMaxFieldLength(int maxFieldLength)
+ {
+ this.maxFieldLength = maxFieldLength;
+ if (indexWriter != null)
+ {
+ indexWriter.setMaxFieldLength(maxFieldLength);
+ }
+ }
- /**
- * @return the current value for termInfosIndexDivisor.
- */
- public int getTermInfosIndexDivisor() {
- return termInfosIndexDivisor;
- }
+ /**
+ * @return the current value for termInfosIndexDivisor.
+ */
+ public int getTermInfosIndexDivisor()
+ {
+ return termInfosIndexDivisor;
+ }
- /**
- * Sets a new value for termInfosIndexDivisor.
- *
- * @param termInfosIndexDivisor the new value.
- */
- public void setTermInfosIndexDivisor(int termInfosIndexDivisor) {
- this.termInfosIndexDivisor = termInfosIndexDivisor;
- }
+ /**
+ * Sets a new value for termInfosIndexDivisor.
+ *
+ * @param termInfosIndexDivisor the new value.
+ */
+ public void setTermInfosIndexDivisor(int termInfosIndexDivisor)
+ {
+ this.termInfosIndexDivisor = termInfosIndexDivisor;
+ }
- //------------------------------< internal >--------------------------------
+ //------------------------------< internal >--------------------------------
- /**
- * Returns the index parameter set on <code>f</code>.
- *
- * @param f a lucene field.
- * @return the index parameter on <code>f</code>.
- */
- private Field.Index getIndexParameter(Fieldable f) {
- if (!f.isIndexed()) {
- return Field.Index.NO;
- } else if (f.isTokenized()) {
- return Field.Index.ANALYZED;
- } else {
- return Field.Index.NOT_ANALYZED;
- }
- }
+ /**
+ * Returns the index parameter set on <code>f</code>.
+ *
+ * @param f a lucene field.
+ * @return the index parameter on <code>f</code>.
+ */
+ private Field.Index getIndexParameter(Fieldable f)
+ {
+ if (!f.isIndexed())
+ {
+ return Field.Index.NO;
+ }
+ else if (f.isTokenized())
+ {
+ return Field.Index.ANALYZED;
+ }
+ else
+ {
+ return Field.Index.NOT_ANALYZED;
+ }
+ }
- /**
- * Returns the store parameter set on <code>f</code>.
- *
- * @param f a lucene field.
- * @return the store parameter on <code>f</code>.
- */
- private Field.Store getStoreParameter(Fieldable f) {
- if (f.isCompressed()) {
- return Field.Store.COMPRESS;
- } else if (f.isStored()) {
- return Field.Store.YES;
- } else {
- return Field.Store.NO;
- }
- }
+ /**
+ * Returns the store parameter set on <code>f</code>.
+ *
+ * @param f a lucene field.
+ * @return the store parameter on <code>f</code>.
+ */
+ private Field.Store getStoreParameter(Fieldable f)
+ {
+ if (f.isCompressed())
+ {
+ return Field.Store.COMPRESS;
+ }
+ else if (f.isStored())
+ {
+ return Field.Store.YES;
+ }
+ else
+ {
+ return Field.Store.NO;
+ }
+ }
- /**
- * Returns the term vector parameter set on <code>f</code>.
- *
- * @param f a lucene field.
- * @return the term vector parameter on <code>f</code>.
- */
- private Field.TermVector getTermVectorParameter(Fieldable f) {
- if (f.isStorePositionWithTermVector() && f.isStoreOffsetWithTermVector()) {
- return Field.TermVector.WITH_POSITIONS_OFFSETS;
- } else if (f.isStorePositionWithTermVector()) {
- return Field.TermVector.WITH_POSITIONS;
- } else if (f.isStoreOffsetWithTermVector()) {
- return Field.TermVector.WITH_OFFSETS;
- } else if (f.isTermVectorStored()) {
- return Field.TermVector.YES;
- } else {
- return Field.TermVector.NO;
- }
- }
+ /**
+ * Returns the term vector parameter set on <code>f</code>.
+ *
+ * @param f a lucene field.
+ * @return the term vector parameter on <code>f</code>.
+ */
+ private Field.TermVector getTermVectorParameter(Fieldable f)
+ {
+ if (f.isStorePositionWithTermVector() && f.isStoreOffsetWithTermVector())
+ {
+ return Field.TermVector.WITH_POSITIONS_OFFSETS;
+ }
+ else if (f.isStorePositionWithTermVector())
+ {
+ return Field.TermVector.WITH_POSITIONS;
+ }
+ else if (f.isStoreOffsetWithTermVector())
+ {
+ return Field.TermVector.WITH_OFFSETS;
+ }
+ else if (f.isTermVectorStored())
+ {
+ return Field.TermVector.YES;
+ }
+ else
+ {
+ return Field.TermVector.NO;
+ }
+ }
- /**
- * Adapter to pipe info messages from lucene into log messages.
- */
- private static final class LoggingPrintStream extends PrintStream {
+ /**
+ * Adapter to pipe info messages from lucene into log messages.
+ */
+ private static final class LoggingPrintStream extends PrintStream
+ {
- /** Buffer print calls until a newline is written */
- private StringBuffer buffer = new StringBuffer();
+ /** Buffer print calls until a newline is written */
+ private StringBuffer buffer = new StringBuffer();
- public LoggingPrintStream() {
- super(new OutputStream() {
- public void write(int b) {
- // do nothing
- }
- });
- }
+ public LoggingPrintStream()
+ {
+ super(new OutputStream()
+ {
+ public void write(int b)
+ {
+ // do nothing
+ }
+ });
+ }
- public void print(String s) {
- buffer.append(s);
- }
+ public void print(String s)
+ {
+ buffer.append(s);
+ }
- public void println(String s) {
- buffer.append(s);
- log.debug(buffer.toString());
- buffer.setLength(0);
- }
- }
+ public void println(String s)
+ {
+ buffer.append(s);
+ log.debug(buffer.toString());
+ buffer.setLength(0);
+ }
+ }
}
16 years, 7 months
exo-jcr SVN: r1144 - in jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src: main/java/org/exoplatform/services/jcr/impl/core/query and 5 other directories.
by do-not-reply@jboss.org
Author: skabashnyuk
Date: 2009-12-22 08:29:21 -0500 (Tue, 22 Dec 2009)
New Revision: 1144
Added:
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/DefaultChangesFilter.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/IndexerChangesFilter.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/IndexerIoMode.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/ChangesFilterListsWrapper.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/IndexerCacheLoader.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/IndexerSingletonStoreCacheLoader.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/JbossCacheIndexChangesFilter.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jbosscache/
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jbosscache/AbstractWriteOnlyCacheLoader.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jbosscache/WriteOnlyCacheLoaderException.java
Modified:
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/config/QueryHandlerParams.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/AbstractQueryHandler.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/IndexingTree.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandler.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandlerContext.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchIndexConfigurationHelper.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchManager.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SystemSearchManager.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/IndexInfos.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/LuceneQueryBuilder.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/MultiIndex.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/NodeIndexer.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java
jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/api/core/query/lucene/SlowQueryHandler.java
Log:
EXOJCR-325: merge with JBC branch
Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/config/QueryHandlerParams.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/config/QueryHandlerParams.java 2009-12-22 10:32:33 UTC (rev 1143)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/config/QueryHandlerParams.java 2009-12-22 13:29:21 UTC (rev 1144)
@@ -92,6 +92,8 @@
public static final String PARAM_USE_COMPOUNDFILE = "use-compoundfile";
public static final String PARAM_VOLATILE_IDLE_TIME = "volatile-idle-time";
+
+ public static final String PARAM_MAX_VOLATILE_SIZE = "max-volatile-size";
//since https://jira.jboss.org/jira/browse/EXOJCR-17
@@ -99,4 +101,7 @@
public static final String PARAM_ANALYZER_CLASS = "analyzer";
+ public static final String PARAM_CHANGES_FILTER_CLASS = "changesfilter-class";
+
+ public static final String PARAM_CHANGES_FILTER_CONFIG_PATH = "changesfilter-config-path";
}
Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/AbstractQueryHandler.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/AbstractQueryHandler.java 2009-12-22 10:32:33 UTC (rev 1143)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/AbstractQueryHandler.java 2009-12-22 13:29:21 UTC (rev 1144)
@@ -21,6 +21,7 @@
import javax.jcr.RepositoryException;
+import org.exoplatform.services.jcr.config.RepositoryConfigurationException;
import org.exoplatform.services.jcr.datamodel.NodeData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -41,6 +42,8 @@
*/
private QueryHandlerContext context;
+ protected boolean initialized = false;
+
/**
* The {@link OnWorkspaceInconsistency} handler. Defaults to 'fail'.
*/
@@ -58,16 +61,31 @@
private String idleTime;
/**
- * Initializes this query handler by setting all properties in this class
- * with appropriate parameter values.
- *
- * @param context the context for this query handler.
- * @throws RepositoryException
+ * Indexer io mode
*/
- public final void init(QueryHandlerContext context) throws IOException, RepositoryException
+ protected IndexerIoMode ioMode = IndexerIoMode.READ_ONLY;
+
+ public boolean isInitialized()
{
+ return initialized;
+ }
+
+ /**
+ * @see org.exoplatform.services.jcr.impl.core.query.QueryHandler#setContext(org.exoplatform.services.jcr.impl.core.query.QueryHandlerContext)
+ */
+ public void setContext(QueryHandlerContext context)
+ {
this.context = context;
+ }
+
+ /**
+ * Initializes QueryHandler with given IoMode (RW/RO)
+ */
+ public void init() throws IOException, RepositoryException, RepositoryConfigurationException
+ {
+ // TODO Auto-generated method stub
doInit();
+ initialized = true;
}
/**
Added: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/DefaultChangesFilter.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/DefaultChangesFilter.java (rev 0)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/DefaultChangesFilter.java 2009-12-22 13:29:21 UTC (rev 1144)
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2009 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.core.query;
+
+import org.exoplatform.services.jcr.config.QueryHandlerEntry;
+import org.exoplatform.services.jcr.config.RepositoryConfigurationException;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+
+import java.io.IOException;
+import java.util.Set;
+
+import javax.jcr.RepositoryException;
+
+/**
+ * @author <a href="mailto:Sergey.Kabashnyuk@exoplatform.org">Sergey Kabashnyuk</a>
+ * @version $Id: exo-jboss-codetemplates.xml 34360 2009-07-22 23:58:59Z ksm $
+ *
+ */
+public class DefaultChangesFilter extends IndexerChangesFilter
+{
+
+ /**
+ * @param searchManager
+ * @param parentSearchManager
+ * @param config
+ * @param indexingTree
+ * @param parentIndexingTree
+ * @param handler
+ * @param parentHandler
+ * @throws IOException
+ * @throws RepositoryConfigurationException
+ * @throws RepositoryException
+ */
+ public DefaultChangesFilter(SearchManager searchManager, SearchManager parentSearchManager,
+ QueryHandlerEntry config, IndexingTree indexingTree, IndexingTree parentIndexingTree, QueryHandler handler,
+ QueryHandler parentHandler) throws IOException, RepositoryConfigurationException, RepositoryException
+ {
+ super(searchManager, parentSearchManager, config, indexingTree, parentIndexingTree, handler, parentHandler);
+ handler.setIndexerIoMode(IndexerIoMode.READ_WRITE);
+ parentHandler.setIndexerIoMode(IndexerIoMode.READ_WRITE);
+
+ if (!parentHandler.isInitialized())
+ {
+ parentHandler.init();
+ }
+ if (!handler.isInitialized())
+ {
+ handler.init();
+ }
+ }
+
+ /**
+ * Logger instance for this class
+ */
+ private static final Log log = ExoLogger.getLogger(DefaultChangesFilter.class);
+
+ /**
+ * @param removedNodes
+ * @param addedNodes
+ * @see org.exoplatform.services.jcr.impl.core.query.IndexerChangesFilter#doUpdateIndex()
+ */
+ @Override
+ protected void doUpdateIndex(Set<String> removedNodes, Set<String> addedNodes, Set<String> parentRemovedNodes,
+ Set<String> parentAddedNodes)
+ {
+
+ try
+ {
+ searchManager.updateIndex(removedNodes, addedNodes);
+ }
+ catch (RepositoryException e)
+ {
+ log.error("Error indexing changes " + e, e);
+ }
+ catch (IOException e)
+ {
+ log.error("Error indexing changes " + e, e);
+ try
+ {
+ handler.logErrorChanges(removedNodes, addedNodes);
+ }
+ catch (IOException ioe)
+ {
+ log.warn("Exception occure when errorLog writed. Error log is not complete. " + ioe, ioe);
+ }
+ }
+
+ try
+ {
+ parentSearchManager.updateIndex(parentRemovedNodes, parentAddedNodes);
+ }
+ catch (RepositoryException e)
+ {
+ log.error("Error indexing changes " + e, e);
+ }
+ catch (IOException e)
+ {
+ log.error("Error indexing changes " + e, e);
+ try
+ {
+ parentHandler.logErrorChanges(removedNodes, addedNodes);
+ }
+ catch (IOException ioe)
+ {
+ log.warn("Exception occure when errorLog writed. Error log is not complete. " + ioe, ioe);
+ }
+ }
+
+ }
+
+}
Property changes on: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/DefaultChangesFilter.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/IndexerChangesFilter.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/IndexerChangesFilter.java (rev 0)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/IndexerChangesFilter.java 2009-12-22 13:29:21 UTC (rev 1144)
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2009 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.core.query;
+
+import org.exoplatform.services.jcr.config.QueryHandlerEntry;
+import org.exoplatform.services.jcr.dataflow.ItemState;
+import org.exoplatform.services.jcr.dataflow.ItemStateChangesLog;
+import org.exoplatform.services.jcr.dataflow.persistent.ItemsPersistenceListener;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:Sergey.Kabashnyuk@exoplatform.org">Sergey Kabashnyuk</a>
+ * @version $Id: exo-jboss-codetemplates.xml 34360 2009-07-22 23:58:59Z ksm $
+ *
+ */
+public abstract class IndexerChangesFilter implements ItemsPersistenceListener
+{
+ /**
+ * Logger instance for this class
+ */
+ private static final Log log = ExoLogger.getLogger(DefaultChangesFilter.class);
+
+ protected final SearchManager searchManager;
+
+ protected final QueryHandlerEntry config;
+
+ protected final QueryHandler handler;
+
+ protected final QueryHandler parentHandler;
+
+ protected final IndexingTree indexingTree;
+
+ protected final SearchManager parentSearchManager;
+
+ protected final IndexingTree parentIndexingTree;
+
+ /**
+ * @param searchManager
+ * @param isSystem
+ * @param handler
+ * @param indexingTree
+ */
+ public IndexerChangesFilter(SearchManager searchManager, SearchManager parentSearchManager,
+ QueryHandlerEntry config, IndexingTree indexingTree, IndexingTree parentIndexingTree, QueryHandler handler,
+ QueryHandler parentHandler)
+ {
+ super();
+ this.searchManager = searchManager;
+ this.parentSearchManager = parentSearchManager;
+ this.config = config;
+ this.parentIndexingTree = parentIndexingTree;
+ this.indexingTree = indexingTree;
+ this.handler = handler;
+ this.parentHandler = parentHandler;
+ }
+
+ /**
+ * @return the handler
+ */
+ public QueryHandler getHandler()
+ {
+ return handler;
+ }
+
+ /**
+ * @return the indexingTree
+ */
+ public IndexingTree getIndexingTree()
+ {
+ return indexingTree;
+ }
+
+ /**
+ * @return the searchManager
+ */
+ public SearchManager getSearchManager()
+ {
+ return searchManager;
+ }
+
+ /**
+ * @see org.exoplatform.services.jcr.dataflow.persistent.ItemsPersistenceListener#onSaveItems(org.exoplatform.services.jcr.dataflow.ItemStateChangesLog)
+ */
+ public void onSaveItems(ItemStateChangesLog itemStates)
+ {
+
+ long time = System.currentTimeMillis();
+
+ // nodes that need to be removed from the index.
+ final Set<String> removedNodes = new HashSet<String>();
+ // nodes that need to be added to the index.
+ final Set<String> addedNodes = new HashSet<String>();
+ //updated
+ final Map<String, List<ItemState>> updatedNodes = new HashMap<String, List<ItemState>>();
+
+ final Set<String> parentRemovedNodes = new HashSet<String>();
+ // nodes that need to be added to the index.
+ final Set<String> parentAddedNodes = new HashSet<String>();
+ //updated
+ final Map<String, List<ItemState>> parentUpdatedNodes = new HashMap<String, List<ItemState>>();
+
+ for (Iterator<ItemState> iter = itemStates.getAllStates().iterator(); iter.hasNext();)
+ {
+ ItemState itemState = iter.next();
+
+ if (!indexingTree.isExcluded(itemState))
+ {
+ acceptChanges(removedNodes, addedNodes, updatedNodes, itemState);
+ }
+ else if (parentIndexingTree != null && !parentIndexingTree.isExcluded(itemState))
+ {
+ acceptChanges(parentRemovedNodes, parentAddedNodes, parentUpdatedNodes, itemState);
+ }
+ }
+
+ for (String uuid : updatedNodes.keySet())
+ {
+ removedNodes.add(uuid);
+ addedNodes.add(uuid);
+ }
+
+ for (String uuid : parentUpdatedNodes.keySet())
+ {
+ parentRemovedNodes.add(uuid);
+ parentAddedNodes.add(uuid);
+ }
+
+ doUpdateIndex(removedNodes, addedNodes, parentRemovedNodes, parentAddedNodes);
+ }
+
+ /**
+ * @param removedNodes
+ * @param addedNodes
+ * @param updatedNodes
+ * @param itemState
+ */
+ private void acceptChanges(final Set<String> removedNodes, final Set<String> addedNodes,
+ final Map<String, List<ItemState>> updatedNodes, ItemState itemState)
+ {
+ {
+ String uuid =
+ itemState.isNode() ? itemState.getData().getIdentifier() : itemState.getData().getParentIdentifier();
+
+ if (itemState.isAdded())
+ {
+ if (itemState.isNode())
+ {
+ addedNodes.add(uuid);
+ }
+ else
+ {
+ if (!addedNodes.contains(uuid))
+ {
+ createNewOrAdd(uuid, itemState, updatedNodes);
+ }
+ }
+ }
+ else if (itemState.isRenamed())
+ {
+ if (itemState.isNode())
+ {
+ addedNodes.add(uuid);
+ }
+ else
+ {
+ createNewOrAdd(uuid, itemState, updatedNodes);
+ }
+ }
+ else if (itemState.isUpdated())
+ {
+ createNewOrAdd(uuid, itemState, updatedNodes);
+ }
+ else if (itemState.isMixinChanged())
+ {
+ createNewOrAdd(uuid, itemState, updatedNodes);
+ }
+ else if (itemState.isDeleted())
+ {
+ if (itemState.isNode())
+ {
+ if (addedNodes.contains(uuid))
+ {
+ addedNodes.remove(uuid);
+ removedNodes.remove(uuid);
+ }
+ else
+ {
+ removedNodes.add(uuid);
+ }
+ // remove all changes after node remove
+ updatedNodes.remove(uuid);
+ }
+ else
+ {
+ if (!removedNodes.contains(uuid) && !addedNodes.contains(uuid))
+ {
+ createNewOrAdd(uuid, itemState, updatedNodes);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Update index.
+ * @param removedNodes
+ * @param addedNodes
+ */
+ protected abstract void doUpdateIndex(Set<String> removedNodes, Set<String> addedNodes,
+ Set<String> parentRemovedNodes, Set<String> parentAddedNodes);
+
+ private void createNewOrAdd(String key, ItemState state, Map<String, List<ItemState>> updatedNodes)
+ {
+ List<ItemState> list = updatedNodes.get(key);
+ if (list == null)
+ {
+ list = new ArrayList<ItemState>();
+ updatedNodes.put(key, list);
+ }
+ list.add(state);
+
+ }
+
+}
Property changes on: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/IndexerChangesFilter.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/IndexerIoMode.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/IndexerIoMode.java (rev 0)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/IndexerIoMode.java 2009-12-22 13:29:21 UTC (rev 1144)
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2009 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.core.query;
+
+/**
+ * @author <a href="mailto:Sergey.Kabashnyuk@exoplatform.org">Sergey Kabashnyuk</a>
+ * @version $Id: exo-jboss-codetemplates.xml 34360 2009-07-22 23:58:59Z ksm $
+ *
+ */
+public enum IndexerIoMode {
+ /**
+ * Only query
+ */
+ READ_ONLY,
+ /**
+ * query on index and write changes
+ */
+ READ_WRITE
+}
Property changes on: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/IndexerIoMode.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/IndexingTree.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/IndexingTree.java 2009-12-22 10:32:33 UTC (rev 1143)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/IndexingTree.java 2009-12-22 13:29:21 UTC (rev 1144)
@@ -29,90 +29,97 @@
/**
* @author <a href="mailto:Sergey.Kabashnyuk@exoplatform.org">Sergey
* Kabashnyuk</a>
- * @version $Id: exo-jboss-codetemplates.xml 34360 2009-07-22 23:58:59Z ksm $
+ * @version $Id: IndexingTree.java 790 2009-11-20 13:45:40Z skabashnyuk $
*
*/
-public class IndexingTree {
- private final QPath indexingRootQpath;
- private final NodeData indexingRoot;
+public class IndexingTree
+{
+ private final QPath indexingRootQpath;
- private final List<QPath> excludedPaths;
+ private final NodeData indexingRoot;
- /**
- * @param indexingRoot
- * @param excludedPaths
- */
- public IndexingTree(NodeData indexingRoot, List<QPath> excludedPaths) {
- super();
- this.indexingRoot = indexingRoot;
- this.indexingRootQpath = indexingRoot.getQPath();
- this.excludedPaths = excludedPaths;
- }
+ private final List<QPath> excludedPaths;
- /**
- * @param indexingRoot
- * @param excludedPaths
- */
- public IndexingTree(NodeData indexingRoot) {
- super();
- this.indexingRoot = indexingRoot;
- this.indexingRootQpath = indexingRoot.getQPath();
- this.excludedPaths = new ArrayList<QPath>();
- }
+ /**
+ * @param indexingRoot
+ * @param excludedPaths
+ */
+ public IndexingTree(NodeData indexingRoot, List<QPath> excludedPaths)
+ {
+ super();
+ this.indexingRoot = indexingRoot;
+ this.indexingRootQpath = indexingRoot.getQPath();
+ this.excludedPaths = excludedPaths;
+ }
- /**
- * @return the excludedPaths
- */
- public List<QPath> getExcludedPaths() {
- return excludedPaths;
- }
+ /**
+ * @param indexingRoot
+ * @param excludedPaths
+ */
+ public IndexingTree(NodeData indexingRoot)
+ {
+ super();
+ this.indexingRoot = indexingRoot;
+ this.indexingRootQpath = indexingRoot.getQPath();
+ this.excludedPaths = new ArrayList<QPath>();
+ }
- /**
- * @return the indexingRoot
- */
- public NodeData getIndexingRoot() {
- return indexingRoot;
- }
+ /**
+ * @return the excludedPaths
+ */
+ public List<QPath> getExcludedPaths()
+ {
+ return excludedPaths;
+ }
- /**
- * Checks if the given event should be excluded based on the
- * {@link #excludePath} setting.
- *
- * @param event
- * observation event
- * @return <code>true</code> if the event should be excluded,
- * <code>false</code> otherwise
- */
- public boolean isExcluded(ItemState event) {
+ /**
+ * @return the indexingRoot
+ */
+ public NodeData getIndexingRoot()
+ {
+ return indexingRoot;
+ }
- for (QPath excludedPath : excludedPaths) {
- if (event.getData().getQPath().isDescendantOf(excludedPath)
- || event.getData().getQPath().equals(excludedPath))
- return true;
- }
+ /**
+ * Checks if the given event should be excluded based on the
+ * {@link #excludePath} setting.
+ *
+ * @param event
+ * observation event
+ * @return <code>true</code> if the event should be excluded,
+ * <code>false</code> otherwise
+ */
+ public boolean isExcluded(ItemState event)
+ {
- return !event.getData().getQPath().isDescendantOf(indexingRootQpath)
- && !event.getData().getQPath().equals(indexingRootQpath);
- }
+ for (QPath excludedPath : excludedPaths)
+ {
+ if (event.getData().getQPath().isDescendantOf(excludedPath) || event.getData().getQPath().equals(excludedPath))
+ return true;
+ }
- /**
- * Checks if the given event should be excluded based on the
- * {@link #excludePath} setting.
- *
- * @param event
- * observation event
- * @return <code>true</code> if the event should be excluded,
- * <code>false</code> otherwise
- */
- public boolean isExcluded(ItemData eventData) {
+ return !event.getData().getQPath().isDescendantOf(indexingRootQpath)
+ && !event.getData().getQPath().equals(indexingRootQpath);
+ }
- for (QPath excludedPath : excludedPaths) {
- if (eventData.getQPath().isDescendantOf(excludedPath)
- || eventData.getQPath().equals(excludedPath))
- return true;
- }
+ /**
+ * Checks if the given event should be excluded based on the
+ * {@link #excludePath} setting.
+ *
+ * @param event
+ * observation event
+ * @return <code>true</code> if the event should be excluded,
+ * <code>false</code> otherwise
+ */
+ public boolean isExcluded(ItemData eventData)
+ {
- return !eventData.getQPath().isDescendantOf(indexingRootQpath)
- && !eventData.getQPath().equals(indexingRootQpath);
- }
+ for (QPath excludedPath : excludedPaths)
+ {
+ if (eventData.getQPath().isDescendantOf(excludedPath) || eventData.getQPath().equals(excludedPath))
+ return true;
+ }
+
+ return !eventData.getQPath().isDescendantOf(indexingRootQpath) && !eventData.getQPath().equals(indexingRootQpath);
+ }
}
Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandler.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandler.java 2009-12-22 10:32:33 UTC (rev 1143)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandler.java 2009-12-22 13:29:21 UTC (rev 1144)
@@ -41,7 +41,7 @@
/**
* Returns the query handler context that passed in {@link
- * #init(QueryHandlerContext)}.
+ * #setContext(QueryHandlerContext)}.
*
* @return the query handler context.
*/
@@ -81,9 +81,31 @@
*/
void close();
- void init(QueryHandlerContext context) throws IOException, RepositoryException, RepositoryConfigurationException;
+ /**
+ * Sets QueryHandlerContext
+ * @param context
+ */
+ void setContext(QueryHandlerContext context);
/**
+ *
+ * initializes QueryHandler
+ *
+ * @param ioMode
+ * @throws IOException
+ * @throws RepositoryException
+ * @throws RepositoryConfigurationException
+ */
+ void init() throws IOException, RepositoryException, RepositoryConfigurationException;
+
+ /**
+ * Checks whether QueryHandler is initialized or not
+ *
+ * @return
+ */
+ boolean isInitialized();
+
+ /**
* Creates a new query by specifying the query statement itself and the
* language in which the query is stated. If the query statement is
* syntactically invalid, given the language specified, an
@@ -110,22 +132,7 @@
*/
void logErrorChanges(Set<String> removed, Set<String> added) throws IOException;
- // /**
- // * Creates a new query by specifying the query object model. If the query
- // * object model is considered invalid for the implementing class, an
- // * InvalidQueryException is thrown.
- // *
- // * @param session the session of the current user creating the query
- // * object.
- // * @param itemMgr the item manager of the current user.
- // * @param qomTree query query object model tree.
- // * @return A <code>Query</code> object.
- // * @throws InvalidQueryException if the query object model tree is invalid.
- // */
- // ExecutableQuery createExecutableQuery(SessionImpl session,
- // ItemManager itemMgr,
- // QueryObjectModelTree qomTree)
- // throws InvalidQueryException;
+ void setIndexerIoMode(IndexerIoMode ioMode) throws IOException;
/**
* @return the name of the query class to use.
Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandlerContext.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandlerContext.java 2009-12-22 10:32:33 UTC (rev 1143)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandlerContext.java 2009-12-22 13:29:21 UTC (rev 1144)
@@ -28,175 +28,184 @@
* stable. This class provides access to the environment where the query handler
* is running in.
*/
-public class QueryHandlerContext {
- /**
- * The persistent <code>ItemStateManager</code>
- */
- private final ItemDataConsumer stateMgr;
+public class QueryHandlerContext
+{
+ /**
+ * The persistent <code>ItemStateManager</code>
+ */
+ private final ItemDataConsumer stateMgr;
- /**
- * The node type registry of the repository
- */
- private final NodeTypeDataManager nodeTypeDataManager;
+ /**
+ * The node type registry of the repository
+ */
+ private final NodeTypeDataManager nodeTypeDataManager;
- /**
- * The namespace registry of the repository.
- */
- private final NamespaceRegistryImpl nsRegistry;
+ /**
+ * The namespace registry of the repository.
+ */
+ private final NamespaceRegistryImpl nsRegistry;
- /**
- * The id of the root node.
- */
- private final IndexingTree indexingTree;
+ /**
+ * The id of the root node.
+ */
+ private final IndexingTree indexingTree;
- /**
- * PropertyType registry to look up the type of a property with a given
- * name.
- */
- private final PropertyTypeRegistry propRegistry;
+ /**
+ * PropertyType registry to look up the type of a property with a given
+ * name.
+ */
+ private final PropertyTypeRegistry propRegistry;
- /**
- * The query handler for the jcr:system tree
- */
- private final QueryHandler parentHandler;
+ /**
+ * The query handler for the jcr:system tree
+ */
+ private final QueryHandler parentHandler;
- /**
- * Text extractor for extracting text content of binary properties.
- */
- private final DocumentReaderService extractor;
+ /**
+ * Text extractor for extracting text content of binary properties.
+ */
+ private final DocumentReaderService extractor;
- private final String indexDirectory;
+ private final String indexDirectory;
- private final boolean createInitialIndex;
+ private final boolean createInitialIndex;
- private final LuceneVirtualTableResolver virtualTableResolver;
+ private final LuceneVirtualTableResolver virtualTableResolver;
- /**
- * Creates a new context instance.
- *
- * @param fs
- * a this <code>QueryHandler</code> may use to store its index.
- * If no <code>FileSystem</code> has been configured
- * <code>fs</code> is <code>null</code>.
- * @param stateMgr
- * provides persistent item states.
- * @param rootId
- * the id of the root node.
- * @param ntRegistry
- * the node type registry.
- * @param nsRegistry
- * the namespace registry.
- * @param parentHandler
- * the parent query handler or <code>null</code> it there is no
- * parent handler.
- * @param virtualTableResolver
- * @param excludedNodeId
- * id of the node that should be excluded from indexing. Any
- * descendant of that node is also excluded from indexing.
- */
- public QueryHandlerContext(ItemDataConsumer stateMgr,
- IndexingTree indexingTree, NodeTypeDataManager nodeTypeDataManager,
- NamespaceRegistryImpl nsRegistry, QueryHandler parentHandler,
- String indexDirectory, DocumentReaderService extractor,
- boolean createInitialIndex,
- LuceneVirtualTableResolver virtualTableResolver) {
- this.stateMgr = stateMgr;
- this.indexingTree = indexingTree;
- this.nodeTypeDataManager = nodeTypeDataManager;
- this.nsRegistry = nsRegistry;
- this.indexDirectory = indexDirectory;
- this.extractor = extractor;
- this.createInitialIndex = createInitialIndex;
- this.virtualTableResolver = virtualTableResolver;
- this.propRegistry = new PropertyTypeRegistry(nodeTypeDataManager);
- this.parentHandler = parentHandler;
- ((NodeTypeDataManagerImpl) this.nodeTypeDataManager)
- .addListener(propRegistry);
- }
+ /**
+ * Creates a new context instance.
+ *
+ * @param fs
+ * a this <code>QueryHandler</code> may use to store its index.
+ * If no <code>FileSystem</code> has been configured
+ * <code>fs</code> is <code>null</code>.
+ * @param stateMgr
+ * provides persistent item states.
+ * @param rootId
+ * the id of the root node.
+ * @param ntRegistry
+ * the node type registry.
+ * @param nsRegistry
+ * the namespace registry.
+ * @param parentHandler
+ * the parent query handler or <code>null</code> it there is no
+ * parent handler.
+ * @param virtualTableResolver
+ * @param excludedNodeId
+ * id of the node that should be excluded from indexing. Any
+ * descendant of that node is also excluded from indexing.
+ */
+ public QueryHandlerContext(ItemDataConsumer stateMgr, IndexingTree indexingTree,
+ NodeTypeDataManager nodeTypeDataManager, NamespaceRegistryImpl nsRegistry, QueryHandler parentHandler,
+ String indexDirectory, DocumentReaderService extractor, boolean createInitialIndex,
+ LuceneVirtualTableResolver virtualTableResolver)
+ {
+ this.stateMgr = stateMgr;
+ this.indexingTree = indexingTree;
+ this.nodeTypeDataManager = nodeTypeDataManager;
+ this.nsRegistry = nsRegistry;
+ this.indexDirectory = indexDirectory;
+ this.extractor = extractor;
+ this.createInitialIndex = createInitialIndex;
+ this.virtualTableResolver = virtualTableResolver;
+ this.propRegistry = new PropertyTypeRegistry(nodeTypeDataManager);
+ this.parentHandler = parentHandler;
+ ((NodeTypeDataManagerImpl)this.nodeTypeDataManager).addListener(propRegistry);
+ }
- /**
- * @return the virtualTableResolver
- */
- public LuceneVirtualTableResolver getVirtualTableResolver() {
- return virtualTableResolver;
- }
+ /**
+ * @return the virtualTableResolver
+ */
+ public LuceneVirtualTableResolver getVirtualTableResolver()
+ {
+ return virtualTableResolver;
+ }
- /**
- * @return the createInitialIndex
- */
- public boolean isCreateInitialIndex() {
- return createInitialIndex;
- }
+ /**
+ * @return the createInitialIndex
+ */
+ public boolean isCreateInitialIndex()
+ {
+ return createInitialIndex;
+ }
- /**
- * Returns the persistent {@link ItemStateManager} of the workspace this
- * <code>QueryHandler</code> is based on.
- *
- * @return the persistent <code>ItemStateManager</code> of the current
- * workspace.
- */
- public ItemDataConsumer getItemStateManager() {
- return stateMgr;
- }
+ /**
+ * Returns the persistent {@link ItemStateManager} of the workspace this
+ * <code>QueryHandler</code> is based on.
+ *
+ * @return the persistent <code>ItemStateManager</code> of the current
+ * workspace.
+ */
+ public ItemDataConsumer getItemStateManager()
+ {
+ return stateMgr;
+ }
- /**
- * Returns the id of the root node.
- *
- * @return the idof the root node.
- */
- public IndexingTree getIndexingTree() {
- return indexingTree;
- }
+ /**
+ * Returns the id of the root node.
+ *
+ * @return the idof the root node.
+ */
+ public IndexingTree getIndexingTree()
+ {
+ return indexingTree;
+ }
- /**
- * Returns the PropertyTypeRegistry for this repository.
- *
- * @return the PropertyTypeRegistry for this repository.
- */
- public PropertyTypeRegistry getPropertyTypeRegistry() {
- return propRegistry;
- }
+ /**
+ * Returns the PropertyTypeRegistry for this repository.
+ *
+ * @return the PropertyTypeRegistry for this repository.
+ */
+ public PropertyTypeRegistry getPropertyTypeRegistry()
+ {
+ return propRegistry;
+ }
- /**
- * Returns the NodeTypeRegistry for this repository.
- *
- * @return the NodeTypeRegistry for this repository.
- */
- public NodeTypeDataManager getNodeTypeDataManager() {
- return nodeTypeDataManager;
- }
+ /**
+ * Returns the NodeTypeRegistry for this repository.
+ *
+ * @return the NodeTypeRegistry for this repository.
+ */
+ public NodeTypeDataManager getNodeTypeDataManager()
+ {
+ return nodeTypeDataManager;
+ }
- /**
- * Returns the NamespaceRegistryImpl for this repository.
- *
- * @return the NamespaceRegistryImpl for this repository.
- */
- public NamespaceRegistryImpl getNamespaceRegistry() {
- return nsRegistry;
- }
+ /**
+ * Returns the NamespaceRegistryImpl for this repository.
+ *
+ * @return the NamespaceRegistryImpl for this repository.
+ */
+ public NamespaceRegistryImpl getNamespaceRegistry()
+ {
+ return nsRegistry;
+ }
- /**
- * Returns the parent query handler.
- *
- * @return the parent query handler.
- */
- public QueryHandler getParentHandler() {
- return parentHandler;
- }
+ /**
+ * Returns the parent query handler.
+ *
+ * @return the parent query handler.
+ */
+ public QueryHandler getParentHandler()
+ {
+ return parentHandler;
+ }
- /**
- * Destroys this context and releases resources.
- */
- public void destroy() {
- ((NodeTypeDataManagerImpl) this.nodeTypeDataManager)
- .removeListener(propRegistry);
- }
+ /**
+ * Destroys this context and releases resources.
+ */
+ public void destroy()
+ {
+ ((NodeTypeDataManagerImpl)this.nodeTypeDataManager).removeListener(propRegistry);
+ }
- public DocumentReaderService getExtractor() {
- return extractor;
- }
+ public DocumentReaderService getExtractor()
+ {
+ return extractor;
+ }
- public String getIndexDirectory() {
- return indexDirectory;
- }
+ public String getIndexDirectory()
+ {
+ return indexDirectory;
+ }
}
Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchIndexConfigurationHelper.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchIndexConfigurationHelper.java 2009-12-22 10:32:33 UTC (rev 1143)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchIndexConfigurationHelper.java 2009-12-22 13:29:21 UTC (rev 1144)
@@ -29,7 +29,7 @@
/**
* @author <a href="mailto:Sergey.Kabashnyuk@exoplatform.org">Sergey
* Kabashnyuk</a>
- * @version $Id: exo-jboss-codetemplates.xml 34360 2009-07-22 23:58:59Z ksm $
+ * @version $Id: SearchIndexConfigurationHelper.java 1053 2009-12-15 09:27:30Z nzamosenchuk $
*
*/
public class SearchIndexConfigurationHelper
@@ -129,6 +129,8 @@
searchIndex.setUseCompoundFile(Boolean.parseBoolean(value));
else if (QueryHandlerParams.PARAM_VOLATILE_IDLE_TIME.equals(name))
searchIndex.setVolatileIdleTime(Integer.parseInt(value));
+ else if (QueryHandlerParams.PARAM_MAX_VOLATILE_SIZE.equals(name))
+ searchIndex.setMaxVolatileIndexSize(Integer.parseInt(value));
else if (QueryHandlerParams.PARAM_ANALYZER_CLASS.equals(name))
{
searchIndex.setAnalyzer(value);
Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchManager.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchManager.java 2009-12-22 10:32:33 UTC (rev 1143)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchManager.java 2009-12-22 13:29:21 UTC (rev 1144)
@@ -1,860 +1,858 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.exoplatform.services.jcr.impl.core.query;
-
-import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.index.Term;
-import org.apache.lucene.search.BooleanQuery;
-import org.apache.lucene.search.WildcardQuery;
-import org.apache.lucene.search.BooleanClause.Occur;
-import org.exoplatform.container.configuration.ConfigurationManager;
-import org.exoplatform.services.document.DocumentReaderService;
-import org.exoplatform.services.jcr.config.QueryHandlerEntry;
-import org.exoplatform.services.jcr.config.QueryHandlerParams;
-import org.exoplatform.services.jcr.config.RepositoryConfigurationException;
-import org.exoplatform.services.jcr.core.nodetype.NodeTypeDataManager;
-import org.exoplatform.services.jcr.dataflow.ItemDataConsumer;
-import org.exoplatform.services.jcr.dataflow.ItemState;
-import org.exoplatform.services.jcr.dataflow.ItemStateChangesLog;
-import org.exoplatform.services.jcr.dataflow.persistent.MandatoryItemsPersistenceListener;
-import org.exoplatform.services.jcr.datamodel.InternalQName;
-import org.exoplatform.services.jcr.datamodel.ItemData;
-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.ValueData;
-import org.exoplatform.services.jcr.impl.Constants;
-import org.exoplatform.services.jcr.impl.core.LocationFactory;
-import org.exoplatform.services.jcr.impl.core.NamespaceRegistryImpl;
-import org.exoplatform.services.jcr.impl.core.SessionDataManager;
-import org.exoplatform.services.jcr.impl.core.SessionImpl;
-import org.exoplatform.services.jcr.impl.core.query.lucene.FieldNames;
-import org.exoplatform.services.jcr.impl.core.query.lucene.LuceneVirtualTableResolver;
-import org.exoplatform.services.jcr.impl.core.query.lucene.QueryHits;
-import org.exoplatform.services.jcr.impl.core.query.lucene.ScoreNode;
-import org.exoplatform.services.jcr.impl.core.query.lucene.SearchIndex;
-import org.exoplatform.services.jcr.impl.core.value.NameValue;
-import org.exoplatform.services.jcr.impl.core.value.PathValue;
-import org.exoplatform.services.jcr.impl.core.value.ValueFactoryImpl;
-import org.exoplatform.services.jcr.impl.dataflow.AbstractValueData;
-import org.exoplatform.services.jcr.impl.dataflow.persistent.WorkspacePersistentDataManager;
-import org.exoplatform.services.log.ExoLogger;
-import org.exoplatform.services.log.Log;
-import org.picocontainer.Startable;
-
-import java.io.IOException;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.Set;
-import java.util.StringTokenizer;
-
-import javax.jcr.Node;
-import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
-import javax.jcr.Value;
-import javax.jcr.query.InvalidQueryException;
-import javax.jcr.query.Query;
-
-/**
- * Acts as a global entry point to execute queries and index nodes.
- */
-public class SearchManager implements Startable, MandatoryItemsPersistenceListener
-{
-
- /**
- * Logger instance for this class
- */
- private static final Log log = ExoLogger.getLogger(SearchManager.class);
-
- protected final QueryHandlerEntry config;
-
- /**
- * Text extractor for extracting text content of binary properties.
- */
- protected final DocumentReaderService extractor;
-
- /**
- * QueryHandler where query execution is delegated to
- */
- protected QueryHandler handler;
-
- /**
- * The shared item state manager instance for the workspace.
- */
- protected final ItemDataConsumer itemMgr;
-
- /**
- * The namespace registry of the repository.
- */
- protected final NamespaceRegistryImpl nsReg;
-
- /**
- * The node type registry.
- */
- protected final NodeTypeDataManager nodeTypeDataManager;
-
- /**
- * QueryHandler of the parent search manager or <code>null</code> if there
- * is none.
- */
- protected final SearchManager parentSearchManager;
-
- // protected QPath indexingRoot;
- //
- // protected List<QPath> excludedPaths = new ArrayList<QPath>();
-
- protected IndexingTree indexingTree;
-
- private final ConfigurationManager cfm;
-
- protected LuceneVirtualTableResolver virtualTableResolver;
-
- /**
- * Creates a new <code>SearchManager</code>.
- *
- * @param config
- * the search configuration.
- * @param nsReg
- * the namespace registry.
- * @param ntReg
- * the node type registry.
- * @param itemMgr
- * the shared item state manager.
- * @param rootNodeId
- * the id of the root node.
- * @param parentMgr
- * the parent search manager or <code>null</code> if there is no
- * parent search manager.
- * @param excludedNodeId
- * id of the node that should be excluded from indexing. Any
- * descendant of that node will also be excluded from indexing.
- * @throws RepositoryException
- * if the search manager cannot be initialized
- * @throws RepositoryConfigurationException
- */
- public SearchManager(QueryHandlerEntry config, NamespaceRegistryImpl nsReg, NodeTypeDataManager ntReg,
- WorkspacePersistentDataManager itemMgr, SystemSearchManagerHolder parentSearchManager,
- DocumentReaderService extractor, ConfigurationManager cfm, final RepositoryIndexSearcherHolder indexSearcherHolder)
- throws RepositoryException, RepositoryConfigurationException
- {
-
- this.extractor = extractor;
- indexSearcherHolder.addIndexSearcher(this);
- this.config = config;
- this.nodeTypeDataManager = ntReg;
- this.nsReg = nsReg;
- this.itemMgr = itemMgr;
- this.cfm = cfm;
- this.virtualTableResolver = new LuceneVirtualTableResolver(nodeTypeDataManager, nsReg);
- this.parentSearchManager = parentSearchManager != null ? parentSearchManager.get() : null;
- itemMgr.addItemPersistenceListener(this);
- }
-
- /**
- * Creates a query object from a node that can be executed on the workspace.
- *
- * @param session
- * the session of the user executing the query.
- * @param itemMgr
- * the item manager of the user executing the query. Needed to
- * return <code>Node</code> instances in the result set.
- * @param node
- * a node of type nt:query.
- * @return a <code>Query</code> instance to execute.
- * @throws InvalidQueryException
- * if <code>absPath</code> is not a valid persisted query (that
- * is, a node of type nt:query)
- * @throws RepositoryException
- * if any other error occurs.
- */
- public Query createQuery(SessionImpl session, SessionDataManager sessionDataManager, Node node)
- throws InvalidQueryException, RepositoryException
- {
- AbstractQueryImpl query = createQueryInstance();
- query.init(session, sessionDataManager, handler, node);
- return query;
- }
-
- /**
- * Creates a query object that can be executed on the workspace.
- *
- * @param session
- * the session of the user executing the query.
- * @param itemMgr
- * the item manager of the user executing the query. Needed to
- * return <code>Node</code> instances in the result set.
- * @param statement
- * the actual query statement.
- * @param language
- * the syntax of the query statement.
- * @return a <code>Query</code> instance to execute.
- * @throws InvalidQueryException
- * if the query is malformed or the <code>language</code> is
- * unknown.
- * @throws RepositoryException
- * if any other error occurs.
- */
- public Query createQuery(SessionImpl session, SessionDataManager sessionDataManager, String statement,
- String language) throws InvalidQueryException, RepositoryException
- {
- AbstractQueryImpl query = createQueryInstance();
- query.init(session, sessionDataManager, handler, statement, language);
- return query;
- }
-
- /**
- * just for test use only
- */
- public QueryHandler getHandler()
- {
-
- return handler;
- }
-
- public void onSaveItems(ItemStateChangesLog changesLog)
- {
- if (handler == null)
- return;
-
- long time = System.currentTimeMillis();
-
- // nodes that need to be removed from the index.
- final Set<String> removedNodes = new HashSet<String>();
- // nodes that need to be added to the index.
- final Set<String> addedNodes = new HashSet<String>();
-
- final Map<String, List<ItemState>> updatedNodes = new HashMap<String, List<ItemState>>();
-
- for (Iterator<ItemState> iter = changesLog.getAllStates().iterator(); iter.hasNext();)
- {
- ItemState itemState = iter.next();
-
- if (!indexingTree.isExcluded(itemState))
- {
- String uuid =
- itemState.isNode() ? itemState.getData().getIdentifier() : itemState.getData().getParentIdentifier();
-
- if (itemState.isAdded())
- {
- if (itemState.isNode())
- {
- addedNodes.add(uuid);
- }
- else
- {
- if (!addedNodes.contains(uuid))
- {
- createNewOrAdd(uuid, itemState, updatedNodes);
- }
- }
- }
- else if (itemState.isRenamed())
- {
- if (itemState.isNode())
- {
- addedNodes.add(uuid);
- }
- else
- {
- createNewOrAdd(uuid, itemState, updatedNodes);
- }
- }
- else if (itemState.isUpdated())
- {
- createNewOrAdd(uuid, itemState, updatedNodes);
- }
- else if (itemState.isMixinChanged())
- {
- createNewOrAdd(uuid, itemState, updatedNodes);
- }
- else if (itemState.isDeleted())
- {
- if (itemState.isNode())
- {
- if (addedNodes.contains(uuid))
- {
- addedNodes.remove(uuid);
- removedNodes.remove(uuid);
- }
- else
- {
- removedNodes.add(uuid);
- }
- // remove all changes after node remove
- updatedNodes.remove(uuid);
- }
- else
- {
- if (!removedNodes.contains(uuid) && !addedNodes.contains(uuid))
- {
- createNewOrAdd(uuid, itemState, updatedNodes);
- }
- }
- }
- }
- }
- // TODO make quick changes
- for (String uuid : updatedNodes.keySet())
- {
- removedNodes.add(uuid);
- addedNodes.add(uuid);
- }
-
- Iterator<NodeData> addedStates = new Iterator<NodeData>()
- {
- private final Iterator<String> iter = addedNodes.iterator();
-
- public boolean hasNext()
- {
- return iter.hasNext();
- }
-
- public NodeData next()
- {
-
- // cycle till find a next or meet the end of set
- do
- {
- String id = iter.next();
- try
- {
- ItemData item = itemMgr.getItemData(id);
- if (item != null)
- {
- if (item.isNode())
- return (NodeData)item; // return node
- else
- log.warn("Node not found, but property " + id + ", " + item.getQPath().getAsString()
- + " found. ");
- }
- else
- log.warn("Unable to index node with id " + id + ", node does not exist.");
-
- }
- catch (RepositoryException e)
- {
- log.error("Can't read next node data " + id, e);
- }
- }
- while (iter.hasNext()); // get next if error or node not found
-
- return null; // we met the end of iterator set
- }
-
- public void remove()
- {
- throw new UnsupportedOperationException();
- }
- };
-
- Iterator<String> removedIds = new Iterator<String>()
- {
- private final Iterator<String> iter = removedNodes.iterator();
-
- public boolean hasNext()
- {
- return iter.hasNext();
- }
-
- public String next()
- {
- return nextNodeId();
- }
-
- public String nextNodeId() throws NoSuchElementException
- {
- return iter.next();
- }
-
- public void remove()
- {
- throw new UnsupportedOperationException();
-
- }
- };
-
- if (removedNodes.size() > 0 || addedNodes.size() > 0)
- {
- try
- {
- handler.updateNodes(removedIds, addedStates);
- }
- catch (RepositoryException e)
- {
- log.error("Error indexing changes " + e, e);
- }
- catch (IOException e)
- {
- log.error("Error indexing changes " + e, e);
- try
- {
- handler.logErrorChanges(removedNodes, addedNodes);
- }
- catch (IOException ioe)
- {
- log.warn("Exception occure when errorLog writed. Error log is not complete. " + ioe, ioe);
- }
- }
- }
-
- if (log.isDebugEnabled())
- {
- log.debug("onEvent: indexing finished in " + String.valueOf(System.currentTimeMillis() - time) + " ms.");
- }
- }
-
- public void createNewOrAdd(String key, ItemState state, Map<String, List<ItemState>> updatedNodes)
- {
- List<ItemState> list = updatedNodes.get(key);
- if (list == null)
- {
- list = new ArrayList<ItemState>();
- updatedNodes.put(key, list);
- }
- list.add(state);
-
- }
-
- public void start()
- {
-
- if (log.isDebugEnabled())
- log.debug("start");
- try
- {
- if (indexingTree == null)
- {
- List<QPath> excludedPath = new ArrayList<QPath>();
- // Calculating excluded node identifiers
- excludedPath.add(Constants.JCR_SYSTEM_PATH);
-
- //if (config.getExcludedNodeIdentifers() != null)
- String excludedNodeIdentifer =
- config.getParameterValue(QueryHandlerParams.PARAM_EXCLUDED_NODE_IDENTIFERS, null);
- if (excludedNodeIdentifer != null)
- {
- StringTokenizer stringTokenizer = new StringTokenizer(excludedNodeIdentifer);
- while (stringTokenizer.hasMoreTokens())
- {
-
- try
- {
- ItemData excludeData = itemMgr.getItemData(stringTokenizer.nextToken());
- if (excludeData != null)
- excludedPath.add(excludeData.getQPath());
- }
- catch (RepositoryException e)
- {
- log.warn(e.getLocalizedMessage());
- }
- }
- }
-
- NodeData indexingRootData = null;
- String rootNodeIdentifer = config.getParameterValue(QueryHandlerParams.PARAM_ROOT_NODE_ID, null);
- if (rootNodeIdentifer != null)
- {
- try
- {
- ItemData indexingRootDataItem = itemMgr.getItemData(rootNodeIdentifer);
- if (indexingRootDataItem != null && indexingRootDataItem.isNode())
- indexingRootData = (NodeData)indexingRootDataItem;
- }
- catch (RepositoryException e)
- {
- log.warn(e.getLocalizedMessage() + " Indexing root set to " + Constants.ROOT_PATH.getAsString());
-
- }
-
- }
- else
- {
- try
- {
- indexingRootData = (NodeData)itemMgr.getItemData(Constants.ROOT_UUID);
- }
- catch (RepositoryException e)
- {
- log.error("Fail to load root node data");
- }
- }
-
- indexingTree = new IndexingTree(indexingRootData, excludedPath);
- }
-
- initializeQueryHandler();
- }
- catch (RepositoryException e)
- {
- log.error(e.getLocalizedMessage());
- handler = null;
- throw new RuntimeException(e.getLocalizedMessage(), e.getCause());
- }
- catch (RepositoryConfigurationException e)
- {
- log.error(e.getLocalizedMessage());
- handler = null;
- throw new RuntimeException(e.getLocalizedMessage(), e.getCause());
- }
- }
-
- public void stop()
- {
- handler.close();
- log.info("Search manager stopped");
- }
-
- // /**
- // * Checks if the given event should be excluded based on the
- // * {@link #excludePath} setting.
- // *
- // * @param event
- // * observation event
- // * @return <code>true</code> if the event should be excluded,
- // * <code>false</code> otherwise
- // */
- // protected boolean isExcluded(ItemState event) {
- //
- // for (QPath excludedPath : excludedPaths) {
- // if (event.getData().getQPath().isDescendantOf(excludedPath)
- // || event.getData().getQPath().equals(excludedPath))
- // return true;
- // }
- //
- // return !event.getData().getQPath().isDescendantOf(indexingRoot)
- // && !event.getData().getQPath().equals(indexingRoot);
- // }
-
- protected QueryHandlerContext createQueryHandlerContext(QueryHandler parentHandler)
- throws RepositoryConfigurationException
- {
-
- QueryHandlerContext context =
- new QueryHandlerContext(itemMgr, indexingTree, nodeTypeDataManager, nsReg, parentHandler, getIndexDir(),
- extractor, true, virtualTableResolver);
- return context;
- }
-
- protected String getIndexDir() throws RepositoryConfigurationException
- {
- String dir = config.getParameterValue(QueryHandlerParams.PARAM_INDEX_DIR, null);
- if (dir == null)
- {
- log.warn(QueryHandlerParams.PARAM_INDEX_DIR + " parameter not found. Using outdated parameter name "
- + QueryHandlerParams.OLD_PARAM_INDEX_DIR);
- dir = config.getParameterValue(QueryHandlerParams.OLD_PARAM_INDEX_DIR);
- }
- return dir;
- }
-
- /**
- * Initializes the query handler.
- *
- * @throws RepositoryException
- * if the query handler cannot be initialized.
- * @throws RepositoryConfigurationException
- * @throws ClassNotFoundException
- */
- protected void initializeQueryHandler() throws RepositoryException, RepositoryConfigurationException
- {
- // initialize query handler
- String className = config.getType();
- if (className == null)
- throw new RepositoryConfigurationException("Content hanler configuration fail");
-
- try
- {
- Class qHandlerClass = Class.forName(className, true, this.getClass().getClassLoader());
- Constructor constuctor = qHandlerClass.getConstructor(QueryHandlerEntry.class, ConfigurationManager.class);
- handler = (QueryHandler)constuctor.newInstance(config, cfm);
- QueryHandler parentHandler = (this.parentSearchManager != null) ? parentSearchManager.getHandler() : null;
- QueryHandlerContext context = createQueryHandlerContext(parentHandler);
- handler.init(context);
-
- }
- catch (SecurityException e)
- {
- throw new RepositoryException(e.getMessage(), e);
- }
- catch (IllegalArgumentException e)
- {
- throw new RepositoryException(e.getMessage(), e);
- }
- catch (ClassNotFoundException e)
- {
- throw new RepositoryException(e.getMessage(), e);
- }
- catch (NoSuchMethodException e)
- {
- throw new RepositoryException(e.getMessage(), e);
- }
- catch (InstantiationException e)
- {
- throw new RepositoryException(e.getMessage(), e);
- }
- catch (IllegalAccessException e)
- {
- throw new RepositoryException(e.getMessage(), e);
- }
- catch (InvocationTargetException e)
- {
- throw new RepositoryException(e.getMessage(), e);
- }
- catch (IOException e)
- {
- throw new RepositoryException(e.getMessage(), e);
- }
- }
-
- /**
- * Creates a new instance of an {@link AbstractQueryImpl} which is not
- * initialized.
- *
- * @return an new query instance.
- * @throws RepositoryException
- * if an error occurs while creating a new query instance.
- */
- protected AbstractQueryImpl createQueryInstance() throws RepositoryException
- {
- try
- {
- String queryImplClassName = handler.getQueryClass();
- Object obj = Class.forName(queryImplClassName).newInstance();
- if (obj instanceof AbstractQueryImpl)
- {
- return (AbstractQueryImpl)obj;
- }
- else
- {
- throw new IllegalArgumentException(queryImplClassName + " is not of type "
- + AbstractQueryImpl.class.getName());
- }
- }
- catch (Throwable t)
- {
- throw new RepositoryException("Unable to create query: " + t.toString(), t);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public Set<String> getFieldNames() throws IndexException
- {
- final Set<String> fildsSet = new HashSet<String>();
- if (handler instanceof SearchIndex)
- {
- IndexReader reader = null;
- try
- {
- reader = ((SearchIndex)handler).getIndexReader();
- final Collection fields = reader.getFieldNames(IndexReader.FieldOption.ALL);
- for (final Object field : fields)
- {
- fildsSet.add((String)field);
- }
- }
- catch (IOException e)
- {
- throw new IndexException(e.getLocalizedMessage(), e);
- }
- finally
- {
- try
- {
- if (reader != null)
- reader.close();
- }
- catch (IOException e)
- {
- throw new IndexException(e.getLocalizedMessage(), e);
- }
- }
-
- }
- return fildsSet;
- }
-
- public Set<String> getNodesByNodeType(final InternalQName nodeType) throws RepositoryException
- {
-
- return getNodes(virtualTableResolver.resolve(nodeType, true));
- }
-
- /**
- * Return set of uuid of nodes. Contains in names prefixes maped to the
- * given uri
- *
- * @param prefix
- * @return
- * @throws RepositoryException
- */
- public Set<String> getNodesByUri(final String uri) throws RepositoryException
- {
- Set<String> result;
- final int defaultClauseCount = BooleanQuery.getMaxClauseCount();
- try
- {
-
- // final LocationFactory locationFactory = new
- // LocationFactory(this);
- final ValueFactoryImpl valueFactory = new ValueFactoryImpl(new LocationFactory(nsReg));
- BooleanQuery.setMaxClauseCount(Integer.MAX_VALUE);
- BooleanQuery query = new BooleanQuery();
-
- final String prefix = nsReg.getNamespacePrefixByURI(uri);
- query.add(new WildcardQuery(new Term(FieldNames.LABEL, prefix + ":*")), Occur.SHOULD);
- // name of the property
- query.add(new WildcardQuery(new Term(FieldNames.PROPERTIES_SET, prefix + ":*")), Occur.SHOULD);
-
- result = getNodes(query);
-
- // value of the property
-
- try
- {
- final Set<String> props = getFieldNames();
-
- query = new BooleanQuery();
- for (final String fieldName : props)
- {
- if (!FieldNames.PROPERTIES_SET.equals(fieldName))
- {
- query.add(new WildcardQuery(new Term(fieldName, "*" + prefix + ":*")), Occur.SHOULD);
- }
- }
- }
- catch (final IndexException e)
- {
- throw new RepositoryException(e.getLocalizedMessage(), e);
- }
-
- final Set<String> propSet = getNodes(query);
- // Manually check property values;
- for (final String uuid : propSet)
- {
- if (isPrefixMatch(valueFactory, uuid, prefix))
- {
- result.add(uuid);
- }
- }
- }
- finally
- {
- BooleanQuery.setMaxClauseCount(defaultClauseCount);
- }
-
- return result;
- }
-
- private boolean isPrefixMatch(final InternalQName value, final String prefix) throws RepositoryException
- {
- return value.getNamespace().equals(nsReg.getNamespaceURIByPrefix(prefix));
- }
-
- private boolean isPrefixMatch(final QPath value, final String prefix) throws RepositoryException
- {
- for (int i = 0; i < value.getEntries().length; i++)
- {
- if (isPrefixMatch(value.getEntries()[i], prefix))
- {
- return true;
- }
- }
- return false;
- }
-
- /**
- * @param valueFactory
- * @param dm
- * @param uuid
- * @param prefix
- * @throws RepositoryException
- */
- private boolean isPrefixMatch(final ValueFactoryImpl valueFactory, final String uuid, final String prefix)
- throws RepositoryException
- {
-
- final ItemData node = itemMgr.getItemData(uuid);
- if (node != null && node.isNode())
- {
- final List<PropertyData> props = itemMgr.getChildPropertiesData((NodeData)node);
- for (final PropertyData propertyData : props)
- {
- if (propertyData.getType() == PropertyType.PATH || propertyData.getType() == PropertyType.NAME)
- {
- for (final ValueData vdata : propertyData.getValues())
- {
- final Value val =
- valueFactory.loadValue(((AbstractValueData)vdata).createTransientCopy(), propertyData.getType());
- if (propertyData.getType() == PropertyType.PATH)
- {
- if (isPrefixMatch(((PathValue)val).getQPath(), prefix))
- {
- return true;
- }
- }
- else if (propertyData.getType() == PropertyType.NAME)
- {
- if (isPrefixMatch(((NameValue)val).getQName(), prefix))
- {
- return true;
- }
- }
- }
- }
- }
- }
- return false;
- }
-
- /**
- * @param query
- * @return
- * @throws RepositoryException
- */
- private Set<String> getNodes(final org.apache.lucene.search.Query query) throws RepositoryException
- {
- Set<String> result = new HashSet<String>();
- try
- {
- QueryHits hits = handler.executeQuery(query);
-
- ScoreNode sn;
-
- while ((sn = hits.nextScoreNode()) != null)
- {
- // Node node = session.getNodeById(sn.getNodeId());
- result.add(sn.getNodeId());
- }
- }
- catch (IOException e)
- {
- throw new RepositoryException(e.getLocalizedMessage(), e);
- }
- return result;
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.exoplatform.services.jcr.impl.core.query;
+
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.WildcardQuery;
+import org.apache.lucene.search.BooleanClause.Occur;
+import org.exoplatform.container.configuration.ConfigurationManager;
+import org.exoplatform.services.document.DocumentReaderService;
+import org.exoplatform.services.jcr.config.QueryHandlerEntry;
+import org.exoplatform.services.jcr.config.QueryHandlerParams;
+import org.exoplatform.services.jcr.config.RepositoryConfigurationException;
+import org.exoplatform.services.jcr.core.nodetype.NodeTypeDataManager;
+import org.exoplatform.services.jcr.dataflow.ItemDataConsumer;
+import org.exoplatform.services.jcr.dataflow.ItemState;
+import org.exoplatform.services.jcr.dataflow.ItemStateChangesLog;
+import org.exoplatform.services.jcr.dataflow.persistent.MandatoryItemsPersistenceListener;
+import org.exoplatform.services.jcr.datamodel.InternalQName;
+import org.exoplatform.services.jcr.datamodel.ItemData;
+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.ValueData;
+import org.exoplatform.services.jcr.impl.Constants;
+import org.exoplatform.services.jcr.impl.core.LocationFactory;
+import org.exoplatform.services.jcr.impl.core.NamespaceRegistryImpl;
+import org.exoplatform.services.jcr.impl.core.SessionDataManager;
+import org.exoplatform.services.jcr.impl.core.SessionImpl;
+import org.exoplatform.services.jcr.impl.core.query.lucene.FieldNames;
+import org.exoplatform.services.jcr.impl.core.query.lucene.LuceneVirtualTableResolver;
+import org.exoplatform.services.jcr.impl.core.query.lucene.QueryHits;
+import org.exoplatform.services.jcr.impl.core.query.lucene.ScoreNode;
+import org.exoplatform.services.jcr.impl.core.query.lucene.SearchIndex;
+import org.exoplatform.services.jcr.impl.core.value.NameValue;
+import org.exoplatform.services.jcr.impl.core.value.PathValue;
+import org.exoplatform.services.jcr.impl.core.value.ValueFactoryImpl;
+import org.exoplatform.services.jcr.impl.dataflow.AbstractValueData;
+import org.exoplatform.services.jcr.impl.dataflow.persistent.WorkspacePersistentDataManager;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+import org.jboss.cache.factories.annotations.NonVolatile;
+import org.picocontainer.Startable;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import javax.jcr.Node;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.query.InvalidQueryException;
+import javax.jcr.query.Query;
+
+/**
+ * Created by The eXo Platform SAS.
+ *
+ * <br/>Date:
+ *
+ * @author <a href="karpenko.sergiy(a)gmail.com">Karpenko Sergiy</a>
+ * @version $Id: SearchManager.java 1008 2009-12-11 15:14:51Z nzamosenchuk $
+ */
+@NonVolatile
+public class SearchManager implements Startable, MandatoryItemsPersistenceListener
+{
+
+ /**
+ * Logger instance for this class
+ */
+ private static final Log log = ExoLogger.getLogger(SearchManager.class);
+
+ protected final QueryHandlerEntry config;
+
+ /**
+ * Text extractor for extracting text content of binary properties.
+ */
+ protected final DocumentReaderService extractor;
+
+ /**
+ * QueryHandler where query execution is delegated to
+ */
+
+ protected QueryHandler handler;
+
+ /**
+ * The shared item state manager instance for the workspace.
+ */
+ protected final ItemDataConsumer itemMgr;
+
+ /**
+ * The namespace registry of the repository.
+ */
+ protected final NamespaceRegistryImpl nsReg;
+
+ /**
+ * The node type registry.
+ */
+ protected final NodeTypeDataManager nodeTypeDataManager;
+
+ /**
+ * QueryHandler of the parent search manager or <code>null</code> if there
+ * is none.
+ */
+ protected final SearchManager parentSearchManager;
+
+ protected IndexingTree indexingTree;
+
+ private final ConfigurationManager cfm;
+
+ protected LuceneVirtualTableResolver virtualTableResolver;
+
+ protected IndexerChangesFilter changesFilter;
+
+ /**
+ * ChangesLog Buffer (used for saves before start).
+ */
+ private List<ItemStateChangesLog> changesLogBuffer = new ArrayList<ItemStateChangesLog>();
+
+ /**
+ * Creates a new <code>SearchManager</code>.
+ *
+ * @param config
+ * the search configuration.
+ * @param nsReg
+ * the namespace registry.
+ * @param ntReg
+ * the node type registry.
+ * @param itemMgr
+ * the shared item state manager.
+ * @param rootNodeId
+ * the id of the root node.
+ * @param parentMgr
+ * the parent search manager or <code>null</code> if there is no
+ * parent search manager.
+ * @param excludedNodeId
+ * id of the node that should be excluded from indexing. Any
+ * descendant of that node will also be excluded from indexing.
+ * @throws RepositoryException
+ * if the search manager cannot be initialized
+ * @throws RepositoryConfigurationException
+ */
+
+ public SearchManager(QueryHandlerEntry config, NamespaceRegistryImpl nsReg, NodeTypeDataManager ntReg,
+ WorkspacePersistentDataManager itemMgr, SystemSearchManagerHolder parentSearchManager,
+ DocumentReaderService extractor, ConfigurationManager cfm, final RepositoryIndexSearcherHolder indexSearcherHolder)
+ throws RepositoryException, RepositoryConfigurationException
+ {
+
+ this.extractor = extractor;
+ indexSearcherHolder.addIndexSearcher(this);
+ this.config = config;
+ this.nodeTypeDataManager = ntReg;
+ this.nsReg = nsReg;
+ this.itemMgr = itemMgr;
+ this.cfm = cfm;
+ this.virtualTableResolver = new LuceneVirtualTableResolver(nodeTypeDataManager, nsReg);
+ this.parentSearchManager = parentSearchManager != null ? parentSearchManager.get() : null;
+ if (parentSearchManager != null)
+ {
+ ((WorkspacePersistentDataManager)this.itemMgr).addItemPersistenceListener(this);
+ }
+ }
+
+ public void createNewOrAdd(String key, ItemState state, Map<String, List<ItemState>> updatedNodes)
+ {
+ List<ItemState> list = updatedNodes.get(key);
+ if (list == null)
+ {
+ list = new ArrayList<ItemState>();
+ updatedNodes.put(key, list);
+ }
+ list.add(state);
+
+ }
+
+ /**
+ * Creates a query object from a node that can be executed on the workspace.
+ *
+ * @param session
+ * the session of the user executing the query.
+ * @param itemMgr
+ * the item manager of the user executing the query. Needed to
+ * return <code>Node</code> instances in the result set.
+ * @param node
+ * a node of type nt:query.
+ * @return a <code>Query</code> instance to execute.
+ * @throws InvalidQueryException
+ * if <code>absPath</code> is not a valid persisted query (that
+ * is, a node of type nt:query)
+ * @throws RepositoryException
+ * if any other error occurs.
+ */
+ public Query createQuery(SessionImpl session, SessionDataManager sessionDataManager, Node node)
+ throws InvalidQueryException, RepositoryException
+ {
+ AbstractQueryImpl query = createQueryInstance();
+ query.init(session, sessionDataManager, handler, node);
+ return query;
+ }
+
+ /**
+ * Creates a query object that can be executed on the workspace.
+ *
+ * @param session
+ * the session of the user executing the query.
+ * @param itemMgr
+ * the item manager of the user executing the query. Needed to
+ * return <code>Node</code> instances in the result set.
+ * @param statement
+ * the actual query statement.
+ * @param language
+ * the syntax of the query statement.
+ * @return a <code>Query</code> instance to execute.
+ * @throws InvalidQueryException
+ * if the query is malformed or the <code>language</code> is
+ * unknown.
+ * @throws RepositoryException
+ * if any other error occurs.
+ */
+ public Query createQuery(SessionImpl session, SessionDataManager sessionDataManager, String statement,
+ String language) throws InvalidQueryException, RepositoryException
+ {
+ AbstractQueryImpl query = createQueryInstance();
+ query.init(session, sessionDataManager, handler, statement, language);
+ return query;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Set<String> getFieldNames() throws IndexException
+ {
+ final Set<String> fildsSet = new HashSet<String>();
+ if (handler instanceof SearchIndex)
+ {
+ IndexReader reader = null;
+ try
+ {
+ reader = ((SearchIndex)handler).getIndexReader();
+ final Collection fields = reader.getFieldNames(IndexReader.FieldOption.ALL);
+ for (final Object field : fields)
+ {
+ fildsSet.add((String)field);
+ }
+ }
+ catch (IOException e)
+ {
+ throw new IndexException(e.getLocalizedMessage(), e);
+ }
+ finally
+ {
+ try
+ {
+ if (reader != null)
+ reader.close();
+ }
+ catch (IOException e)
+ {
+ throw new IndexException(e.getLocalizedMessage(), e);
+ }
+ }
+
+ }
+ return fildsSet;
+ }
+
+ /**
+ * just for test use only
+ */
+ public QueryHandler getHandler()
+ {
+
+ return handler;
+ }
+
+ public Set<String> getNodesByNodeType(final InternalQName nodeType) throws RepositoryException
+ {
+
+ return getNodes(virtualTableResolver.resolve(nodeType, true));
+ }
+
+ /**
+ * Return set of uuid of nodes. Contains in names prefixes maped to the
+ * given uri
+ *
+ * @param prefix
+ * @return
+ * @throws RepositoryException
+ */
+ public Set<String> getNodesByUri(final String uri) throws RepositoryException
+ {
+ Set<String> result;
+ final int defaultClauseCount = BooleanQuery.getMaxClauseCount();
+ try
+ {
+
+ // final LocationFactory locationFactory = new
+ // LocationFactory(this);
+ final ValueFactoryImpl valueFactory = new ValueFactoryImpl(new LocationFactory(nsReg));
+ BooleanQuery.setMaxClauseCount(Integer.MAX_VALUE);
+ BooleanQuery query = new BooleanQuery();
+
+ final String prefix = nsReg.getNamespacePrefixByURI(uri);
+ query.add(new WildcardQuery(new Term(FieldNames.LABEL, prefix + ":*")), Occur.SHOULD);
+ // name of the property
+ query.add(new WildcardQuery(new Term(FieldNames.PROPERTIES_SET, prefix + ":*")), Occur.SHOULD);
+
+ result = getNodes(query);
+
+ // value of the property
+
+ try
+ {
+ final Set<String> props = getFieldNames();
+
+ query = new BooleanQuery();
+ for (final String fieldName : props)
+ {
+ if (!FieldNames.PROPERTIES_SET.equals(fieldName))
+ {
+ query.add(new WildcardQuery(new Term(fieldName, "*" + prefix + ":*")), Occur.SHOULD);
+ }
+ }
+ }
+ catch (final IndexException e)
+ {
+ throw new RepositoryException(e.getLocalizedMessage(), e);
+ }
+
+ final Set<String> propSet = getNodes(query);
+ // Manually check property values;
+ for (final String uuid : propSet)
+ {
+ if (isPrefixMatch(valueFactory, uuid, prefix))
+ {
+ result.add(uuid);
+ }
+ }
+ }
+ finally
+ {
+ BooleanQuery.setMaxClauseCount(defaultClauseCount);
+ }
+
+ return result;
+ }
+
+ /**
+ * @see org.exoplatform.services.jcr.dataflow.persistent.ItemsPersistenceListener#onSaveItems(org.exoplatform.services.jcr.dataflow.ItemStateChangesLog)
+ */
+ public void onSaveItems(ItemStateChangesLog itemStates)
+ {
+ //skip empty
+ if (itemStates.getSize() > 0)
+ {
+ //Check if SearchManager started and filter configured
+ if (changesFilter == null)
+ {
+ changesLogBuffer.add(itemStates);
+ }
+ else
+ {
+ changesFilter.onSaveItems(itemStates);
+ }
+ }
+ }
+
+ public void start()
+ {
+
+ if (log.isDebugEnabled())
+ log.debug("start");
+ try
+ {
+ if (indexingTree == null)
+ {
+ List<QPath> excludedPath = new ArrayList<QPath>();
+ // Calculating excluded node identifiers
+ excludedPath.add(Constants.JCR_SYSTEM_PATH);
+
+ //if (config.getExcludedNodeIdentifers() != null)
+ String excludedNodeIdentifer =
+ config.getParameterValue(QueryHandlerParams.PARAM_EXCLUDED_NODE_IDENTIFERS, null);
+ if (excludedNodeIdentifer != null)
+ {
+ StringTokenizer stringTokenizer = new StringTokenizer(excludedNodeIdentifer);
+ while (stringTokenizer.hasMoreTokens())
+ {
+
+ try
+ {
+ ItemData excludeData = itemMgr.getItemData(stringTokenizer.nextToken());
+ if (excludeData != null)
+ excludedPath.add(excludeData.getQPath());
+ }
+ catch (RepositoryException e)
+ {
+ log.warn(e.getLocalizedMessage());
+ }
+ }
+ }
+
+ NodeData indexingRootData = null;
+ String rootNodeIdentifer = config.getParameterValue(QueryHandlerParams.PARAM_ROOT_NODE_ID, null);
+ if (rootNodeIdentifer != null)
+ {
+ try
+ {
+ ItemData indexingRootDataItem = itemMgr.getItemData(rootNodeIdentifer);
+ if (indexingRootDataItem != null && indexingRootDataItem.isNode())
+ indexingRootData = (NodeData)indexingRootDataItem;
+ }
+ catch (RepositoryException e)
+ {
+ log.warn(e.getLocalizedMessage() + " Indexing root set to " + Constants.ROOT_PATH.getAsString());
+
+ }
+
+ }
+ else
+ {
+ try
+ {
+ indexingRootData = (NodeData)itemMgr.getItemData(Constants.ROOT_UUID);
+ // indexingRootData =
+ // new TransientNodeData(Constants.ROOT_PATH, Constants.ROOT_UUID, 1, Constants.NT_UNSTRUCTURED,
+ // new InternalQName[0], 0, null, new AccessControlList());
+ }
+ catch (RepositoryException e)
+ {
+ log.error("Fail to load root node data");
+ }
+ }
+
+ indexingTree = new IndexingTree(indexingRootData, excludedPath);
+ }
+ initializeQueryHandler();
+
+ if (changesLogBuffer.size() > 0)
+ {
+ for (ItemStateChangesLog bufferedChangesLog : changesLogBuffer)
+ {
+ onSaveItems(bufferedChangesLog);
+ }
+ changesLogBuffer.clear();
+ changesLogBuffer = null;
+ }
+
+ }
+ catch (RepositoryException e)
+ {
+ log.error(e.getLocalizedMessage());
+ handler = null;
+ throw new RuntimeException(e.getLocalizedMessage(), e.getCause());
+ }
+ catch (RepositoryConfigurationException e)
+ {
+ log.error(e.getLocalizedMessage());
+ handler = null;
+ throw new RuntimeException(e.getLocalizedMessage(), e.getCause());
+ }
+ }
+
+ public void stop()
+ {
+ handler.close();
+ log.info("Search manager stopped");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void updateIndex(final Set<String> removedNodes, final Set<String> addedNodes) throws RepositoryException,
+ IOException
+ {
+ if (handler != null)
+ {
+ Iterator<NodeData> addedStates = new Iterator<NodeData>()
+ {
+ private final Iterator<String> iter = addedNodes.iterator();
+
+ public boolean hasNext()
+ {
+ return iter.hasNext();
+ }
+
+ public NodeData next()
+ {
+
+ // cycle till find a next or meet the end of set
+ do
+ {
+ String id = iter.next();
+ try
+ {
+ ItemData item = itemMgr.getItemData(id);
+ if (item != null)
+ {
+ if (item.isNode())
+ {
+ if (!indexingTree.isExcluded(item))
+ return (NodeData)item;
+ }
+ else
+ log.warn("Node not found, but property " + id + ", " + item.getQPath().getAsString()
+ + " found. ");
+ }
+ else
+ log.warn("Unable to index node with id " + id + ", node does not exist.");
+
+ }
+ catch (RepositoryException e)
+ {
+ log.error("Can't read next node data " + id, e);
+ }
+ }
+ while (iter.hasNext()); // get next if error or node not found
+
+ return null; // we met the end of iterator set
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+ };
+
+ Iterator<String> removedIds = new Iterator<String>()
+ {
+ private final Iterator<String> iter = removedNodes.iterator();
+
+ public boolean hasNext()
+ {
+ return iter.hasNext();
+ }
+
+ public String next()
+ {
+ return nextNodeId();
+ }
+
+ public String nextNodeId() throws NoSuchElementException
+ {
+ return iter.next();
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+
+ }
+ };
+
+ if (removedNodes.size() > 0 || addedNodes.size() > 0)
+ {
+ handler.updateNodes(removedIds, addedStates);
+ }
+ }
+
+ }
+
+ protected QueryHandlerContext createQueryHandlerContext(QueryHandler parentHandler)
+ throws RepositoryConfigurationException
+ {
+
+ QueryHandlerContext context =
+ new QueryHandlerContext(itemMgr, indexingTree, nodeTypeDataManager, nsReg, parentHandler, getIndexDir(),
+ extractor, true, virtualTableResolver);
+ return context;
+ }
+
+ /**
+ * Creates a new instance of an {@link AbstractQueryImpl} which is not
+ * initialized.
+ *
+ * @return an new query instance.
+ * @throws RepositoryException
+ * if an error occurs while creating a new query instance.
+ */
+ protected AbstractQueryImpl createQueryInstance() throws RepositoryException
+ {
+ try
+ {
+ String queryImplClassName = handler.getQueryClass();
+ Object obj = Class.forName(queryImplClassName).newInstance();
+ if (obj instanceof AbstractQueryImpl)
+ {
+ return (AbstractQueryImpl)obj;
+ }
+ else
+ {
+ throw new IllegalArgumentException(queryImplClassName + " is not of type "
+ + AbstractQueryImpl.class.getName());
+ }
+ }
+ catch (Throwable t)
+ {
+ throw new RepositoryException("Unable to create query: " + t.toString(), t);
+ }
+ }
+
+ protected String getIndexDir() throws RepositoryConfigurationException
+ {
+ String dir = config.getParameterValue(QueryHandlerParams.PARAM_INDEX_DIR, null);
+ if (dir == null)
+ {
+ log.warn(QueryHandlerParams.PARAM_INDEX_DIR + " parameter not found. Using outdated parameter name "
+ + QueryHandlerParams.OLD_PARAM_INDEX_DIR);
+ dir = config.getParameterValue(QueryHandlerParams.OLD_PARAM_INDEX_DIR);
+ }
+ return dir;
+ }
+
+ /**
+ * @return the indexingTree
+ */
+ protected IndexingTree getIndexingTree()
+ {
+ return indexingTree;
+ }
+
+ /**
+ * Initialize changes filter.
+ * @throws RepositoryException
+ * @throws RepositoryConfigurationException
+ * @throws ClassNotFoundException
+ * @throws NoSuchMethodException
+ * @throws SecurityException
+ */
+ protected IndexerChangesFilter initializeChangesFilter() throws RepositoryException,
+ RepositoryConfigurationException
+
+ {
+ IndexerChangesFilter newChangesFilter = null;
+ Class<? extends IndexerChangesFilter> changesFilterClass = DefaultChangesFilter.class;
+ String changesFilterClassName = config.getParameterValue(QueryHandlerParams.PARAM_CHANGES_FILTER_CLASS, null);
+ try
+ {
+ if (changesFilterClassName != null)
+ {
+ changesFilterClass =
+ (Class<? extends IndexerChangesFilter>)Class.forName(changesFilterClassName, true, this.getClass()
+ .getClassLoader());
+ }
+ Constructor<? extends IndexerChangesFilter> constuctor =
+ changesFilterClass.getConstructor(SearchManager.class, SearchManager.class, QueryHandlerEntry.class,
+ IndexingTree.class, IndexingTree.class, QueryHandler.class, QueryHandler.class);
+ if (parentSearchManager != null)
+ {
+ newChangesFilter =
+ constuctor.newInstance(this, parentSearchManager, config, indexingTree, parentSearchManager
+ .getIndexingTree(), handler, parentSearchManager.getHandler());
+ }
+ }
+ catch (SecurityException e)
+ {
+ throw new RepositoryException(e.getMessage(), e);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new RepositoryException(e.getMessage(), e);
+ }
+ catch (ClassNotFoundException e)
+ {
+ throw new RepositoryException(e.getMessage(), e);
+ }
+ catch (NoSuchMethodException e)
+ {
+ throw new RepositoryException(e.getMessage(), e);
+ }
+ catch (InstantiationException e)
+ {
+ throw new RepositoryException(e.getMessage(), e);
+ }
+ catch (IllegalAccessException e)
+ {
+ throw new RepositoryException(e.getMessage(), e);
+ }
+ catch (InvocationTargetException e)
+ {
+ throw new RepositoryException(e.getMessage(), e);
+ }
+ return newChangesFilter;
+ }
+
+ /**
+ * Initializes the query handler.
+ *
+ * @throws RepositoryException
+ * if the query handler cannot be initialized.
+ * @throws RepositoryConfigurationException
+ * @throws ClassNotFoundException
+ */
+ protected void initializeQueryHandler() throws RepositoryException, RepositoryConfigurationException
+ {
+ // initialize query handler
+ String className = config.getType();
+ if (className == null)
+ throw new RepositoryConfigurationException("Content hanler configuration fail");
+
+ try
+ {
+ Class qHandlerClass = Class.forName(className, true, this.getClass().getClassLoader());
+ Constructor constuctor = qHandlerClass.getConstructor(QueryHandlerEntry.class, ConfigurationManager.class);
+ handler = (QueryHandler)constuctor.newInstance(config, cfm);
+ QueryHandler parentHandler = (this.parentSearchManager != null) ? parentSearchManager.getHandler() : null;
+ QueryHandlerContext context = createQueryHandlerContext(parentHandler);
+ handler.setContext(context);
+
+ if (parentSearchManager != null)
+ {
+ changesFilter = initializeChangesFilter();
+ }
+ }
+ catch (SecurityException e)
+ {
+ throw new RepositoryException(e.getMessage(), e);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new RepositoryException(e.getMessage(), e);
+ }
+ catch (ClassNotFoundException e)
+ {
+ throw new RepositoryException(e.getMessage(), e);
+ }
+ catch (NoSuchMethodException e)
+ {
+ throw new RepositoryException(e.getMessage(), e);
+ }
+ catch (InstantiationException e)
+ {
+ throw new RepositoryException(e.getMessage(), e);
+ }
+ catch (IllegalAccessException e)
+ {
+ throw new RepositoryException(e.getMessage(), e);
+ }
+ catch (InvocationTargetException e)
+ {
+ throw new RepositoryException(e.getMessage(), e);
+ }
+ }
+
+ /**
+ * @param query
+ * @return
+ * @throws RepositoryException
+ */
+ private Set<String> getNodes(final org.apache.lucene.search.Query query) throws RepositoryException
+ {
+ Set<String> result = new HashSet<String>();
+ try
+ {
+ QueryHits hits = handler.executeQuery(query);
+
+ ScoreNode sn;
+
+ while ((sn = hits.nextScoreNode()) != null)
+ {
+ // Node node = session.getNodeById(sn.getNodeId());
+ result.add(sn.getNodeId());
+ }
+ }
+ catch (IOException e)
+ {
+ throw new RepositoryException(e.getLocalizedMessage(), e);
+ }
+ return result;
+ }
+
+ private boolean isPrefixMatch(final InternalQName value, final String prefix) throws RepositoryException
+ {
+ return value.getNamespace().equals(nsReg.getNamespaceURIByPrefix(prefix));
+ }
+
+ private boolean isPrefixMatch(final QPath value, final String prefix) throws RepositoryException
+ {
+ for (int i = 0; i < value.getEntries().length; i++)
+ {
+ if (isPrefixMatch(value.getEntries()[i], prefix))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @param valueFactory
+ * @param dm
+ * @param uuid
+ * @param prefix
+ * @throws RepositoryException
+ */
+ private boolean isPrefixMatch(final ValueFactoryImpl valueFactory, final String uuid, final String prefix)
+ throws RepositoryException
+ {
+
+ final ItemData node = itemMgr.getItemData(uuid);
+ if (node != null && node.isNode())
+ {
+ final List<PropertyData> props = itemMgr.getChildPropertiesData((NodeData)node);
+ for (final PropertyData propertyData : props)
+ {
+ if (propertyData.getType() == PropertyType.PATH || propertyData.getType() == PropertyType.NAME)
+ {
+ for (final ValueData vdata : propertyData.getValues())
+ {
+ final Value val =
+ valueFactory.loadValue(((AbstractValueData)vdata).createTransientCopy(), propertyData.getType());
+ if (propertyData.getType() == PropertyType.PATH)
+ {
+ if (isPrefixMatch(((PathValue)val).getQPath(), prefix))
+ {
+ return true;
+ }
+ }
+ else if (propertyData.getType() == PropertyType.NAME)
+ {
+ if (isPrefixMatch(((NameValue)val).getQName(), prefix))
+ {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+}
Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SystemSearchManager.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SystemSearchManager.java 2009-12-22 10:32:33 UTC (rev 1143)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SystemSearchManager.java 2009-12-22 13:29:21 UTC (rev 1144)
@@ -21,7 +21,6 @@
import org.exoplatform.services.jcr.config.QueryHandlerEntry;
import org.exoplatform.services.jcr.config.RepositoryConfigurationException;
import org.exoplatform.services.jcr.core.nodetype.NodeTypeDataManager;
-import org.exoplatform.services.jcr.dataflow.ItemStateChangesLog;
import org.exoplatform.services.jcr.datamodel.NodeData;
import org.exoplatform.services.jcr.datamodel.QPath;
import org.exoplatform.services.jcr.impl.Constants;
@@ -55,10 +54,16 @@
*/
private boolean isStarted = false;
- /**
- * ChangesLog Buffer (used for saves before start).
- */
- private List<ItemStateChangesLog> changesLogBuffer = new ArrayList<ItemStateChangesLog>();
+ //
+ // /**
+ // * ChangesLog Buffer (used for saves before start).
+ // */
+ // private List<ItemStateChangesLog> changesLogBuffer = new ArrayList<ItemStateChangesLog>();
+ //
+ // /**
+ // * ChangesLog Buffer (used for saves before start).
+ // */
+ // private List<List<WriteCommand>> writeCommandBuffer = new ArrayList<List<WriteCommand>>();
public static final String INDEX_DIR_SUFFIX = "system";
@@ -69,69 +74,166 @@
super(config, nsReg, ntReg, itemMgr, null, service, cfm, indexSearcherHolder);
}
+ // @Override
+ // public void onSaveItems(ItemStateChangesLog changesLog)
+ // {
+ // if (!isStarted)
+ // {
+ // changesLogBuffer.add(changesLog);
+ // }
+ // else
+ // {
+ // super.onSaveItems(changesLog);
+ // }
+ // }
+
@Override
- public void onSaveItems(ItemStateChangesLog changesLog)
+ public void start()
{
if (!isStarted)
{
- changesLogBuffer.add(changesLog);
- }
- else
- {
- super.onSaveItems(changesLog);
- }
- }
- @Override
- public void start()
- {
-
- isStarted = true;
- try
- {
- if (indexingTree == null)
+ try
{
- List<QPath> excludedPaths = new ArrayList<QPath>();
+ if (indexingTree == null)
+ {
+ List<QPath> excludedPaths = new ArrayList<QPath>();
- NodeData indexingRootNodeData = (NodeData)itemMgr.getItemData(Constants.SYSTEM_UUID);
+ NodeData indexingRootNodeData = (NodeData)itemMgr.getItemData(Constants.SYSTEM_UUID);
- indexingTree = new IndexingTree(indexingRootNodeData, excludedPaths);
+ indexingTree = new IndexingTree(indexingRootNodeData, excludedPaths);
+ }
+ initializeQueryHandler();
+
}
- initializeQueryHandler();
+ catch (RepositoryException e)
+ {
+ log.error(e.getLocalizedMessage());
+ handler = null;
+ //freeBuffers();
+ throw new RuntimeException(e);
+ }
+ catch (RepositoryConfigurationException e)
+ {
+ log.error(e.getLocalizedMessage());
+ handler = null;
+ //freeBuffers();
+ throw new RuntimeException(e);
+ }
+ isStarted = true;
}
-
- catch (RepositoryException e)
- {
- log.error(e.getLocalizedMessage());
- handler = null;
- changesLogBuffer.clear();
- changesLogBuffer = null;
- throw new RuntimeException(e);
- }
- catch (RepositoryConfigurationException e)
- {
- log.error(e.getLocalizedMessage());
- handler = null;
- changesLogBuffer.clear();
- changesLogBuffer = null;
- throw new RuntimeException(e);
- }
- for (ItemStateChangesLog bufferedChangesLog : changesLogBuffer)
- {
- super.onSaveItems(bufferedChangesLog);
- }
- changesLogBuffer.clear();
- changesLogBuffer = null;
+ // if (changesLogBuffer.size() > 0)
+ // {
+ // for (ItemStateChangesLog bufferedChangesLog : changesLogBuffer)
+ // {
+ // super.onSaveItems(bufferedChangesLog);
+ // }
+ //
+ // }
+ //
+ // if (writeCommandBuffer.size() > 0)
+ // {
+ // try
+ // {
+ // for (List<WriteCommand> bufferedWriteLog : writeCommandBuffer)
+ // {
+ // super.onSaveItems(bufferedWriteLog);
+ // }
+ // }
+ // catch (RepositoryException e)
+ // {
+ // freeBuffers();
+ // throw new RuntimeException(e);
+ //
+ // }
+ // }
+ // freeBuffers();
}
+ // /**
+ // * @see org.exoplatform.services.jcr.impl.core.query.SearchManager#initializeChangesFilter()
+ // */
+ // @Override
+ // protected void initializeChangesFilter() throws RepositoryException, RepositoryConfigurationException
+ // {
+ // Class<? extends IndexerChangesFilter> changesFilterClass = DefaultChangesFilter.class;
+ // String changesFilterClassName = config.getParameterValue(QueryHandlerParams.PARAM_CHANGES_FILTER_CLASS, null);
+ // try
+ // {
+ // if (changesFilterClassName != null)
+ // {
+ // changesFilterClass =
+ // (Class<? extends IndexerChangesFilter>)Class.forName(changesFilterClassName, true, this.getClass()
+ // .getClassLoader());
+ // }
+ // Constructor<? extends IndexerChangesFilter> constuctor =
+ // changesFilterClass.getConstructor(SearchManager.class, QueryHandlerEntry.class, Boolean.class,
+ // IndexingTree.class);
+ // changesFilter = constuctor.newInstance(this, config, true, indexingTree);
+ // }
+ // catch (SecurityException e)
+ // {
+ // throw new RepositoryException(e.getMessage(), e);
+ // }
+ // catch (IllegalArgumentException e)
+ // {
+ // throw new RepositoryException(e.getMessage(), e);
+ // }
+ // catch (ClassNotFoundException e)
+ // {
+ // throw new RepositoryException(e.getMessage(), e);
+ // }
+ // catch (NoSuchMethodException e)
+ // {
+ // throw new RepositoryException(e.getMessage(), e);
+ // }
+ // catch (InstantiationException e)
+ // {
+ // throw new RepositoryException(e.getMessage(), e);
+ // }
+ // catch (IllegalAccessException e)
+ // {
+ // throw new RepositoryException(e.getMessage(), e);
+ // }
+ // catch (InvocationTargetException e)
+ // {
+ // throw new RepositoryException(e.getMessage(), e);
+ // }
+ // }
+
+ // private void freeBuffers()
+ // {
+ // changesLogBuffer.clear();
+ // changesLogBuffer = null;
+ // writeCommandBuffer.clear();
+ // writeCommandBuffer = null;
+ // }
+
@Override
protected QueryHandlerContext createQueryHandlerContext(QueryHandler parentHandler)
throws RepositoryConfigurationException
{
QueryHandlerContext context =
new QueryHandlerContext(itemMgr, indexingTree, nodeTypeDataManager, nsReg, parentHandler, getIndexDir() + "_"
- + INDEX_DIR_SUFFIX, extractor, changesLogBuffer.size() > 0 && !isStarted, virtualTableResolver);
+ + INDEX_DIR_SUFFIX, extractor, true, virtualTableResolver);
return context;
}
+ //
+ // /* (non-Javadoc)
+ // * @see org.exoplatform.services.jcr.impl.core.query.SearchManager#onSaveItems(java.util.List)
+ // */
+ // @Override
+ // public void onSaveItems(List<WriteCommand> modifications) throws RepositoryException
+ // {
+ // if (!isStarted)
+ // {
+ // writeCommandBuffer.add(modifications);
+ // }
+ // else
+ // {
+ // super.onSaveItems(modifications);
+ // }
+ //
+ // }
}
Added: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/ChangesFilterListsWrapper.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/ChangesFilterListsWrapper.java (rev 0)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/ChangesFilterListsWrapper.java 2009-12-22 13:29:21 UTC (rev 1144)
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2009 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.core.query.jbosscache;
+
+import java.io.Serializable;
+import java.util.Set;
+
+/**
+ * FOR TESTING PURPOSES ONLY. Used to avoid batching usage in indexer cache.
+ *
+ * @author <a href="mailto:nikolazius@gmail.com">Nikolay Zamosenchuk</a>
+ * @version $Id: ChangesFilterListsWrapper.java 34360 2009-07-22 23:58:59Z nzamosenchuk $
+ *
+ */
+public class ChangesFilterListsWrapper implements Serializable
+{
+ private static final long serialVersionUID = 1L;
+
+ private Set<String> addedNodes;
+
+ private Set<String> removedNodes;
+
+ private Set<String> parentAddedNodes;
+
+ private Set<String> parentRemovedNodes;
+
+ /**
+ * Creates ChangesFilterListsWrapper data class, containing given lists.
+ *
+ * @param addedNodes
+ * @param removedNodes
+ * @param parentAddedNodes
+ * @param parentRemovedNodes
+ */
+ public ChangesFilterListsWrapper(Set<String> addedNodes, Set<String> removedNodes, Set<String> parentAddedNodes,
+ Set<String> parentRemovedNodes)
+ {
+ this.addedNodes = addedNodes;
+ this.removedNodes = removedNodes;
+ this.parentAddedNodes = parentAddedNodes;
+ this.parentRemovedNodes = parentRemovedNodes;
+ }
+
+ public Set<String> getAddedNodes()
+ {
+ return addedNodes;
+ }
+
+ public Set<String> getRemovedNodes()
+ {
+ return removedNodes;
+ }
+
+ public Set<String> getParentAddedNodes()
+ {
+ return parentAddedNodes;
+ }
+
+ public Set<String> getParentRemovedNodes()
+ {
+ return parentRemovedNodes;
+ }
+
+ public String dump()
+ {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("\n");
+ buffer.append("Added=").append(addedNodes.toString()).append("\n");
+ buffer.append("Removed=").append(removedNodes.toString()).append("\n");
+ buffer.append("ParentAdded=").append(parentAddedNodes.toString()).append("\n");
+ buffer.append("ParentRemoved=").append(parentRemovedNodes.toString());
+ return buffer.toString();
+ }
+}
Property changes on: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/ChangesFilterListsWrapper.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/IndexerCacheLoader.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/IndexerCacheLoader.java (rev 0)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/IndexerCacheLoader.java 2009-12-22 13:29:21 UTC (rev 1144)
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2003-2009 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.core.query.jbosscache;
+
+import org.exoplatform.services.jcr.config.RepositoryConfigurationException;
+import org.exoplatform.services.jcr.impl.core.query.IndexerIoMode;
+import org.exoplatform.services.jcr.impl.core.query.QueryHandler;
+import org.exoplatform.services.jcr.impl.core.query.SearchManager;
+import org.exoplatform.services.jcr.impl.storage.jbosscache.AbstractWriteOnlyCacheLoader;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.Modification;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Set;
+
+import javax.jcr.RepositoryException;
+
+/**
+ * @author <a href="mailto:nikolazius@gmail.com">Nikolay Zamosenchuk</a>
+ * @version $Id: IndexerCacheLoader.java 34360 2009-07-22 23:58:59Z nzamosenchuk $
+ *
+ */
+public class IndexerCacheLoader extends AbstractWriteOnlyCacheLoader
+{
+ private final Log log = ExoLogger.getLogger(this.getClass().getName());
+
+ private SearchManager searchManager;
+
+ private SearchManager parentSearchManager;
+
+ private QueryHandler handler;
+
+ private QueryHandler parentHandler;
+
+ /**
+ * Inject dependencies needed for CacheLoader: SearchManagers and QueryHandlers.
+ *
+ * @param searchManager
+ * @param parentSearchManager
+ * @param handler
+ * @param parentHandler
+ * @throws RepositoryConfigurationException
+ */
+ public void init(SearchManager searchManager, SearchManager parentSearchManager, QueryHandler handler,
+ QueryHandler parentHandler) throws RepositoryConfigurationException
+ {
+ this.searchManager = searchManager;
+ this.parentSearchManager = parentSearchManager;
+ this.handler = handler;
+ this.parentHandler = parentHandler;
+ }
+
+ /**
+ * @see org.exoplatform.services.jcr.impl.storage.jbosscache.AbstractWriteOnlyCacheLoader#put(org.jboss.cache.Fqn, java.lang.Object, java.lang.Object)
+ */
+ @Override
+ public Object put(Fqn arg0, Object key, Object val) throws Exception
+ {
+ if (key.equals(JbossCacheIndexChangesFilter.LISTWRAPPER) && val instanceof ChangesFilterListsWrapper)
+ {
+ if (log.isDebugEnabled())
+ {
+ log.info("Received list wrapper, start indexing...");
+ }
+ ChangesFilterListsWrapper wrapper = (ChangesFilterListsWrapper)val;
+ updateIndex(wrapper.getAddedNodes(), wrapper.getRemovedNodes(), wrapper.getParentAddedNodes(), wrapper
+ .getParentRemovedNodes());
+ }
+ return null;
+ }
+
+ /**
+ * Flushes lists of added/removed nodes to SearchManagers, starting indexing.
+ *
+ * @param addedNodes
+ * @param removedNodes
+ * @param parentAddedNodes
+ * @param parentRemovedNodes
+ */
+ protected void updateIndex(Set<String> addedNodes, Set<String> removedNodes, Set<String> parentAddedNodes,
+ Set<String> parentRemovedNodes)
+ {
+ // pass lists to search manager
+ if (searchManager != null && (addedNodes.size() > 0 || removedNodes.size() > 0))
+ {
+ try
+ {
+ searchManager.updateIndex(removedNodes, addedNodes);
+ }
+ catch (RepositoryException e)
+ {
+ log.error("Error indexing changes " + e, e);
+ }
+ catch (IOException e)
+ {
+ log.error("Error indexing changes " + e, e);
+ try
+ {
+ handler.logErrorChanges(removedNodes, addedNodes);
+ }
+ catch (IOException ioe)
+ {
+ log.warn("Exception occure when errorLog writed. Error log is not complete. " + ioe, ioe);
+ }
+ }
+ }
+ // pass lists to parent search manager
+ if (parentSearchManager != null && (parentAddedNodes.size() > 0 || parentRemovedNodes.size() > 0))
+ {
+ try
+ {
+ parentSearchManager.updateIndex(parentRemovedNodes, parentAddedNodes);
+ }
+ catch (RepositoryException e)
+ {
+ log.error("Error indexing changes " + e, e);
+ }
+ catch (IOException e)
+ {
+ log.error("Error indexing changes " + e, e);
+ try
+ {
+ parentHandler.logErrorChanges(removedNodes, addedNodes);
+ }
+ catch (IOException ioe)
+ {
+ log.warn("Exception occure when errorLog writed. Error log is not complete. " + ioe, ioe);
+ }
+ }
+ }
+ }
+
+ /**
+ * Switches Indexer mode from RO to RW, or from RW to RO
+ *
+ * @param ioMode
+ */
+ public void setMode(IndexerIoMode ioMode)
+ {
+ try
+ {
+ if (handler != null)
+ {
+ handler.setIndexerIoMode(ioMode);
+ }
+ if (parentHandler != null)
+ {
+ parentHandler.setIndexerIoMode(ioMode);
+ }
+ }
+ catch (IOException e)
+ {
+ log.error("Unable to set indexer mode to " + ioMode, e);
+ }
+ }
+
+ /**
+ * @see org.exoplatform.services.jcr.impl.storage.jbosscache.AbstractWriteOnlyCacheLoader#put(java.util.List)
+ */
+ @Override
+ public void put(List<Modification> modifications) throws Exception
+ {
+ // batching is not used
+ }
+}
Property changes on: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/IndexerCacheLoader.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/IndexerSingletonStoreCacheLoader.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/IndexerSingletonStoreCacheLoader.java (rev 0)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/IndexerSingletonStoreCacheLoader.java 2009-12-22 13:29:21 UTC (rev 1144)
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2009 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.core.query.jbosscache;
+
+import org.exoplatform.services.jcr.impl.core.query.IndexerIoMode;
+import org.exoplatform.services.jcr.util.IdGenerator;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.NodeSPI;
+import org.jboss.cache.loader.SingletonStoreCacheLoader;
+import org.jboss.cache.notifications.annotation.CacheListener;
+import org.jboss.cache.notifications.annotation.CacheStarted;
+import org.jboss.cache.notifications.event.Event;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.Callable;
+
+/**
+ * @author <a href="mailto:nikolazius@gmail.com">Nikolay Zamosenchuk</a>
+ * @version $Id: IndexerSingletonStoreCacheLoader.java 1008 2009-12-11 15:14:51Z nzamosenchuk $
+ *
+ */
+public class IndexerSingletonStoreCacheLoader extends SingletonStoreCacheLoader
+{
+ private final Log log = ExoLogger.getLogger(this.getClass().getName());
+
+ /**
+ * @see org.jboss.cache.loader.SingletonStoreCacheLoader#activeStatusChanged(boolean)
+ */
+ @Override
+ protected void activeStatusChanged(boolean newActiveState) throws PushStateException
+ {
+ // at first change indexer mode
+ setIndexerMode(newActiveState);
+ // and them push states if needed
+ super.activeStatusChanged(newActiveState);
+ }
+
+ @Override
+ protected Callable<?> createPushStateTask()
+ {
+ return new Callable()
+ {
+ public Object call() throws Exception
+ {
+ final boolean debugEnabled = log.isDebugEnabled();
+
+ if (debugEnabled)
+ log.debug("start pushing in-memory state to cache cacheLoader collection");
+
+ final Set<String> removedNodes = new HashSet<String>();
+ final Set<String> addedNodes = new HashSet<String>();
+ final Set<String> parentRemovedNodes = new HashSet<String>();
+ final Set<String> parentAddedNodes = new HashSet<String>();
+ // merging all lists stored in memory
+ Collection<NodeSPI> children = cache.getRoot().getChildren();
+ for (NodeSPI aChildren : children)
+ {
+ Fqn<?> fqn = aChildren.getFqn();
+ Object value = cache.get(fqn, JbossCacheIndexChangesFilter.LISTWRAPPER);
+ if (value != null && value instanceof ChangesFilterListsWrapper)
+ {
+ // get wrapper object
+ ChangesFilterListsWrapper listsWrapper = (ChangesFilterListsWrapper)value;
+ // get search manager lists
+ addedNodes.addAll(listsWrapper.getAddedNodes());
+ removedNodes.addAll(listsWrapper.getRemovedNodes());
+ // parent search manager lists
+ parentAddedNodes.addAll(listsWrapper.getParentAddedNodes());
+ parentRemovedNodes.addAll(listsWrapper.getParentAddedNodes());
+ };
+ }
+ //TODO: recover logic is here, lists are: removedNodes and addedNodes String id = IdGenerator.generate();
+ String id = IdGenerator.generate();
+ cache.put(id, JbossCacheIndexChangesFilter.LISTWRAPPER, new ChangesFilterListsWrapper(addedNodes,
+ removedNodes, parentAddedNodes, parentRemovedNodes));
+ if (debugEnabled)
+ log.debug("in-memory state passed to cache cacheLoader successfully");
+ return null;
+ }
+ };
+ }
+
+ /**
+ * Sets/changes indexer mode
+ *
+ * @param writeEnabled
+ */
+ protected void setIndexerMode(boolean writeEnabled)
+ {
+ // get base cache loader that is configured under SingletonStoreCacheLoader
+ // if it is IndexerCacheLoader need to call setMode(ioMode)
+ if (getCacheLoader() instanceof IndexerCacheLoader)
+ {
+ // if newActiveState is true IndexerCacheLoader is coordinator with write enabled;
+ ((IndexerCacheLoader)getCacheLoader()).setMode(writeEnabled ? IndexerIoMode.READ_WRITE
+ : IndexerIoMode.READ_ONLY);
+ log.info("Set indexer io mode to:" + (writeEnabled ? IndexerIoMode.READ_WRITE : IndexerIoMode.READ_ONLY));
+ }
+ }
+}
Property changes on: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/IndexerSingletonStoreCacheLoader.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/JbossCacheIndexChangesFilter.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/JbossCacheIndexChangesFilter.java (rev 0)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/JbossCacheIndexChangesFilter.java 2009-12-22 13:29:21 UTC (rev 1144)
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2009 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.core.query.jbosscache;
+
+import org.exoplatform.services.jcr.config.QueryHandlerEntry;
+import org.exoplatform.services.jcr.config.QueryHandlerParams;
+import org.exoplatform.services.jcr.config.RepositoryConfigurationException;
+import org.exoplatform.services.jcr.impl.core.query.IndexerChangesFilter;
+import org.exoplatform.services.jcr.impl.core.query.IndexerIoMode;
+import org.exoplatform.services.jcr.impl.core.query.IndexingTree;
+import org.exoplatform.services.jcr.impl.core.query.QueryHandler;
+import org.exoplatform.services.jcr.impl.core.query.SearchManager;
+import org.exoplatform.services.jcr.util.IdGenerator;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+import org.jboss.cache.Cache;
+import org.jboss.cache.CacheFactory;
+import org.jboss.cache.CacheSPI;
+import org.jboss.cache.DefaultCacheFactory;
+import org.jboss.cache.config.CacheLoaderConfig;
+import org.jboss.cache.config.CacheLoaderConfig.IndividualCacheLoaderConfig;
+import org.jboss.cache.config.CacheLoaderConfig.IndividualCacheLoaderConfig.SingletonStoreConfig;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.jcr.RepositoryException;
+
+/**
+ * @author <a href="mailto:Sergey.Kabashnyuk@exoplatform.org">Sergey Kabashnyuk</a>
+ * @version $Id: exo-jboss-codetemplates.xml 34360 2009-07-22 23:58:59Z ksm $
+ *
+ */
+public class JbossCacheIndexChangesFilter extends IndexerChangesFilter
+{
+ /**
+ * Logger instance for this class
+ */
+ private final Log log = ExoLogger.getLogger(JbossCacheIndexChangesFilter.class);
+
+ private final Cache<Serializable, Object> cache;
+
+ public static String ADDED = "$add".intern();
+
+ public static String REMOVED = "$remove".intern();
+
+ public static String PARENT_ADDED = "$padd".intern();
+
+ public static String PARENT_REMOVED = "$premove".intern();
+
+ public static String LISTWRAPPER = "$lists".intern();
+
+ /**
+ * @param searchManager
+ * @param config
+ * @param indexingTree
+ * @throws RepositoryConfigurationException
+ */
+ public JbossCacheIndexChangesFilter(SearchManager searchManager, SearchManager parentSearchManager,
+ QueryHandlerEntry config, IndexingTree indexingTree, IndexingTree parentIndexingTree, QueryHandler handler,
+ QueryHandler parentHandler) throws IOException, RepositoryException, RepositoryConfigurationException
+ {
+ super(searchManager, parentSearchManager, config, indexingTree, parentIndexingTree, handler, parentHandler);
+ String jbcConfig = config.getParameterValue(QueryHandlerParams.PARAM_CHANGES_FILTER_CONFIG_PATH);
+ CacheFactory<Serializable, Object> factory = new DefaultCacheFactory<Serializable, Object>();
+ log.info("JBoss Cache configuration used: " + jbcConfig);
+ this.cache = factory.createCache(jbcConfig, false);
+
+ // initialize IndexerCacheLoader
+ IndexerCacheLoader indexerCacheLoader = new IndexerCacheLoader();
+ // inject dependencies
+ indexerCacheLoader.init(searchManager, parentSearchManager, handler, parentHandler);
+ // set SingltonStoreCacheLoader
+ SingletonStoreConfig singletonStoreConfig = new SingletonStoreConfig();
+ singletonStoreConfig.setSingletonStoreClass(IndexerSingletonStoreCacheLoader.class.getName());
+ //singletonStoreConfig.setSingletonStoreClass(SingletonStoreCacheLoader.class.getName());
+ Properties singletonStoreProperties = new Properties();
+ singletonStoreProperties.setProperty("pushStateWhenCoordinator", "false");
+ singletonStoreProperties.setProperty("pushStateWhenCoordinatorTimeout", "10000");
+ singletonStoreConfig.setProperties(singletonStoreProperties);
+ singletonStoreConfig.setSingletonStoreEnabled(true);
+ // create CacheLoaderConfig
+ IndividualCacheLoaderConfig individualCacheLoaderConfig = new IndividualCacheLoaderConfig();
+ // set SingletonStoreConfig
+ individualCacheLoaderConfig.setSingletonStoreConfig(singletonStoreConfig);
+ // set CacheLoader
+ individualCacheLoaderConfig.setCacheLoader(indexerCacheLoader);
+ // set parameters
+ individualCacheLoaderConfig.setFetchPersistentState(false);
+ individualCacheLoaderConfig.setAsync(false);
+ individualCacheLoaderConfig.setIgnoreModifications(false);
+ individualCacheLoaderConfig.setPurgeOnStartup(false);
+ // create CacheLoaderConfig
+ CacheLoaderConfig cacheLoaderConfig = new CacheLoaderConfig();
+ cacheLoaderConfig.setShared(false);
+ cacheLoaderConfig.setPassivation(false);
+ cacheLoaderConfig.addIndividualCacheLoaderConfig(individualCacheLoaderConfig);
+ // insert CacheLoaderConfig
+ this.cache.getConfiguration().setCacheLoaderConfig(cacheLoaderConfig);
+ this.cache.create();
+ this.cache.start();
+ // start will invoke cache listener which will notify handler that mode is changed
+ IndexerIoMode ioMode =
+ ((CacheSPI)cache).getRPCManager().isCoordinator() ? IndexerIoMode.READ_WRITE : IndexerIoMode.READ_ONLY;
+
+ handler.setIndexerIoMode(ioMode);
+ parentHandler.setIndexerIoMode(ioMode);
+
+ if (!parentHandler.isInitialized())
+ {
+ parentHandler.init();
+ }
+ if (!handler.isInitialized())
+ {
+ handler.init();
+ }
+
+ }
+
+ /**
+ * @see org.exoplatform.services.jcr.impl.core.query.IndexerChangesFilter#doUpdateIndex(java.util.Set, java.util.Set, java.util.Set, java.util.Set)
+ */
+ @Override
+ protected void doUpdateIndex(Set<String> removedNodes, Set<String> addedNodes, Set<String> parentRemovedNodes,
+ Set<String> parentAddedNodes)
+ {
+ String id = IdGenerator.generate();
+ cache.put(id, LISTWRAPPER, new ChangesFilterListsWrapper(addedNodes, removedNodes, parentAddedNodes,
+ parentRemovedNodes));
+ }
+
+}
Property changes on: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/jbosscache/JbossCacheIndexChangesFilter.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/IndexInfos.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/IndexInfos.java 2009-12-22 10:32:33 UTC (rev 1143)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/IndexInfos.java 2009-12-22 13:29:21 UTC (rev 1144)
@@ -152,6 +152,15 @@
}
/**
+ * Returns the index name at position <code>i</code>.
+ * @param i the position.
+ * @return the index name.
+ */
+ Set<String> getNames() {
+ return new HashSet<String>(indexes);
+ }
+
+ /**
* Returns the number of index names.
* @return the number of index names.
*/
Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/LuceneQueryBuilder.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/LuceneQueryBuilder.java 2009-12-22 10:32:33 UTC (rev 1143)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/LuceneQueryBuilder.java 2009-12-22 13:29:21 UTC (rev 1144)
@@ -775,27 +775,18 @@
}, null);
QPath relPath = node.getRelativePath();
-
- InternalQName propName;
-
if (node.getOperation() == QueryConstants.OPERATION_SIMILAR)
{
// this is a bit ugly:
// add the name of a dummy property because relPath actually
// references a property. whereas the relPath of the similar
// operation references a node
- //relPath = QPath.makeChildPath(relPath, Constants.JCR_PRIMARYTYPE);
- propName = Constants.JCR_PRIMARYTYPE;
+ relPath = QPath.makeChildPath(relPath, Constants.JCR_PRIMARYTYPE);
}
- else
- {
- propName = relPath.getName();
- }
-
String field = "";
try
{
- field = resolver.createJCRName(propName).getAsString();
+ field = resolver.createJCRName(relPath.getName()).getAsString();
}
catch (NamespaceException e)
{
@@ -804,7 +795,7 @@
}
// support for fn:name()
- //InternalQName propName = relPath.getName();
+ InternalQName propName = relPath.getName();
if (propName.getNamespace().equals(NS_FN_URI) && propName.getName().equals("name()"))
{
if (node.getValueType() != QueryConstants.TYPE_STRING)
@@ -1062,7 +1053,7 @@
}
}
- if (relPath != null && relPath.getEntries().length > 1)
+ if (relPath.getEntries().length > 1)
{
// child axis in relation
QPathEntry[] elements = relPath.getEntries();
Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/MultiIndex.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/MultiIndex.java 2009-12-22 10:32:33 UTC (rev 1143)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/MultiIndex.java 2009-12-22 13:29:21 UTC (rev 1144)
@@ -24,11 +24,13 @@
import org.exoplatform.services.jcr.datamodel.ItemData;
import org.exoplatform.services.jcr.datamodel.NodeData;
import org.exoplatform.services.jcr.impl.Constants;
+import org.exoplatform.services.jcr.impl.core.query.IndexerIoMode;
import org.exoplatform.services.jcr.impl.core.query.IndexingTree;
import org.exoplatform.services.jcr.impl.core.query.lucene.directory.DirectoryManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
@@ -73,2024 +75,2400 @@
* thread and reader threads is done using {@link #updateMonitor} and
* {@link #updateInProgress}.
*/
-public class MultiIndex {
+public class MultiIndex
+{
- /**
- * The logger instance for this class
- */
- private static final Logger log = LoggerFactory.getLogger(MultiIndex.class);
+ /**
+ * The logger instance for this class
+ */
+ private static final Logger log = LoggerFactory.getLogger(MultiIndex.class);
- /**
- * Names of active persistent index directories.
- */
- private final IndexInfos indexNames = new IndexInfos("indexes");
+ /**
+ * Names of active persistent index directories.
+ */
+ private IndexInfos indexNames = new IndexInfos("indexes");
- /**
- * Names of index directories that can be deleted.
- */
- private final Set deletable = new HashSet();
+ /**
+ * Names of index directories that can be deleted.
+ */
+ private final Set deletable = new HashSet();
- /**
- * List of open persistent indexes. This list may also contain an open
- * PersistentIndex owned by the IndexMerger daemon. Such an index is not
- * registered with indexNames and <b>must not</b> be used in regular index
- * operations (delete node, etc.)!
- */
- private final List indexes = new ArrayList();
+ /**
+ * List of open persistent indexes. This list may also contain an open
+ * PersistentIndex owned by the IndexMerger daemon. Such an index is not
+ * registered with indexNames and <b>must not</b> be used in regular index
+ * operations (delete node, etc.)!
+ */
+ private final List indexes = new ArrayList();
- /**
- * The internal namespace mappings of the query manager.
- */
- private final NamespaceMappings nsMappings;
+ /**
+ * The internal namespace mappings of the query manager.
+ */
+ private final NamespaceMappings nsMappings;
- /**
- * The directory manager.
- */
- private final DirectoryManager directoryManager;
+ /**
+ * The directory manager.
+ */
+ private final DirectoryManager directoryManager;
- /**
- * The base directory to store the index.
- */
- private final Directory indexDir;
+ /**
+ * The base directory to store the index.
+ */
+ private final Directory indexDir;
- /**
- * The query handler
- */
- private final SearchIndex handler;
+ /**
+ * The query handler
+ */
+ private final SearchIndex handler;
- /**
- * The volatile index.
- */
- private VolatileIndex volatileIndex;
+ /**
+ * The volatile index.
+ */
+ private VolatileIndex volatileIndex;
- /**
- * Flag indicating whether an update operation is in progress.
- */
- private boolean updateInProgress = false;
+ /**
+ * Flag indicating whether an update operation is in progress.
+ */
+ private boolean updateInProgress = false;
- /**
- * If not <code>null</code> points to a valid <code>IndexReader</code> that
- * reads from all indexes, including volatile and persistent indexes.
- */
- private CachingMultiIndexReader multiReader;
+ /**
+ * If not <code>null</code> points to a valid <code>IndexReader</code> that
+ * reads from all indexes, including volatile and persistent indexes.
+ */
+ private CachingMultiIndexReader multiReader;
- /**
- * Shared document number cache across all persistent indexes.
- */
- private final DocNumberCache cache;
+ /**
+ * Shared document number cache across all persistent indexes.
+ */
+ private final DocNumberCache cache;
- /**
- * Monitor to use to synchronize access to {@link #multiReader} and
- * {@link #updateInProgress}.
- */
- private final Object updateMonitor = new Object();
+ /**
+ * Monitor to use to synchronize access to {@link #multiReader} and
+ * {@link #updateInProgress}.
+ */
+ private final Object updateMonitor = new Object();
- /**
- * <code>true</code> if the redo log contained entries on startup.
- */
- private boolean redoLogApplied = false;
+ /**
+ * <code>true</code> if the redo log contained entries on startup.
+ */
+ private boolean redoLogApplied = false;
- /**
- * The time this index was last flushed or a transaction was committed.
- */
- private long lastFlushTime;
+ /**
+ * The time this index was last flushed or a transaction was committed.
+ */
+ private long lastFlushTime;
- /**
- * The <code>IndexMerger</code> for this <code>MultiIndex</code>.
- */
- private final IndexMerger merger;
+ /**
+ * The <code>IndexMerger</code> for this <code>MultiIndex</code>.
+ */
+ private final IndexMerger merger;
- /**
- * Timer to schedule flushes of this index after some idle time.
- */
- private static final Timer FLUSH_TIMER = new Timer(true);
+ /**
+ * Timer to schedule flushes of this index after some idle time.
+ */
+ private static final Timer FLUSH_TIMER = new Timer(true);
- /**
- * Task that is periodically called by {@link #FLUSH_TIMER} and checks if
- * index should be flushed.
- */
- private final TimerTask flushTask;
+ /**
+ * Task that is periodically called by {@link #FLUSH_TIMER} and checks if
+ * index should be flushed.
+ */
+ private TimerTask flushTask;
- /**
- * The RedoLog of this <code>MultiIndex</code>.
- */
- private final RedoLog redoLog;
+ /**
+ * The RedoLog of this <code>MultiIndex</code>.
+ */
+ private RedoLog redoLog = null;
- /**
- * The indexing queue with pending text extraction jobs.
- */
- private IndexingQueue indexingQueue;
+ /**
+ * The indexing queue with pending text extraction jobs.
+ */
+ private IndexingQueue indexingQueue;
- /**
- * Set<NodeId> of uuids that should not be indexed.
- */
- private final IndexingTree indexingTree;
+ /**
+ * Set<NodeId> of uuids that should not be indexed.
+ */
+ private final IndexingTree indexingTree;
- /**
- * The next transaction id.
- */
- private long nextTransactionId = 0;
+ /**
+ * The next transaction id.
+ */
+ private long nextTransactionId = 0;
- /**
- * The current transaction id.
- */
- private long currentTransactionId = -1;
+ /**
+ * The current transaction id.
+ */
+ private long currentTransactionId = -1;
- /**
- * Flag indicating whether re-indexing is running.
- */
- private boolean reindexing = false;
+ /**
+ * Flag indicating whether re-indexing is running.
+ */
+ private boolean reindexing = false;
- /**
- * The index format version of this multi index.
- */
- private final IndexFormatVersion version;
+ /**
+ * The index format version of this multi index.
+ */
+ private final IndexFormatVersion version;
- /**
- * Creates a new MultiIndex.
- *
- * @param handler
- * the search handler
- * @param excludedIDs
- * Set<NodeId> that contains uuids that should not be indexed
- * nor further traversed.
- * @throws IOException
- * if an error occurs
- */
- MultiIndex(SearchIndex handler, IndexingTree indexingTree)
- throws IOException {
- this.directoryManager = handler.getDirectoryManager();
- this.indexDir = directoryManager.getDirectory(".");
- this.handler = handler;
- this.cache = new DocNumberCache(handler.getCacheSize());
- this.redoLog = new RedoLog(indexDir);
- this.indexingTree = indexingTree;
- this.nsMappings = handler.getNamespaceMappings();
+ /**
+ * Indexer io mode
+ */
+ private IndexerIoMode ioMode = IndexerIoMode.READ_ONLY;
- if (indexNames.exists(indexDir)) {
- indexNames.read(indexDir);
- }
+ /**
+ * Creates a new MultiIndex in READ ONLY MODE! setIndexerIoMode(READ_WRITE) later.
+ *
+ * @param handler
+ * the search handler
+ * @param excludedIDs
+ * Set<NodeId> that contains uuids that should not be indexed
+ * nor further traversed.
+ * @throws IOException
+ * if an error occurs
+ */
+ MultiIndex(SearchIndex handler, IndexingTree indexingTree, IndexerIoMode ioMode) throws IOException
+ {
+ this.ioMode = ioMode;
+ this.directoryManager = handler.getDirectoryManager();
+ this.indexDir = directoryManager.getDirectory(".");
+ this.handler = handler;
+ this.cache = new DocNumberCache(handler.getCacheSize());
+ this.indexingTree = indexingTree;
+ this.nsMappings = handler.getNamespaceMappings();
+ this.flushTask = null;
+ if (indexNames.exists(indexDir))
+ {
+ indexNames.read(indexDir);
+ }
- // as of 1.5 deletable file is not used anymore
- removeDeletable();
+ // as of 1.5 deletable file is not used anymore
+ removeDeletable();
- // initialize IndexMerger
- merger = new IndexMerger(this);
- merger.setMaxMergeDocs(handler.getMaxMergeDocs());
- merger.setMergeFactor(handler.getMergeFactor());
- merger.setMinMergeDocs(handler.getMinMergeDocs());
+ // initialize IndexMerger
+ merger = new IndexMerger(this);
+ merger.setMaxMergeDocs(handler.getMaxMergeDocs());
+ merger.setMergeFactor(handler.getMergeFactor());
+ merger.setMinMergeDocs(handler.getMinMergeDocs());
- IndexingQueueStore store = new IndexingQueueStore(indexDir);
+ IndexingQueueStore store = new IndexingQueueStore(indexDir);
- // initialize indexing queue
- this.indexingQueue = new IndexingQueue(store);
+ // initialize indexing queue
+ this.indexingQueue = new IndexingQueue(store);
- // open persistent indexes
- for (int i = 0; i < indexNames.size(); i++) {
- String name = indexNames.getName(i);
- // only open if it still exists
- // it is possible that indexNames still contains a name for
- // an index that has been deleted, but indexNames has not been
- // written to disk.
- if (!directoryManager.hasDirectory(name)) {
- log.debug("index does not exist anymore: " + name);
- // move on to next index
- continue;
- }
- PersistentIndex index = new PersistentIndex(name, handler
- .getTextAnalyzer(), handler.getSimilarity(), cache,
- indexingQueue, directoryManager);
- index.setMaxFieldLength(handler.getMaxFieldLength());
- index.setUseCompoundFile(handler.getUseCompoundFile());
- index.setTermInfosIndexDivisor(handler.getTermInfosIndexDivisor());
- indexes.add(index);
- merger.indexAdded(index.getName(), index.getNumDocuments());
- }
+ // open persistent indexes
+ for (int i = 0; i < indexNames.size(); i++)
+ {
+ String name = indexNames.getName(i);
+ // only open if it still exists
+ // it is possible that indexNames still contains a name for
+ // an index that has been deleted, but indexNames has not been
+ // written to disk.
+ if (!directoryManager.hasDirectory(name))
+ {
+ log.debug("index does not exist anymore: " + name);
+ // move on to next index
+ continue;
+ }
+ PersistentIndex index =
+ new PersistentIndex(name, handler.getTextAnalyzer(), handler.getSimilarity(), cache, indexingQueue,
+ directoryManager);
+ index.setMaxFieldLength(handler.getMaxFieldLength());
+ index.setUseCompoundFile(handler.getUseCompoundFile());
+ index.setTermInfosIndexDivisor(handler.getTermInfosIndexDivisor());
+ indexes.add(index);
+ merger.indexAdded(index.getName(), index.getNumDocuments());
+ }
- // init volatile index
- resetVolatileIndex();
+ // init volatile index
+ resetVolatileIndex();
- // set index format version and at the same time
- // initialize hierarchy cache if requested.
- CachingMultiIndexReader reader = getIndexReader(handler
- .isInitializeHierarchyCache());
- try {
- version = IndexFormatVersion.getVersion(reader);
- } finally {
- reader.release();
- }
+ // set index format version and at the same time
+ // initialize hierarchy cache if requested.
+ CachingMultiIndexReader reader = getIndexReader(handler.isInitializeHierarchyCache());
+ try
+ {
+ version = IndexFormatVersion.getVersion(reader);
+ }
+ finally
+ {
+ reader.release();
+ }
+ indexingQueue.initialize(this);
+ if (ioMode == IndexerIoMode.READ_WRITE)
+ {
+ setReadWrite();
+ }
+ }
- indexingQueue.initialize(this);
+ /**
+ * Returns the number of documents in this index.
+ *
+ * @return the number of documents in this index.
+ * @throws IOException
+ * if an error occurs while reading from the index.
+ */
+ int numDocs() throws IOException
+ {
+ if (indexNames.size() == 0)
+ {
+ return volatileIndex.getNumDocuments();
+ }
+ else
+ {
+ CachingMultiIndexReader reader = getIndexReader();
+ try
+ {
+ return reader.numDocs();
+ }
+ finally
+ {
+ reader.release();
+ }
+ }
+ }
- redoLogApplied = redoLog.hasEntries();
+ /**
+ * @return the index format version for this multi index.
+ */
+ IndexFormatVersion getIndexFormatVersion()
+ {
+ return version;
+ }
- // run recovery
- Recovery.run(this, redoLog);
+ /**
+ * Creates an initial index by traversing the node hierarchy starting at the
+ * node with <code>rootId</code>.
+ *
+ * @param stateMgr
+ * the item state manager.
+ * @param rootId
+ * the id of the node from where to start.
+ * @param rootPath
+ * the path of the node from where to start.
+ * @throws IOException
+ * if an error occurs while indexing the workspace.
+ * @throws IllegalStateException
+ * if this index is not empty.
+ */
+ void createInitialIndex(ItemDataConsumer stateMgr) throws IOException
+ {
+ // only do an initial index if there are no indexes at all
+ if (indexNames.size() == 0)
+ {
+ reindexing = true;
+ try
+ {
+ long count = 0;
+ // traverse and index workspace
+ executeAndLog(new Start(Action.INTERNAL_TRANSACTION));
+ // NodeData rootState = (NodeData) stateMgr.getItemData(rootId);
+ count = createIndex(indexingTree.getIndexingRoot(), stateMgr, count);
+ executeAndLog(new Commit(getTransactionId()));
+ log.info("Created initial index for {} nodes", new Long(count));
+ releaseMultiReader();
+ scheduleFlushTask();
+ }
+ catch (Exception e)
+ {
+ String msg = "Error indexing workspace";
+ IOException ex = new IOException(msg);
+ ex.initCause(e);
+ throw ex;
+ }
+ finally
+ {
+ reindexing = false;
+ }
+ }
+ else
+ {
+ throw new IllegalStateException("Index already present");
+ }
+ }
- // enqueue unused segments for deletion
- enqueueUnusedSegments();
- attemptDelete();
+ /**
+ * Atomically updates the index by removing some documents and adding
+ * others.
+ *
+ * @param remove
+ * collection of <code>UUID</code>s that identify documents to
+ * remove
+ * @param add
+ * collection of <code>Document</code>s to add. Some of the
+ * elements in this collection may be <code>null</code>, to
+ * indicate that a node could not be indexed successfully.
+ * @throws IOException
+ * if an error occurs while updating the index.
+ */
+ synchronized void update(Collection remove, Collection add) throws IOException
+ {
+ // make sure a reader is available during long updates
+ if (add.size() > handler.getBufferSize())
+ {
+ try
+ {
+ getIndexReader().release();
+ }
+ catch (IOException e)
+ {
+ // do not fail if an exception is thrown here
+ log.warn("unable to prepare index reader " + "for queries during update", e);
+ }
+ }
- // now that we are ready, start index merger
- merger.start();
+ synchronized (updateMonitor)
+ {
+ updateInProgress = true;
+ }
+ try
+ {
+ long transactionId = nextTransactionId++;
+ executeAndLog(new Start(transactionId));
- if (redoLogApplied) {
- // wait for the index merge to finish pending jobs
- try {
- merger.waitUntilIdle();
- } catch (InterruptedException e) {
- // move on
- }
- flush();
- }
+ boolean flush = false;
+ for (Iterator it = remove.iterator(); it.hasNext();)
+ {
+ executeAndLog(new DeleteNode(transactionId, (String)it.next()));
+ }
+ for (Iterator it = add.iterator(); it.hasNext();)
+ {
+ Document doc = (Document)it.next();
+ if (doc != null)
+ {
+ executeAndLog(new AddNode(transactionId, doc));
+ // commit volatile index if needed
+ flush |= checkVolatileCommit();
+ }
+ }
+ executeAndLog(new Commit(transactionId));
- flushTask = new TimerTask() {
- public void run() {
- // check if there are any indexing jobs finished
- checkIndexingQueue();
- // check if volatile index should be flushed
- checkFlush();
- }
- };
+ // flush whole index when volatile index has been commited.
+ if (flush)
+ {
+ flush();
+ }
+ }
+ finally
+ {
+ synchronized (updateMonitor)
+ {
+ updateInProgress = false;
+ updateMonitor.notifyAll();
+ releaseMultiReader();
+ }
+ }
+ }
- if (indexNames.size() > 0) {
- scheduleFlushTask();
- }
- }
+ /**
+ * Adds a document to the index.
+ *
+ * @param doc
+ * the document to add.
+ * @throws IOException
+ * if an error occurs while adding the document to the index.
+ */
+ void addDocument(Document doc) throws IOException
+ {
+ update(Collections.EMPTY_LIST, Arrays.asList(new Document[]{doc}));
+ }
- /**
- * Returns the number of documents in this index.
- *
- * @return the number of documents in this index.
- * @throws IOException
- * if an error occurs while reading from the index.
- */
- int numDocs() throws IOException {
- if (indexNames.size() == 0) {
- return volatileIndex.getNumDocuments();
- } else {
- CachingMultiIndexReader reader = getIndexReader();
- try {
- return reader.numDocs();
- } finally {
- reader.release();
- }
- }
- }
+ /**
+ * Deletes the first document that matches the <code>uuid</code>.
+ *
+ * @param uuid
+ * document that match this <code>uuid</code> will be deleted.
+ * @throws IOException
+ * if an error occurs while deleting the document.
+ */
+ void removeDocument(String uuid) throws IOException
+ {
+ update(Arrays.asList(new String[]{uuid}), Collections.EMPTY_LIST);
+ }
- /**
- * @return the index format version for this multi index.
- */
- IndexFormatVersion getIndexFormatVersion() {
- return version;
- }
+ /**
+ * Deletes all documents that match the <code>uuid</code>.
+ *
+ * @param uuid
+ * documents that match this <code>uuid</code> will be deleted.
+ * @return the number of deleted documents.
+ * @throws IOException
+ * if an error occurs while deleting documents.
+ */
+ synchronized int removeAllDocuments(String uuid) throws IOException
+ {
+ synchronized (updateMonitor)
+ {
+ updateInProgress = true;
+ }
+ int num;
+ try
+ {
+ Term idTerm = new Term(FieldNames.UUID, uuid.toString());
+ executeAndLog(new Start(Action.INTERNAL_TRANSACTION));
+ num = volatileIndex.removeDocument(idTerm);
+ if (num > 0)
+ {
+ redoLog.append(new DeleteNode(getTransactionId(), uuid));
+ }
+ for (int i = 0; i < indexes.size(); i++)
+ {
+ PersistentIndex index = (PersistentIndex)indexes.get(i);
+ // only remove documents from registered indexes
+ if (indexNames.contains(index.getName()))
+ {
+ int removed = index.removeDocument(idTerm);
+ if (removed > 0)
+ {
+ redoLog.append(new DeleteNode(getTransactionId(), uuid));
+ }
+ num += removed;
+ }
+ }
+ executeAndLog(new Commit(getTransactionId()));
+ }
+ finally
+ {
+ synchronized (updateMonitor)
+ {
+ updateInProgress = false;
+ updateMonitor.notifyAll();
+ releaseMultiReader();
+ }
+ }
+ return num;
+ }
- /**
- * Creates an initial index by traversing the node hierarchy starting at the
- * node with <code>rootId</code>.
- *
- * @param stateMgr
- * the item state manager.
- * @param rootId
- * the id of the node from where to start.
- * @param rootPath
- * the path of the node from where to start.
- * @throws IOException
- * if an error occurs while indexing the workspace.
- * @throws IllegalStateException
- * if this index is not empty.
- */
- void createInitialIndex(ItemDataConsumer stateMgr) throws IOException {
- // only do an initial index if there are no indexes at all
- if (indexNames.size() == 0) {
- reindexing = true;
- try {
- long count = 0;
- // traverse and index workspace
- executeAndLog(new Start(Action.INTERNAL_TRANSACTION));
- // NodeData rootState = (NodeData) stateMgr.getItemData(rootId);
- count = createIndex(indexingTree.getIndexingRoot(), stateMgr,
- count);
- executeAndLog(new Commit(getTransactionId()));
- log.info("Created initial index for {} nodes", new Long(count));
- releaseMultiReader();
- scheduleFlushTask();
- } catch (Exception e) {
- String msg = "Error indexing workspace";
- IOException ex = new IOException(msg);
- ex.initCause(e);
- throw ex;
- } finally {
- reindexing = false;
- }
- } else {
- throw new IllegalStateException("Index already present");
- }
- }
+ /**
+ * Returns <code>IndexReader</code>s for the indexes named
+ * <code>indexNames</code>. An <code>IndexListener</code> is registered and
+ * notified when documents are deleted from one of the indexes in
+ * <code>indexNames</code>.
+ * <p/>
+ * Note: the number of <code>IndexReaders</code> returned by this method is
+ * not necessarily the same as the number of index names passed. An index
+ * might have been deleted and is not reachable anymore.
+ *
+ * @param indexNames
+ * the names of the indexes for which to obtain readers.
+ * @param listener
+ * the listener to notify when documents are deleted.
+ * @return the <code>IndexReaders</code>.
+ * @throws IOException
+ * if an error occurs acquiring the index readers.
+ */
+ synchronized IndexReader[] getIndexReaders(String[] indexNames, IndexListener listener) throws IOException
+ {
+ Set names = new HashSet(Arrays.asList(indexNames));
+ Map indexReaders = new HashMap();
- /**
- * Atomically updates the index by removing some documents and adding
- * others.
- *
- * @param remove
- * collection of <code>UUID</code>s that identify documents to
- * remove
- * @param add
- * collection of <code>Document</code>s to add. Some of the
- * elements in this collection may be <code>null</code>, to
- * indicate that a node could not be indexed successfully.
- * @throws IOException
- * if an error occurs while updating the index.
- */
- synchronized void update(Collection remove, Collection add)
- throws IOException {
- // make sure a reader is available during long updates
- if (add.size() > handler.getBufferSize()) {
- try {
- getIndexReader().release();
- } catch (IOException e) {
- // do not fail if an exception is thrown here
- log.warn("unable to prepare index reader "
- + "for queries during update", e);
- }
- }
+ try
+ {
+ for (Iterator it = indexes.iterator(); it.hasNext();)
+ {
+ PersistentIndex index = (PersistentIndex)it.next();
+ if (names.contains(index.getName()))
+ {
+ indexReaders.put(index.getReadOnlyIndexReader(listener), index);
+ }
+ }
+ }
+ catch (IOException e)
+ {
+ // release readers obtained so far
+ for (Iterator it = indexReaders.entrySet().iterator(); it.hasNext();)
+ {
+ Map.Entry entry = (Map.Entry)it.next();
+ ReadOnlyIndexReader reader = (ReadOnlyIndexReader)entry.getKey();
+ try
+ {
+ reader.release();
+ }
+ catch (IOException ex)
+ {
+ log.warn("Exception releasing index reader: " + ex);
+ }
+ ((PersistentIndex)entry.getValue()).resetListener();
+ }
+ throw e;
+ }
- synchronized (updateMonitor) {
- updateInProgress = true;
- }
- try {
- long transactionId = nextTransactionId++;
- executeAndLog(new Start(transactionId));
+ return (IndexReader[])indexReaders.keySet().toArray(new IndexReader[indexReaders.size()]);
+ }
- boolean flush = false;
- for (Iterator it = remove.iterator(); it.hasNext();) {
- executeAndLog(new DeleteNode(transactionId, (String) it.next()));
- }
- for (Iterator it = add.iterator(); it.hasNext();) {
- Document doc = (Document) it.next();
- if (doc != null) {
- executeAndLog(new AddNode(transactionId, doc));
- // commit volatile index if needed
- flush |= checkVolatileCommit();
- }
- }
- executeAndLog(new Commit(transactionId));
+ /**
+ * Creates a new Persistent index. The new index is not registered with this
+ * <code>MultiIndex</code>.
+ *
+ * @param indexName
+ * the name of the index to open, or <code>null</code> if an
+ * index with a new name should be created.
+ * @return a new <code>PersistentIndex</code>.
+ * @throws IOException
+ * if a new index cannot be created.
+ */
+ synchronized PersistentIndex getOrCreateIndex(String indexName) throws IOException
+ {
+ // check existing
+ for (Iterator it = indexes.iterator(); it.hasNext();)
+ {
+ PersistentIndex idx = (PersistentIndex)it.next();
+ if (idx.getName().equals(indexName))
+ {
+ return idx;
+ }
+ }
- // flush whole index when volatile index has been commited.
- if (flush) {
- flush();
- }
- } finally {
- synchronized (updateMonitor) {
- updateInProgress = false;
- updateMonitor.notifyAll();
- releaseMultiReader();
- }
- }
- }
+ if (ioMode == IndexerIoMode.READ_ONLY)
+ {
+ throw new UnsupportedOperationException("Can't create index in READ_ONLY mode.");
+ }
- /**
- * Adds a document to the index.
- *
- * @param doc
- * the document to add.
- * @throws IOException
- * if an error occurs while adding the document to the index.
- */
- void addDocument(Document doc) throws IOException {
- update(Collections.EMPTY_LIST, Arrays.asList(new Document[] { doc }));
- }
+ // otherwise open / create it
+ if (indexName == null)
+ {
+ do
+ {
+ indexName = indexNames.newName();
+ }
+ while (directoryManager.hasDirectory(indexName));
+ }
+ PersistentIndex index;
+ try
+ {
+ index =
+ new PersistentIndex(indexName, handler.getTextAnalyzer(), handler.getSimilarity(), cache, indexingQueue,
+ directoryManager);
+ }
+ catch (IOException e)
+ {
+ // do some clean up
+ if (!directoryManager.delete(indexName))
+ {
+ deletable.add(indexName);
+ }
+ throw e;
+ }
+ index.setMaxFieldLength(handler.getMaxFieldLength());
+ index.setUseCompoundFile(handler.getUseCompoundFile());
+ index.setTermInfosIndexDivisor(handler.getTermInfosIndexDivisor());
- /**
- * Deletes the first document that matches the <code>uuid</code>.
- *
- * @param uuid
- * document that match this <code>uuid</code> will be deleted.
- * @throws IOException
- * if an error occurs while deleting the document.
- */
- void removeDocument(String uuid) throws IOException {
- update(Arrays.asList(new String[] { uuid }), Collections.EMPTY_LIST);
- }
+ // add to list of open indexes and return it
+ indexes.add(index);
+ return index;
+ }
- /**
- * Deletes all documents that match the <code>uuid</code>.
- *
- * @param uuid
- * documents that match this <code>uuid</code> will be deleted.
- * @return the number of deleted documents.
- * @throws IOException
- * if an error occurs while deleting documents.
- */
- synchronized int removeAllDocuments(String uuid) throws IOException {
- synchronized (updateMonitor) {
- updateInProgress = true;
- }
- int num;
- try {
- Term idTerm = new Term(FieldNames.UUID, uuid.toString());
- executeAndLog(new Start(Action.INTERNAL_TRANSACTION));
- num = volatileIndex.removeDocument(idTerm);
- if (num > 0) {
- redoLog.append(new DeleteNode(getTransactionId(), uuid));
- }
- for (int i = 0; i < indexes.size(); i++) {
- PersistentIndex index = (PersistentIndex) indexes.get(i);
- // only remove documents from registered indexes
- if (indexNames.contains(index.getName())) {
- int removed = index.removeDocument(idTerm);
- if (removed > 0) {
- redoLog
- .append(new DeleteNode(getTransactionId(), uuid));
- }
- num += removed;
- }
- }
- executeAndLog(new Commit(getTransactionId()));
- } finally {
- synchronized (updateMonitor) {
- updateInProgress = false;
- updateMonitor.notifyAll();
- releaseMultiReader();
- }
- }
- return num;
- }
+ /**
+ * Returns <code>true</code> if this multi index has an index segment with
+ * the given name. This method even returns <code>true</code> if an index
+ * segments has not yet been loaded / initialized but exists on disk.
+ *
+ * @param indexName
+ * the name of the index segment.
+ * @return <code>true</code> if it exists; otherwise <code>false</code>.
+ * @throws IOException
+ * if an error occurs while checking existence of directory.
+ */
+ synchronized boolean hasIndex(String indexName) throws IOException
+ {
+ // check existing
+ for (Iterator it = indexes.iterator(); it.hasNext();)
+ {
+ PersistentIndex idx = (PersistentIndex)it.next();
+ if (idx.getName().equals(indexName))
+ {
+ return true;
+ }
+ }
+ // check if it exists on disk
+ return directoryManager.hasDirectory(indexName);
+ }
- /**
- * Returns <code>IndexReader</code>s for the indexes named
- * <code>indexNames</code>. An <code>IndexListener</code> is registered and
- * notified when documents are deleted from one of the indexes in
- * <code>indexNames</code>.
- * <p/>
- * Note: the number of <code>IndexReaders</code> returned by this method is
- * not necessarily the same as the number of index names passed. An index
- * might have been deleted and is not reachable anymore.
- *
- * @param indexNames
- * the names of the indexes for which to obtain readers.
- * @param listener
- * the listener to notify when documents are deleted.
- * @return the <code>IndexReaders</code>.
- * @throws IOException
- * if an error occurs acquiring the index readers.
- */
- synchronized IndexReader[] getIndexReaders(String[] indexNames,
- IndexListener listener) throws IOException {
- Set names = new HashSet(Arrays.asList(indexNames));
- Map indexReaders = new HashMap();
+ /**
+ * Replaces the indexes with names <code>obsoleteIndexes</code> with
+ * <code>index</code>. Documents that must be deleted in <code>index</code>
+ * can be identified with <code>Term</code>s in <code>deleted</code>.
+ *
+ * @param obsoleteIndexes
+ * the names of the indexes to replace.
+ * @param index
+ * the new index that is the result of a merge of the indexes to
+ * replace.
+ * @param deleted
+ * <code>Term</code>s that identify documents that must be
+ * deleted in <code>index</code>.
+ * @throws IOException
+ * if an exception occurs while replacing the indexes.
+ */
+ void replaceIndexes(String[] obsoleteIndexes, PersistentIndex index, Collection deleted) throws IOException
+ {
- try {
- for (Iterator it = indexes.iterator(); it.hasNext();) {
- PersistentIndex index = (PersistentIndex) it.next();
- if (names.contains(index.getName())) {
- indexReaders.put(index.getReadOnlyIndexReader(listener),
- index);
- }
- }
- } catch (IOException e) {
- // release readers obtained so far
- for (Iterator it = indexReaders.entrySet().iterator(); it.hasNext();) {
- Map.Entry entry = (Map.Entry) it.next();
- ReadOnlyIndexReader reader = (ReadOnlyIndexReader) entry
- .getKey();
- try {
- reader.release();
- } catch (IOException ex) {
- log.warn("Exception releasing index reader: " + ex);
- }
- ((PersistentIndex) entry.getValue()).resetListener();
- }
- throw e;
- }
+ if (handler.isInitializeHierarchyCache())
+ {
+ // force initializing of caches
+ long time = System.currentTimeMillis();
+ index.getReadOnlyIndexReader(true).release();
+ time = System.currentTimeMillis() - time;
+ log.debug("hierarchy cache initialized in {} ms", new Long(time));
+ }
- return (IndexReader[]) indexReaders.keySet().toArray(
- new IndexReader[indexReaders.size()]);
- }
+ synchronized (this)
+ {
+ synchronized (updateMonitor)
+ {
+ updateInProgress = true;
+ }
+ try
+ {
+ // if we are reindexing there is already an active transaction
+ if (!reindexing)
+ {
+ executeAndLog(new Start(Action.INTERNAL_TRANS_REPL_INDEXES));
+ }
+ // delete obsolete indexes
+ Set names = new HashSet(Arrays.asList(obsoleteIndexes));
+ for (Iterator it = names.iterator(); it.hasNext();)
+ {
+ // do not try to delete indexes that are already gone
+ String indexName = (String)it.next();
+ if (indexNames.contains(indexName))
+ {
+ executeAndLog(new DeleteIndex(getTransactionId(), indexName));
+ }
+ }
- /**
- * Creates a new Persistent index. The new index is not registered with this
- * <code>MultiIndex</code>.
- *
- * @param indexName
- * the name of the index to open, or <code>null</code> if an
- * index with a new name should be created.
- * @return a new <code>PersistentIndex</code>.
- * @throws IOException
- * if a new index cannot be created.
- */
- synchronized PersistentIndex getOrCreateIndex(String indexName)
- throws IOException {
- // check existing
- for (Iterator it = indexes.iterator(); it.hasNext();) {
- PersistentIndex idx = (PersistentIndex) it.next();
- if (idx.getName().equals(indexName)) {
- return idx;
- }
- }
+ // Index merger does not log an action when it creates the
+ // target
+ // index of the merge. We have to do this here.
+ executeAndLog(new CreateIndex(getTransactionId(), index.getName()));
- // otherwise open / create it
- if (indexName == null) {
- do {
- indexName = indexNames.newName();
- } while (directoryManager.hasDirectory(indexName));
- }
- PersistentIndex index;
- try {
- index = new PersistentIndex(indexName, handler.getTextAnalyzer(),
- handler.getSimilarity(), cache, indexingQueue,
- directoryManager);
- } catch (IOException e) {
- // do some clean up
- if (!directoryManager.delete(indexName)) {
- deletable.add(indexName);
- }
- throw e;
- }
- index.setMaxFieldLength(handler.getMaxFieldLength());
- index.setUseCompoundFile(handler.getUseCompoundFile());
- index.setTermInfosIndexDivisor(handler.getTermInfosIndexDivisor());
+ executeAndLog(new AddIndex(getTransactionId(), index.getName()));
- // add to list of open indexes and return it
- indexes.add(index);
- return index;
- }
+ // delete documents in index
+ for (Iterator it = deleted.iterator(); it.hasNext();)
+ {
+ Term id = (Term)it.next();
+ index.removeDocument(id);
+ }
+ index.commit();
- /**
- * Returns <code>true</code> if this multi index has an index segment with
- * the given name. This method even returns <code>true</code> if an index
- * segments has not yet been loaded / initialized but exists on disk.
- *
- * @param indexName
- * the name of the index segment.
- * @return <code>true</code> if it exists; otherwise <code>false</code>.
- * @throws IOException
- * if an error occurs while checking existence of directory.
- */
- synchronized boolean hasIndex(String indexName) throws IOException {
- // check existing
- for (Iterator it = indexes.iterator(); it.hasNext();) {
- PersistentIndex idx = (PersistentIndex) it.next();
- if (idx.getName().equals(indexName)) {
- return true;
- }
- }
- // check if it exists on disk
- return directoryManager.hasDirectory(indexName);
- }
+ if (!reindexing)
+ {
+ // only commit if we are not reindexing
+ // when reindexing the final commit is done at the very end
+ executeAndLog(new Commit(getTransactionId()));
+ }
+ }
+ finally
+ {
+ synchronized (updateMonitor)
+ {
+ updateInProgress = false;
+ updateMonitor.notifyAll();
+ releaseMultiReader();
+ }
+ }
+ }
+ if (reindexing)
+ {
+ // do some cleanup right away when reindexing
+ attemptDelete();
+ }
+ }
- /**
- * Replaces the indexes with names <code>obsoleteIndexes</code> with
- * <code>index</code>. Documents that must be deleted in <code>index</code>
- * can be identified with <code>Term</code>s in <code>deleted</code>.
- *
- * @param obsoleteIndexes
- * the names of the indexes to replace.
- * @param index
- * the new index that is the result of a merge of the indexes to
- * replace.
- * @param deleted
- * <code>Term</code>s that identify documents that must be
- * deleted in <code>index</code>.
- * @throws IOException
- * if an exception occurs while replacing the indexes.
- */
- void replaceIndexes(String[] obsoleteIndexes, PersistentIndex index,
- Collection deleted) throws IOException {
+ /**
+ * Returns an read-only <code>IndexReader</code> that spans alls indexes of
+ * this <code>MultiIndex</code>.
+ *
+ * @return an <code>IndexReader</code>.
+ * @throws IOException
+ * if an error occurs constructing the <code>IndexReader</code>.
+ */
+ public CachingMultiIndexReader getIndexReader() throws IOException
+ {
+ return getIndexReader(false);
+ }
- if (handler.isInitializeHierarchyCache()) {
- // force initializing of caches
- long time = System.currentTimeMillis();
- index.getReadOnlyIndexReader(true).release();
- time = System.currentTimeMillis() - time;
- log.debug("hierarchy cache initialized in {} ms", new Long(time));
- }
+ /**
+ * Returns an read-only <code>IndexReader</code> that spans alls indexes of
+ * this <code>MultiIndex</code>.
+ *
+ * @param initCache
+ * when set <code>true</code> the hierarchy cache is completely
+ * initialized before this call returns.
+ * @return an <code>IndexReader</code>.
+ * @throws IOException
+ * if an error occurs constructing the <code>IndexReader</code>.
+ */
+ public synchronized CachingMultiIndexReader getIndexReader(boolean initCache) throws IOException
+ {
+ synchronized (updateMonitor)
+ {
- synchronized (this) {
- synchronized (updateMonitor) {
- updateInProgress = true;
- }
- try {
- // if we are reindexing there is already an active transaction
- if (!reindexing) {
- executeAndLog(new Start(Action.INTERNAL_TRANS_REPL_INDEXES));
- }
- // delete obsolete indexes
- Set names = new HashSet(Arrays.asList(obsoleteIndexes));
- for (Iterator it = names.iterator(); it.hasNext();) {
- // do not try to delete indexes that are already gone
- String indexName = (String) it.next();
- if (indexNames.contains(indexName)) {
- executeAndLog(new DeleteIndex(getTransactionId(),
- indexName));
- }
- }
+ // TODO: re-implement in less aggressive way
+ if (ioMode == IndexerIoMode.READ_ONLY)
+ {
+ // this is temporary and extensive solution to re-read list of indexes.
+ refreshIndexesList();
+ }
+ if (multiReader != null)
+ {
+ multiReader.acquire();
+ return multiReader;
+ }
+ // no reader available
+ // wait until no update is in progress
+ while (updateInProgress)
+ {
+ try
+ {
+ updateMonitor.wait();
+ }
+ catch (InterruptedException e)
+ {
+ throw new IOException("Interrupted while waiting to aquire reader");
+ }
+ }
+ // some other read thread might have created the reader in the
+ // meantime -> check again
+ if (multiReader == null)
+ {
+ List readerList = new ArrayList();
+ for (int i = 0; i < indexes.size(); i++)
+ {
+ PersistentIndex pIdx = (PersistentIndex)indexes.get(i);
+
+ if (indexNames.contains(pIdx.getName()))
+ {
+ try
+ {
+ readerList.add(pIdx.getReadOnlyIndexReader(initCache));
+ }
+ catch (FileNotFoundException e)
+ {
+ if(directoryManager.hasDirectory(pIdx.getName())){
+ throw e;
+ }
+ }
+ }
+ }
+ readerList.add(volatileIndex.getReadOnlyIndexReader());
+ ReadOnlyIndexReader[] readers =
+ (ReadOnlyIndexReader[])readerList.toArray(new ReadOnlyIndexReader[readerList.size()]);
+ multiReader = new CachingMultiIndexReader(readers, cache);
+ }
+ multiReader.acquire();
+ return multiReader;
+ }
+ }
- // Index merger does not log an action when it creates the
- // target
- // index of the merge. We have to do this here.
- executeAndLog(new CreateIndex(getTransactionId(), index
- .getName()));
+ /**
+ * Returns the volatile index.
+ *
+ * @return the volatile index.
+ */
+ VolatileIndex getVolatileIndex()
+ {
+ return volatileIndex;
+ }
- executeAndLog(new AddIndex(getTransactionId(), index.getName()));
+ /**
+ * Closes this <code>MultiIndex</code>.
+ */
+ void close()
+ {
- // delete documents in index
- for (Iterator it = deleted.iterator(); it.hasNext();) {
- Term id = (Term) it.next();
- index.removeDocument(id);
- }
- index.commit();
+ // stop index merger
+ // when calling this method we must not lock this MultiIndex, otherwise
+ // a deadlock might occur
+ merger.dispose();
- if (!reindexing) {
- // only commit if we are not reindexing
- // when reindexing the final commit is done at the very end
- executeAndLog(new Commit(getTransactionId()));
- }
- } finally {
- synchronized (updateMonitor) {
- updateInProgress = false;
- updateMonitor.notifyAll();
- releaseMultiReader();
- }
- }
- }
- if (reindexing) {
- // do some cleanup right away when reindexing
- attemptDelete();
- }
- }
+ synchronized (this)
+ {
+ // stop timer
+ if (flushTask != null)
+ {
+ flushTask.cancel();
+ }
- /**
- * Returns an read-only <code>IndexReader</code> that spans alls indexes of
- * this <code>MultiIndex</code>.
- *
- * @return an <code>IndexReader</code>.
- * @throws IOException
- * if an error occurs constructing the <code>IndexReader</code>.
- */
- public CachingMultiIndexReader getIndexReader() throws IOException {
- return getIndexReader(false);
- }
+ // commit / close indexes
+ try
+ {
+ releaseMultiReader();
+ }
+ catch (IOException e)
+ {
+ log.error("Exception while closing search index.", e);
+ }
+ try
+ {
+ flush();
+ }
+ catch (IOException e)
+ {
+ log.error("Exception while closing search index.", e);
+ }
+ volatileIndex.close();
+ for (int i = 0; i < indexes.size(); i++)
+ {
+ ((PersistentIndex)indexes.get(i)).close();
+ }
- /**
- * Returns an read-only <code>IndexReader</code> that spans alls indexes of
- * this <code>MultiIndex</code>.
- *
- * @param initCache
- * when set <code>true</code> the hierarchy cache is completely
- * initialized before this call returns.
- * @return an <code>IndexReader</code>.
- * @throws IOException
- * if an error occurs constructing the <code>IndexReader</code>.
- */
- public synchronized CachingMultiIndexReader getIndexReader(boolean initCache)
- throws IOException {
- synchronized (updateMonitor) {
- if (multiReader != null) {
- multiReader.acquire();
- return multiReader;
- }
- // no reader available
- // wait until no update is in progress
- while (updateInProgress) {
- try {
- updateMonitor.wait();
- } catch (InterruptedException e) {
- throw new IOException(
- "Interrupted while waiting to aquire reader");
- }
- }
- // some other read thread might have created the reader in the
- // meantime -> check again
- if (multiReader == null) {
- List readerList = new ArrayList();
- for (int i = 0; i < indexes.size(); i++) {
- PersistentIndex pIdx = (PersistentIndex) indexes.get(i);
- if (indexNames.contains(pIdx.getName())) {
- readerList.add(pIdx.getReadOnlyIndexReader(initCache));
- }
- }
- readerList.add(volatileIndex.getReadOnlyIndexReader());
- ReadOnlyIndexReader[] readers = (ReadOnlyIndexReader[]) readerList
- .toArray(new ReadOnlyIndexReader[readerList.size()]);
- multiReader = new CachingMultiIndexReader(readers, cache);
- }
- multiReader.acquire();
- return multiReader;
- }
- }
+ // close indexing queue
+ indexingQueue.close();
- /**
- * Returns the volatile index.
- *
- * @return the volatile index.
- */
- VolatileIndex getVolatileIndex() {
- return volatileIndex;
- }
+ // finally close directory
+ try
+ {
+ indexDir.close();
+ }
+ catch (IOException e)
+ {
+ log.error("Exception while closing directory.", e);
+ }
+ }
+ }
- /**
- * Closes this <code>MultiIndex</code>.
- */
- void close() {
+ /**
+ * Returns the namespace mappings of this search index.
+ *
+ * @return the namespace mappings of this search index.
+ */
+ NamespaceMappings getNamespaceMappings()
+ {
+ return nsMappings;
+ }
- // stop index merger
- // when calling this method we must not lock this MultiIndex, otherwise
- // a deadlock might occur
- merger.dispose();
+ /**
+ * Returns the indexing queue for this multi index.
+ *
+ * @return the indexing queue for this multi index.
+ */
+ public IndexingQueue getIndexingQueue()
+ {
+ return indexingQueue;
+ }
- synchronized (this) {
- // stop timer
- flushTask.cancel();
+ /**
+ * Returns a lucene Document for the <code>node</code>.
+ *
+ * @param node
+ * the node to index.
+ * @return the index document.
+ * @throws RepositoryException
+ * if an error occurs while reading from the workspace.
+ */
+ Document createDocument(NodeData node) throws RepositoryException
+ {
+ return handler.createDocument(node, nsMappings, version);
+ }
- // commit / close indexes
- try {
- releaseMultiReader();
- } catch (IOException e) {
- log.error("Exception while closing search index.", e);
- }
- try {
- flush();
- } catch (IOException e) {
- log.error("Exception while closing search index.", e);
- }
- volatileIndex.close();
- for (int i = 0; i < indexes.size(); i++) {
- ((PersistentIndex) indexes.get(i)).close();
- }
+ /**
+ * Returns a lucene Document for the Node with <code>id</code>.
+ *
+ * @param id
+ * the id of the node to index.
+ * @return the index document.
+ * @throws RepositoryException
+ * if an error occurs while reading from the workspace or if
+ * there is no node with <code>id</code>.
+ */
+ Document createDocument(String id) throws RepositoryException
+ {
+ ItemData data = handler.getContext().getItemStateManager().getItemData(id);
+ if (data == null)
+ throw new ItemNotFoundException("Item id=" + id + " not found");
+ if (!data.isNode())
+ throw new RepositoryException("Item with id " + id + " is not a node");
+ return createDocument((NodeData)data);
- // close indexing queue
- indexingQueue.close();
+ }
- // finally close directory
- try {
- indexDir.close();
- } catch (IOException e) {
- log.error("Exception while closing directory.", e);
- }
- }
- }
+ /**
+ * Returns <code>true</code> if the redo log contained entries while this
+ * index was instantiated; <code>false</code> otherwise.
+ *
+ * @return <code>true</code> if the redo log contained entries.
+ */
+ boolean getRedoLogApplied()
+ {
+ return redoLogApplied;
+ }
- /**
- * Returns the namespace mappings of this search index.
- *
- * @return the namespace mappings of this search index.
- */
- NamespaceMappings getNamespaceMappings() {
- return nsMappings;
- }
+ /**
+ * Removes the <code>index</code> from the list of active sub indexes. The
+ * Index is not acutally deleted right away, but postponed to the
+ * transaction commit.
+ * <p/>
+ * This method does not close the index, but rather expects that the index
+ * has already been closed.
+ *
+ * @param index
+ * the index to delete.
+ */
+ synchronized void deleteIndex(PersistentIndex index)
+ {
+ // remove it from the lists if index is registered
+ indexes.remove(index);
+ indexNames.removeName(index.getName());
+ synchronized (deletable)
+ {
+ log.debug("Moved " + index.getName() + " to deletable");
+ deletable.add(index.getName());
+ }
+ }
- /**
- * Returns the indexing queue for this multi index.
- *
- * @return the indexing queue for this multi index.
- */
- public IndexingQueue getIndexingQueue() {
- return indexingQueue;
- }
+ /**
+ * Flushes this <code>MultiIndex</code>. Persists all pending changes and
+ * resets the redo log.
+ *
+ * @throws IOException
+ * if the flush fails.
+ */
+ public void flush() throws IOException
+ {
+ synchronized (this)
+ {
+ // commit volatile index
+ executeAndLog(new Start(Action.INTERNAL_TRANSACTION));
+ commitVolatileIndex();
- /**
- * Returns a lucene Document for the <code>node</code>.
- *
- * @param node
- * the node to index.
- * @return the index document.
- * @throws RepositoryException
- * if an error occurs while reading from the workspace.
- */
- Document createDocument(NodeData node) throws RepositoryException {
- return handler.createDocument(node, nsMappings, version);
- }
+ // commit persistent indexes
+ for (int i = indexes.size() - 1; i >= 0; i--)
+ {
+ PersistentIndex index = (PersistentIndex)indexes.get(i);
+ // only commit indexes we own
+ // index merger also places PersistentIndex instances in
+ // indexes,
+ // but does not make them public by registering the name in
+ // indexNames
+ if (indexNames.contains(index.getName()))
+ {
+ index.commit();
+ // check if index still contains documents
+ if (index.getNumDocuments() == 0)
+ {
+ executeAndLog(new DeleteIndex(getTransactionId(), index.getName()));
+ }
+ }
+ }
+ executeAndLog(new Commit(getTransactionId()));
- /**
- * Returns a lucene Document for the Node with <code>id</code>.
- *
- * @param id
- * the id of the node to index.
- * @return the index document.
- * @throws RepositoryException
- * if an error occurs while reading from the workspace or if
- * there is no node with <code>id</code>.
- */
- Document createDocument(String id) throws RepositoryException {
- ItemData data = handler.getContext().getItemStateManager().getItemData(
- id);
- if (data == null)
- throw new ItemNotFoundException("Item id=" + id + " not found");
- if (!data.isNode())
- throw new RepositoryException("Item with id " + id
- + " is not a node");
- return createDocument((NodeData) data);
+ indexNames.write(indexDir);
- }
+ // reset redo log
+ redoLog.clear();
- /**
- * Returns <code>true</code> if the redo log contained entries while this
- * index was instantiated; <code>false</code> otherwise.
- *
- * @return <code>true</code> if the redo log contained entries.
- */
- boolean getRedoLogApplied() {
- return redoLogApplied;
- }
+ lastFlushTime = System.currentTimeMillis();
+ }
- /**
- * Removes the <code>index</code> from the list of active sub indexes. The
- * Index is not acutally deleted right away, but postponed to the
- * transaction commit.
- * <p/>
- * This method does not close the index, but rather expects that the index
- * has already been closed.
- *
- * @param index
- * the index to delete.
- */
- synchronized void deleteIndex(PersistentIndex index) {
- // remove it from the lists if index is registered
- indexes.remove(index);
- indexNames.removeName(index.getName());
- synchronized (deletable) {
- log.debug("Moved " + index.getName() + " to deletable");
- deletable.add(index.getName());
- }
- }
+ // delete obsolete indexes
+ attemptDelete();
+ }
- /**
- * Flushes this <code>MultiIndex</code>. Persists all pending changes and
- * resets the redo log.
- *
- * @throws IOException
- * if the flush fails.
- */
- public void flush() throws IOException {
- synchronized (this) {
- // commit volatile index
- executeAndLog(new Start(Action.INTERNAL_TRANSACTION));
- commitVolatileIndex();
+ /**
+ * Releases the {@link #multiReader} and sets it <code>null</code>. If the
+ * reader is already <code>null</code> this method does nothing. When this
+ * method returns {@link #multiReader} is guaranteed to be <code>null</code>
+ * even if an exception is thrown.
+ * <p/>
+ * Please note that this method does not take care of any synchronization. A
+ * caller must ensure that it is the only thread operating on this multi
+ * index, or that it holds the {@link #updateMonitor}.
+ *
+ * @throws IOException
+ * if an error occurs while releasing the reader.
+ */
+ void releaseMultiReader() throws IOException
+ {
+ if (multiReader != null)
+ {
+ try
+ {
+ multiReader.release();
+ }
+ finally
+ {
+ multiReader = null;
+ }
+ }
+ }
- // commit persistent indexes
- for (int i = indexes.size() - 1; i >= 0; i--) {
- PersistentIndex index = (PersistentIndex) indexes.get(i);
- // only commit indexes we own
- // index merger also places PersistentIndex instances in
- // indexes,
- // but does not make them public by registering the name in
- // indexNames
- if (indexNames.contains(index.getName())) {
- index.commit();
- // check if index still contains documents
- if (index.getNumDocuments() == 0) {
- executeAndLog(new DeleteIndex(getTransactionId(), index
- .getName()));
- }
- }
- }
- executeAndLog(new Commit(getTransactionId()));
+ // -------------------------< internal
+ // >-------------------------------------
- indexNames.write(indexDir);
+ /**
+ * Enqueues unused segments for deletion in {@link #deletable}. This method
+ * does not synchronize on {@link #deletable}! A caller must ensure that it
+ * is the only one acting on the {@link #deletable} map.
+ *
+ * @throws IOException
+ * if an error occurs while reading directories.
+ */
+ private void enqueueUnusedSegments() throws IOException
+ {
+ // walk through index segments
+ String[] dirNames = directoryManager.getDirectoryNames();
+ for (int i = 0; i < dirNames.length; i++)
+ {
+ if (dirNames[i].startsWith("_") && !indexNames.contains(dirNames[i]))
+ {
+ deletable.add(dirNames[i]);
+ }
+ }
+ }
- // reset redo log
- redoLog.clear();
+ /**
+ * Cancel flush task and add new one
+ */
+ private void scheduleFlushTask()
+ {
+ // cancel task
+ if (flushTask != null)
+ {
+ flushTask.cancel();
+ }
+ // clear canceled tasks
+ FLUSH_TIMER.purge();
+ // new flush task, cause canceled can't be re-used
+ flushTask = new TimerTask()
+ {
+ public void run()
+ {
+ // check if there are any indexing jobs finished
+ checkIndexingQueue();
+ // check if volatile index should be flushed
+ checkFlush();
+ }
+ };
+ FLUSH_TIMER.schedule(flushTask, 0, 1000);
+ lastFlushTime = System.currentTimeMillis();
+ }
- lastFlushTime = System.currentTimeMillis();
- }
+ /**
+ * Resets the volatile index to a new instance.
+ */
+ private void resetVolatileIndex() throws IOException
+ {
+ volatileIndex = new VolatileIndex(handler.getTextAnalyzer(), handler.getSimilarity(), indexingQueue);
+ volatileIndex.setUseCompoundFile(handler.getUseCompoundFile());
+ volatileIndex.setMaxFieldLength(handler.getMaxFieldLength());
+ volatileIndex.setBufferSize(handler.getBufferSize());
+ }
- // delete obsolete indexes
- attemptDelete();
- }
+ /**
+ * Returns the current transaction id.
+ *
+ * @return the current transaction id.
+ */
+ private long getTransactionId()
+ {
+ return currentTransactionId;
+ }
- /**
- * Releases the {@link #multiReader} and sets it <code>null</code>. If the
- * reader is already <code>null</code> this method does nothing. When this
- * method returns {@link #multiReader} is guaranteed to be <code>null</code>
- * even if an exception is thrown.
- * <p/>
- * Please note that this method does not take care of any synchronization. A
- * caller must ensure that it is the only thread operating on this multi
- * index, or that it holds the {@link #updateMonitor}.
- *
- * @throws IOException
- * if an error occurs while releasing the reader.
- */
- void releaseMultiReader() throws IOException {
- if (multiReader != null) {
- try {
- multiReader.release();
- } finally {
- multiReader = null;
- }
- }
- }
+ /**
+ * Executes action <code>a</code> and appends the action to the redo log if
+ * successful.
+ *
+ * @param a
+ * the <code>Action</code> to execute.
+ * @return the executed action.
+ * @throws IOException
+ * if an error occurs while executing the action or appending
+ * the action to the redo log.
+ */
+ private Action executeAndLog(Action a) throws IOException
+ {
+ a.execute(this);
+ redoLog.append(a);
+ // please note that flushing the redo log is only required on
+ // commit, but we also want to keep track of new indexes for sure.
+ // otherwise it might happen that unused index folders are orphaned
+ // after a crash.
+ if (a.getType() == Action.TYPE_COMMIT || a.getType() == Action.TYPE_ADD_INDEX)
+ {
+ redoLog.flush();
+ }
+ return a;
+ }
- // -------------------------< internal
- // >-------------------------------------
+ /**
+ * Checks if it is needed to commit the volatile index according to
+ * {@link SearchIndex#getMaxVolatileIndexSize()}.
+ *
+ * @return <code>true</code> if the volatile index has been committed,
+ * <code>false</code> otherwise.
+ * @throws IOException
+ * if an error occurs while committing the volatile index.
+ */
+ private boolean checkVolatileCommit() throws IOException
+ {
+ if (volatileIndex.getRamSizeInBytes() >= handler.getMaxVolatileIndexSize())
+ {
+ commitVolatileIndex();
+ return true;
+ }
+ return false;
+ }
- /**
- * Enqueues unused segments for deletion in {@link #deletable}. This method
- * does not synchronize on {@link #deletable}! A caller must ensure that it
- * is the only one acting on the {@link #deletable} map.
- *
- * @throws IOException
- * if an error occurs while reading directories.
- */
- private void enqueueUnusedSegments() throws IOException {
- // walk through index segments
- String[] dirNames = directoryManager.getDirectoryNames();
- for (int i = 0; i < dirNames.length; i++) {
- if (dirNames[i].startsWith("_")
- && !indexNames.contains(dirNames[i])) {
- deletable.add(dirNames[i]);
- }
- }
- }
+ /**
+ * Commits the volatile index to a persistent index. The new persistent
+ * index is added to the list of indexes but not written to disk. When this
+ * method returns a new volatile index has been created.
+ *
+ * @throws IOException
+ * if an error occurs while writing the volatile index to disk.
+ */
+ private void commitVolatileIndex() throws IOException
+ {
- private void scheduleFlushTask() {
- lastFlushTime = System.currentTimeMillis();
- FLUSH_TIMER.schedule(flushTask, 0, 1000);
- }
+ // check if volatile index contains documents at all
+ if (volatileIndex.getNumDocuments() > 0)
+ {
- /**
- * Resets the volatile index to a new instance.
- */
- private void resetVolatileIndex() throws IOException {
- volatileIndex = new VolatileIndex(handler.getTextAnalyzer(), handler
- .getSimilarity(), indexingQueue);
- volatileIndex.setUseCompoundFile(handler.getUseCompoundFile());
- volatileIndex.setMaxFieldLength(handler.getMaxFieldLength());
- volatileIndex.setBufferSize(handler.getBufferSize());
- }
+ long time = System.currentTimeMillis();
+ // create index
+ CreateIndex create = new CreateIndex(getTransactionId(), null);
+ executeAndLog(create);
- /**
- * Returns the current transaction id.
- *
- * @return the current transaction id.
- */
- private long getTransactionId() {
- return currentTransactionId;
- }
+ // commit volatile index
+ executeAndLog(new VolatileCommit(getTransactionId(), create.getIndexName()));
- /**
- * Executes action <code>a</code> and appends the action to the redo log if
- * successful.
- *
- * @param a
- * the <code>Action</code> to execute.
- * @return the executed action.
- * @throws IOException
- * if an error occurs while executing the action or appending
- * the action to the redo log.
- */
- private Action executeAndLog(Action a) throws IOException {
- a.execute(this);
- redoLog.append(a);
- // please note that flushing the redo log is only required on
- // commit, but we also want to keep track of new indexes for sure.
- // otherwise it might happen that unused index folders are orphaned
- // after a crash.
- if (a.getType() == Action.TYPE_COMMIT
- || a.getType() == Action.TYPE_ADD_INDEX) {
- redoLog.flush();
- }
- return a;
- }
+ // add new index
+ AddIndex add = new AddIndex(getTransactionId(), create.getIndexName());
+ executeAndLog(add);
- /**
- * Checks if it is needed to commit the volatile index according to
- * {@link SearchIndex#getMaxVolatileIndexSize()}.
- *
- * @return <code>true</code> if the volatile index has been committed,
- * <code>false</code> otherwise.
- * @throws IOException
- * if an error occurs while committing the volatile index.
- */
- private boolean checkVolatileCommit() throws IOException {
- if (volatileIndex.getRamSizeInBytes() >= handler
- .getMaxVolatileIndexSize()) {
- commitVolatileIndex();
- return true;
- }
- return false;
- }
+ // create new volatile index
+ resetVolatileIndex();
- /**
- * Commits the volatile index to a persistent index. The new persistent
- * index is added to the list of indexes but not written to disk. When this
- * method returns a new volatile index has been created.
- *
- * @throws IOException
- * if an error occurs while writing the volatile index to disk.
- */
- private void commitVolatileIndex() throws IOException {
+ time = System.currentTimeMillis() - time;
+ log.debug("Committed in-memory index in " + time + "ms.");
+ }
+ }
- // check if volatile index contains documents at all
- if (volatileIndex.getNumDocuments() > 0) {
+ /**
+ * Recursively creates an index starting with the NodeState
+ * <code>node</code>.
+ *
+ * @param node
+ * the current NodeState.
+ * @param path
+ * the path of the current node.
+ * @param stateMgr
+ * the shared item state manager.
+ * @param count
+ * the number of nodes already indexed.
+ * @return the number of nodes indexed so far.
+ * @throws IOException
+ * if an error occurs while writing to the index.
+ * @throws ItemStateException
+ * if an node state cannot be found.
+ * @throws RepositoryException
+ * if any other error occurs
+ */
+ private long createIndex(NodeData node, ItemDataConsumer stateMgr, long count) throws IOException,
+ RepositoryException
+ {
+ // NodeId id = node.getNodeId();
- long time = System.currentTimeMillis();
- // create index
- CreateIndex create = new CreateIndex(getTransactionId(), null);
- executeAndLog(create);
+ if (indexingTree.isExcluded(node))
+ {
+ return count;
+ }
+ executeAndLog(new AddNode(getTransactionId(), node.getIdentifier()));
+ if (++count % 100 == 0)
+ {
- // commit volatile index
- executeAndLog(new VolatileCommit(getTransactionId(), create
- .getIndexName()));
+ log.info("indexing... {} ({})", node.getQPath().getAsString(), new Long(count));
+ }
+ if (count % 10 == 0)
+ {
+ checkIndexingQueue(true);
+ }
+ checkVolatileCommit();
+ List<NodeData> children = stateMgr.getChildNodesData(node);
+ for (NodeData nodeData : children)
+ {
- // add new index
- AddIndex add = new AddIndex(getTransactionId(), create
- .getIndexName());
- executeAndLog(add);
+ NodeData childState = (NodeData)stateMgr.getItemData(nodeData.getIdentifier());
+ if (childState == null)
+ {
+ handler.getOnWorkspaceInconsistencyHandler().handleMissingChildNode(
+ new ItemNotFoundException("Child not found "), handler, nodeData.getQPath(), node, nodeData);
+ }
- // create new volatile index
- resetVolatileIndex();
+ if (nodeData != null)
+ {
+ count = createIndex(nodeData, stateMgr, count);
+ }
+ }
- time = System.currentTimeMillis() - time;
- log.debug("Committed in-memory index in " + time + "ms.");
- }
- }
+ return count;
+ }
- /**
- * Recursively creates an index starting with the NodeState
- * <code>node</code>.
- *
- * @param node
- * the current NodeState.
- * @param path
- * the path of the current node.
- * @param stateMgr
- * the shared item state manager.
- * @param count
- * the number of nodes already indexed.
- * @return the number of nodes indexed so far.
- * @throws IOException
- * if an error occurs while writing to the index.
- * @throws ItemStateException
- * if an node state cannot be found.
- * @throws RepositoryException
- * if any other error occurs
- */
- private long createIndex(NodeData node, ItemDataConsumer stateMgr,
- long count) throws IOException, RepositoryException {
- // NodeId id = node.getNodeId();
+ /**
+ * Attempts to delete all files recorded in {@link #deletable}.
+ */
+ private void attemptDelete()
+ {
+ synchronized (deletable)
+ {
+ for (Iterator it = deletable.iterator(); it.hasNext();)
+ {
+ String indexName = (String)it.next();
+ if (directoryManager.delete(indexName))
+ {
+ it.remove();
+ }
+ else
+ {
+ log.info("Unable to delete obsolete index: " + indexName);
+ }
+ }
+ }
+ }
- if (indexingTree.isExcluded(node)) {
- return count;
- }
- executeAndLog(new AddNode(getTransactionId(), node.getIdentifier()));
- if (++count % 100 == 0) {
+ /**
+ * Removes the deletable file if it exists. The file is not used anymore in
+ * Jackrabbit versions >= 1.5.
+ */
+ private void removeDeletable()
+ {
+ String fileName = "deletable";
+ try
+ {
+ if (indexDir.fileExists(fileName))
+ {
+ indexDir.deleteFile(fileName);
+ }
+ }
+ catch (IOException e)
+ {
+ log.warn("Unable to remove file 'deletable'.", e);
+ }
+ }
- log.info("indexing... {} ({})", node.getQPath().getAsString(),
- new Long(count));
- }
- if (count % 10 == 0) {
- checkIndexingQueue(true);
- }
- checkVolatileCommit();
- List<NodeData> children = stateMgr.getChildNodesData(node);
- for (NodeData nodeData : children) {
+ /**
+ * Checks the duration between the last commit to this index and the current
+ * time and flushes the index (if there are changes at all) if the duration
+ * (idle time) is more than {@link SearchIndex#getVolatileIdleTime()}
+ * seconds.
+ */
+ private synchronized void checkFlush()
+ {
+ long idleTime = System.currentTimeMillis() - lastFlushTime;
+ // do not flush if volatileIdleTime is zero or negative
+ if (handler.getVolatileIdleTime() > 0 && idleTime > handler.getVolatileIdleTime() * 1000)
+ {
+ try
+ {
+ if (redoLog.hasEntries())
+ {
+ log.debug("Flushing index after being idle for " + idleTime + " ms.");
+ synchronized (updateMonitor)
+ {
+ updateInProgress = true;
+ }
+ try
+ {
+ flush();
+ }
+ finally
+ {
+ synchronized (updateMonitor)
+ {
+ updateInProgress = false;
+ updateMonitor.notifyAll();
+ releaseMultiReader();
+ }
+ }
+ }
+ }
+ catch (IOException e)
+ {
+ log.error("Unable to commit volatile index", e);
+ }
+ }
+ }
- NodeData childState = (NodeData) stateMgr.getItemData(nodeData
- .getIdentifier());
- if (childState == null) {
- handler.getOnWorkspaceInconsistencyHandler()
- .handleMissingChildNode(
- new ItemNotFoundException("Child not found "),
- handler, nodeData.getQPath(), node, nodeData);
- }
+ /**
+ * Checks the indexing queue for finished text extrator jobs and updates the
+ * index accordingly if there are any new ones. This method is synchronized
+ * and should only be called by the timer task that periodically checks if
+ * there are documents ready in the indexing queue. A new transaction is
+ * used when documents are transfered from the indexing queue to the index.
+ */
+ private synchronized void checkIndexingQueue()
+ {
+ checkIndexingQueue(false);
+ }
- if (nodeData != null) {
- count = createIndex(nodeData, stateMgr, count);
- }
- }
+ /**
+ * Checks the indexing queue for finished text extrator jobs and updates the
+ * index accordingly if there are any new ones.
+ *
+ * @param transactionPresent
+ * whether a transaction is in progress and the current
+ * {@link #getTransactionId()} should be used. If
+ * <code>false</code> a new transaction is created when documents
+ * are transfered from the indexing queue to the index.
+ */
+ private void checkIndexingQueue(boolean transactionPresent)
+ {
+ Document[] docs = indexingQueue.getFinishedDocuments();
+ Map finished = new HashMap();
+ for (int i = 0; i < docs.length; i++)
+ {
+ String uuid = docs[i].get(FieldNames.UUID);
+ finished.put(uuid, docs[i]);
+ }
- return count;
- }
+ // now update index with the remaining ones if there are any
+ if (!finished.isEmpty())
+ {
+ log.info("updating index with {} nodes from indexing queue.", new Long(finished.size()));
- /**
- * Attempts to delete all files recorded in {@link #deletable}.
- */
- private void attemptDelete() {
- synchronized (deletable) {
- for (Iterator it = deletable.iterator(); it.hasNext();) {
- String indexName = (String) it.next();
- if (directoryManager.delete(indexName)) {
- it.remove();
- } else {
- log.info("Unable to delete obsolete index: " + indexName);
- }
- }
- }
- }
+ // remove documents from the queue
+ for (Iterator it = finished.keySet().iterator(); it.hasNext();)
+ {
+ indexingQueue.removeDocument(it.next().toString());
+ }
- /**
- * Removes the deletable file if it exists. The file is not used anymore in
- * Jackrabbit versions >= 1.5.
- */
- private void removeDeletable() {
- String fileName = "deletable";
- try {
- if (indexDir.fileExists(fileName)) {
- indexDir.deleteFile(fileName);
- }
- } catch (IOException e) {
- log.warn("Unable to remove file 'deletable'.", e);
- }
- }
+ try
+ {
+ if (transactionPresent)
+ {
+ for (Iterator it = finished.keySet().iterator(); it.hasNext();)
+ {
+ executeAndLog(new DeleteNode(getTransactionId(), (String)it.next()));
+ }
+ for (Iterator it = finished.values().iterator(); it.hasNext();)
+ {
+ executeAndLog(new AddNode(getTransactionId(), (Document)it.next()));
+ }
+ }
+ else
+ {
+ update(finished.keySet(), finished.values());
+ }
+ }
+ catch (IOException e)
+ {
+ // update failed
+ log.warn("Failed to update index with deferred text extraction", e);
+ }
+ }
+ }
- /**
- * Checks the duration between the last commit to this index and the current
- * time and flushes the index (if there are changes at all) if the duration
- * (idle time) is more than {@link SearchIndex#getVolatileIdleTime()}
- * seconds.
- */
- private synchronized void checkFlush() {
- long idleTime = System.currentTimeMillis() - lastFlushTime;
- // do not flush if volatileIdleTime is zero or negative
- if (handler.getVolatileIdleTime() > 0
- && idleTime > handler.getVolatileIdleTime() * 1000) {
- try {
- if (redoLog.hasEntries()) {
- log.debug("Flushing index after being idle for " + idleTime
- + " ms.");
- synchronized (updateMonitor) {
- updateInProgress = true;
- }
- try {
- flush();
- } finally {
- synchronized (updateMonitor) {
- updateInProgress = false;
- updateMonitor.notifyAll();
- releaseMultiReader();
- }
- }
- }
- } catch (IOException e) {
- log.error("Unable to commit volatile index", e);
- }
- }
- }
+ // ------------------------< Actions
+ // >---------------------------------------
- /**
- * Checks the indexing queue for finished text extrator jobs and updates the
- * index accordingly if there are any new ones. This method is synchronized
- * and should only be called by the timer task that periodically checks if
- * there are documents ready in the indexing queue. A new transaction is
- * used when documents are transfered from the indexing queue to the index.
- */
- private synchronized void checkIndexingQueue() {
- checkIndexingQueue(false);
- }
+ /**
+ * Defines an action on an <code>MultiIndex</code>.
+ */
+ public abstract static class Action
+ {
- /**
- * Checks the indexing queue for finished text extrator jobs and updates the
- * index accordingly if there are any new ones.
- *
- * @param transactionPresent
- * whether a transaction is in progress and the current
- * {@link #getTransactionId()} should be used. If
- * <code>false</code> a new transaction is created when documents
- * are transfered from the indexing queue to the index.
- */
- private void checkIndexingQueue(boolean transactionPresent) {
- Document[] docs = indexingQueue.getFinishedDocuments();
- Map finished = new HashMap();
- for (int i = 0; i < docs.length; i++) {
- String uuid = docs[i].get(FieldNames.UUID);
- finished.put(uuid, docs[i]);
- }
+ /**
+ * Action identifier in redo log for transaction start action.
+ */
+ static final String START = "STR";
- // now update index with the remaining ones if there are any
- if (!finished.isEmpty()) {
- log.info("updating index with {} nodes from indexing queue.",
- new Long(finished.size()));
+ /**
+ * Action type for start action.
+ */
+ public static final int TYPE_START = 0;
- // remove documents from the queue
- for (Iterator it = finished.keySet().iterator(); it.hasNext();) {
- indexingQueue.removeDocument(it.next().toString());
- }
+ /**
+ * Action identifier in redo log for add node action.
+ */
+ static final String ADD_NODE = "ADD";
- try {
- if (transactionPresent) {
- for (Iterator it = finished.keySet().iterator(); it
- .hasNext();) {
- executeAndLog(new DeleteNode(getTransactionId(),
- (String) it.next()));
- }
- for (Iterator it = finished.values().iterator(); it
- .hasNext();) {
- executeAndLog(new AddNode(getTransactionId(),
- (Document) it.next()));
- }
- } else {
- update(finished.keySet(), finished.values());
- }
- } catch (IOException e) {
- // update failed
- log.warn(
- "Failed to update index with deferred text extraction",
- e);
- }
- }
- }
+ /**
+ * Action type for add node action.
+ */
+ public static final int TYPE_ADD_NODE = 1;
- // ------------------------< Actions
- // >---------------------------------------
+ /**
+ * Action identifier in redo log for node delete action.
+ */
+ static final String DELETE_NODE = "DEL";
- /**
- * Defines an action on an <code>MultiIndex</code>.
- */
- public abstract static class Action {
+ /**
+ * Action type for delete node action.
+ */
+ public static final int TYPE_DELETE_NODE = 2;
- /**
- * Action identifier in redo log for transaction start action.
- */
- static final String START = "STR";
+ /**
+ * Action identifier in redo log for transaction commit action.
+ */
+ static final String COMMIT = "COM";
- /**
- * Action type for start action.
- */
- public static final int TYPE_START = 0;
+ /**
+ * Action type for commit action.
+ */
+ public static final int TYPE_COMMIT = 3;
- /**
- * Action identifier in redo log for add node action.
- */
- static final String ADD_NODE = "ADD";
+ /**
+ * Action identifier in redo log for volatile index commit action.
+ */
+ static final String VOLATILE_COMMIT = "VOL_COM";
- /**
- * Action type for add node action.
- */
- public static final int TYPE_ADD_NODE = 1;
+ /**
+ * Action type for volatile index commit action.
+ */
+ public static final int TYPE_VOLATILE_COMMIT = 4;
- /**
- * Action identifier in redo log for node delete action.
- */
- static final String DELETE_NODE = "DEL";
+ /**
+ * Action identifier in redo log for index create action.
+ */
+ static final String CREATE_INDEX = "CRE_IDX";
- /**
- * Action type for delete node action.
- */
- public static final int TYPE_DELETE_NODE = 2;
+ /**
+ * Action type for create index action.
+ */
+ public static final int TYPE_CREATE_INDEX = 5;
- /**
- * Action identifier in redo log for transaction commit action.
- */
- static final String COMMIT = "COM";
+ /**
+ * Action identifier in redo log for index add action.
+ */
+ static final String ADD_INDEX = "ADD_IDX";
- /**
- * Action type for commit action.
- */
- public static final int TYPE_COMMIT = 3;
+ /**
+ * Action type for add index action.
+ */
+ public static final int TYPE_ADD_INDEX = 6;
- /**
- * Action identifier in redo log for volatile index commit action.
- */
- static final String VOLATILE_COMMIT = "VOL_COM";
+ /**
+ * Action identifier in redo log for delete index action.
+ */
+ static final String DELETE_INDEX = "DEL_IDX";
- /**
- * Action type for volatile index commit action.
- */
- public static final int TYPE_VOLATILE_COMMIT = 4;
+ /**
+ * Action type for delete index action.
+ */
+ public static final int TYPE_DELETE_INDEX = 7;
- /**
- * Action identifier in redo log for index create action.
- */
- static final String CREATE_INDEX = "CRE_IDX";
+ /**
+ * Transaction identifier for internal actions like volatile index
+ * commit triggered by timer thread.
+ */
+ static final long INTERNAL_TRANSACTION = -1;
- /**
- * Action type for create index action.
- */
- public static final int TYPE_CREATE_INDEX = 5;
+ /**
+ * Transaction identifier for internal action that replaces indexs.
+ */
+ static final long INTERNAL_TRANS_REPL_INDEXES = -2;
- /**
- * Action identifier in redo log for index add action.
- */
- static final String ADD_INDEX = "ADD_IDX";
+ /**
+ * The id of the transaction that executed this action.
+ */
+ private final long transactionId;
- /**
- * Action type for add index action.
- */
- public static final int TYPE_ADD_INDEX = 6;
+ /**
+ * The action type.
+ */
+ private final int type;
- /**
- * Action identifier in redo log for delete index action.
- */
- static final String DELETE_INDEX = "DEL_IDX";
+ /**
+ * Creates a new <code>Action</code>.
+ *
+ * @param transactionId
+ * the id of the transaction that executed this action.
+ * @param type
+ * the action type.
+ */
+ Action(long transactionId, int type)
+ {
+ this.transactionId = transactionId;
+ this.type = type;
+ }
- /**
- * Action type for delete index action.
- */
- public static final int TYPE_DELETE_INDEX = 7;
+ /**
+ * Returns the transaction id for this <code>Action</code>.
+ *
+ * @return the transaction id for this <code>Action</code>.
+ */
+ long getTransactionId()
+ {
+ return transactionId;
+ }
- /**
- * Transaction identifier for internal actions like volatile index
- * commit triggered by timer thread.
- */
- static final long INTERNAL_TRANSACTION = -1;
+ /**
+ * Returns the action type.
+ *
+ * @return the action type.
+ */
+ int getType()
+ {
+ return type;
+ }
- /**
- * Transaction identifier for internal action that replaces indexs.
- */
- static final long INTERNAL_TRANS_REPL_INDEXES = -2;
+ /**
+ * Executes this action on the <code>index</code>.
+ *
+ * @param index
+ * the index where to execute the action.
+ * @throws IOException
+ * if the action fails due to some I/O error in the index or
+ * some other error.
+ */
+ public abstract void execute(MultiIndex index) throws IOException;
- /**
- * The id of the transaction that executed this action.
- */
- private final long transactionId;
+ /**
+ * Executes the inverse operation of this action. That is, does an undo
+ * of this action. This default implementation does nothing, but returns
+ * silently.
+ *
+ * @param index
+ * the index where to undo the action.
+ * @throws IOException
+ * if the action cannot be undone.
+ */
+ public void undo(MultiIndex index) throws IOException
+ {
+ }
- /**
- * The action type.
- */
- private final int type;
+ /**
+ * Returns a <code>String</code> representation of this action that can
+ * be written to the {@link RedoLog}.
+ *
+ * @return a <code>String</code> representation of this action.
+ */
+ public abstract String toString();
- /**
- * Creates a new <code>Action</code>.
- *
- * @param transactionId
- * the id of the transaction that executed this action.
- * @param type
- * the action type.
- */
- Action(long transactionId, int type) {
- this.transactionId = transactionId;
- this.type = type;
- }
+ /**
+ * Parses an line in the redo log and created an {@link Action}.
+ *
+ * @param line
+ * the line from the redo log.
+ * @return an <code>Action</code>.
+ * @throws IllegalArgumentException
+ * if the line is malformed.
+ */
+ static Action fromString(String line) throws IllegalArgumentException
+ {
+ int endTransIdx = line.indexOf(' ');
+ if (endTransIdx == -1)
+ {
+ throw new IllegalArgumentException(line);
+ }
+ long transactionId;
+ try
+ {
+ transactionId = Long.parseLong(line.substring(0, endTransIdx));
+ }
+ catch (NumberFormatException e)
+ {
+ throw new IllegalArgumentException(line);
+ }
+ int endActionIdx = line.indexOf(' ', endTransIdx + 1);
+ if (endActionIdx == -1)
+ {
+ // action does not have arguments
+ endActionIdx = line.length();
+ }
+ String actionLabel = line.substring(endTransIdx + 1, endActionIdx);
+ String arguments = "";
+ if (endActionIdx + 1 <= line.length())
+ {
+ arguments = line.substring(endActionIdx + 1);
+ }
+ Action a;
+ if (actionLabel.equals(Action.ADD_NODE))
+ {
+ a = AddNode.fromString(transactionId, arguments);
+ }
+ else if (actionLabel.equals(Action.ADD_INDEX))
+ {
+ a = AddIndex.fromString(transactionId, arguments);
+ }
+ else if (actionLabel.equals(Action.COMMIT))
+ {
+ a = Commit.fromString(transactionId, arguments);
+ }
+ else if (actionLabel.equals(Action.CREATE_INDEX))
+ {
+ a = CreateIndex.fromString(transactionId, arguments);
+ }
+ else if (actionLabel.equals(Action.DELETE_INDEX))
+ {
+ a = DeleteIndex.fromString(transactionId, arguments);
+ }
+ else if (actionLabel.equals(Action.DELETE_NODE))
+ {
+ a = DeleteNode.fromString(transactionId, arguments);
+ }
+ else if (actionLabel.equals(Action.START))
+ {
+ a = Start.fromString(transactionId, arguments);
+ }
+ else if (actionLabel.equals(Action.VOLATILE_COMMIT))
+ {
+ a = VolatileCommit.fromString(transactionId, arguments);
+ }
+ else
+ {
+ throw new IllegalArgumentException(line);
+ }
+ return a;
+ }
+ }
- /**
- * Returns the transaction id for this <code>Action</code>.
- *
- * @return the transaction id for this <code>Action</code>.
- */
- long getTransactionId() {
- return transactionId;
- }
+ /**
+ * Adds an index to the MultiIndex's active persistent index list.
+ */
+ private static class AddIndex extends Action
+ {
- /**
- * Returns the action type.
- *
- * @return the action type.
- */
- int getType() {
- return type;
- }
+ /**
+ * The name of the index to add.
+ */
+ private String indexName;
- /**
- * Executes this action on the <code>index</code>.
- *
- * @param index
- * the index where to execute the action.
- * @throws IOException
- * if the action fails due to some I/O error in the index or
- * some other error.
- */
- public abstract void execute(MultiIndex index) throws IOException;
+ /**
+ * Creates a new AddIndex action.
+ *
+ * @param transactionId
+ * the id of the transaction that executes this action.
+ * @param indexName
+ * the name of the index to add, or <code>null</code> if an
+ * index with a new name should be created.
+ */
+ AddIndex(long transactionId, String indexName)
+ {
+ super(transactionId, Action.TYPE_ADD_INDEX);
+ this.indexName = indexName;
+ }
- /**
- * Executes the inverse operation of this action. That is, does an undo
- * of this action. This default implementation does nothing, but returns
- * silently.
- *
- * @param index
- * the index where to undo the action.
- * @throws IOException
- * if the action cannot be undone.
- */
- public void undo(MultiIndex index) throws IOException {
- }
+ /**
+ * Creates a new AddIndex action.
+ *
+ * @param transactionId
+ * the id of the transaction that executes this action.
+ * @param arguments
+ * the name of the index to add.
+ * @return the AddIndex action.
+ * @throws IllegalArgumentException
+ * if the arguments are malformed.
+ */
+ static AddIndex fromString(long transactionId, String arguments)
+ {
+ return new AddIndex(transactionId, arguments);
+ }
- /**
- * Returns a <code>String</code> representation of this action that can
- * be written to the {@link RedoLog}.
- *
- * @return a <code>String</code> representation of this action.
- */
- public abstract String toString();
+ /**
+ * Adds a sub index to <code>index</code>.
+ *
+ * @inheritDoc
+ */
+ public void execute(MultiIndex index) throws IOException
+ {
+ PersistentIndex idx = index.getOrCreateIndex(indexName);
+ if (!index.indexNames.contains(indexName))
+ {
+ index.indexNames.addName(indexName);
+ // now that the index is in the active list let the merger know
+ // about it
+ index.merger.indexAdded(indexName, idx.getNumDocuments());
+ }
+ }
- /**
- * Parses an line in the redo log and created an {@link Action}.
- *
- * @param line
- * the line from the redo log.
- * @return an <code>Action</code>.
- * @throws IllegalArgumentException
- * if the line is malformed.
- */
- static Action fromString(String line) throws IllegalArgumentException {
- int endTransIdx = line.indexOf(' ');
- if (endTransIdx == -1) {
- throw new IllegalArgumentException(line);
- }
- long transactionId;
- try {
- transactionId = Long.parseLong(line.substring(0, endTransIdx));
- } catch (NumberFormatException e) {
- throw new IllegalArgumentException(line);
- }
- int endActionIdx = line.indexOf(' ', endTransIdx + 1);
- if (endActionIdx == -1) {
- // action does not have arguments
- endActionIdx = line.length();
- }
- String actionLabel = line.substring(endTransIdx + 1, endActionIdx);
- String arguments = "";
- if (endActionIdx + 1 <= line.length()) {
- arguments = line.substring(endActionIdx + 1);
- }
- Action a;
- if (actionLabel.equals(Action.ADD_NODE)) {
- a = AddNode.fromString(transactionId, arguments);
- } else if (actionLabel.equals(Action.ADD_INDEX)) {
- a = AddIndex.fromString(transactionId, arguments);
- } else if (actionLabel.equals(Action.COMMIT)) {
- a = Commit.fromString(transactionId, arguments);
- } else if (actionLabel.equals(Action.CREATE_INDEX)) {
- a = CreateIndex.fromString(transactionId, arguments);
- } else if (actionLabel.equals(Action.DELETE_INDEX)) {
- a = DeleteIndex.fromString(transactionId, arguments);
- } else if (actionLabel.equals(Action.DELETE_NODE)) {
- a = DeleteNode.fromString(transactionId, arguments);
- } else if (actionLabel.equals(Action.START)) {
- a = Start.fromString(transactionId, arguments);
- } else if (actionLabel.equals(Action.VOLATILE_COMMIT)) {
- a = VolatileCommit.fromString(transactionId, arguments);
- } else {
- throw new IllegalArgumentException(line);
- }
- return a;
- }
- }
+ /**
+ * @inheritDoc
+ */
+ public String toString()
+ {
+ StringBuffer logLine = new StringBuffer();
+ logLine.append(Long.toString(getTransactionId()));
+ logLine.append(' ');
+ logLine.append(Action.ADD_INDEX);
+ logLine.append(' ');
+ logLine.append(indexName);
+ return logLine.toString();
+ }
+ }
- /**
- * Adds an index to the MultiIndex's active persistent index list.
- */
- private static class AddIndex extends Action {
+ /**
+ * Adds a node to the index.
+ */
+ private static class AddNode extends Action
+ {
- /**
- * The name of the index to add.
- */
- private String indexName;
+ /**
+ * The maximum length of a AddNode String.
+ */
+ private static final int ENTRY_LENGTH =
+ Long.toString(Long.MAX_VALUE).length() + Action.ADD_NODE.length() + Constants.UUID_FORMATTED_LENGTH + 2;
- /**
- * Creates a new AddIndex action.
- *
- * @param transactionId
- * the id of the transaction that executes this action.
- * @param indexName
- * the name of the index to add, or <code>null</code> if an
- * index with a new name should be created.
- */
- AddIndex(long transactionId, String indexName) {
- super(transactionId, Action.TYPE_ADD_INDEX);
- this.indexName = indexName;
- }
+ /**
+ * The uuid of the node to add.
+ */
+ private final String uuid;
- /**
- * Creates a new AddIndex action.
- *
- * @param transactionId
- * the id of the transaction that executes this action.
- * @param arguments
- * the name of the index to add.
- * @return the AddIndex action.
- * @throws IllegalArgumentException
- * if the arguments are malformed.
- */
- static AddIndex fromString(long transactionId, String arguments) {
- return new AddIndex(transactionId, arguments);
- }
+ /**
+ * The document to add to the index, or <code>null</code> if not
+ * available.
+ */
+ private Document doc;
- /**
- * Adds a sub index to <code>index</code>.
- *
- * @inheritDoc
- */
- public void execute(MultiIndex index) throws IOException {
- PersistentIndex idx = index.getOrCreateIndex(indexName);
- if (!index.indexNames.contains(indexName)) {
- index.indexNames.addName(indexName);
- // now that the index is in the active list let the merger know
- // about it
- index.merger.indexAdded(indexName, idx.getNumDocuments());
- }
- }
+ /**
+ * Creates a new AddNode action.
+ *
+ * @param transactionId
+ * the id of the transaction that executes this action.
+ * @param uuid
+ * the uuid of the node to add.
+ */
+ AddNode(long transactionId, String uuid)
+ {
+ super(transactionId, Action.TYPE_ADD_NODE);
+ this.uuid = uuid;
+ }
- /**
- * @inheritDoc
- */
- public String toString() {
- StringBuffer logLine = new StringBuffer();
- logLine.append(Long.toString(getTransactionId()));
- logLine.append(' ');
- logLine.append(Action.ADD_INDEX);
- logLine.append(' ');
- logLine.append(indexName);
- return logLine.toString();
- }
- }
+ /**
+ * Creates a new AddNode action.
+ *
+ * @param transactionId
+ * the id of the transaction that executes this action.
+ * @param doc
+ * the document to add.
+ */
+ AddNode(long transactionId, Document doc)
+ {
+ this(transactionId, doc.get(FieldNames.UUID));
+ this.doc = doc;
+ }
- /**
- * Adds a node to the index.
- */
- private static class AddNode extends Action {
+ /**
+ * Creates a new AddNode action.
+ *
+ * @param transactionId
+ * the id of the transaction that executes this action.
+ * @param arguments
+ * the arguments to this action. The uuid of the node to add
+ * @return the AddNode action.
+ * @throws IllegalArgumentException
+ * if the arguments are malformed. Not a UUID.
+ */
+ static AddNode fromString(long transactionId, String arguments) throws IllegalArgumentException
+ {
+ // simple length check
+ if (arguments.length() != Constants.UUID_FORMATTED_LENGTH)
+ {
+ throw new IllegalArgumentException("arguments is not a uuid");
+ }
+ return new AddNode(transactionId, arguments);
+ }
- /**
- * The maximum length of a AddNode String.
- */
- private static final int ENTRY_LENGTH = Long.toString(Long.MAX_VALUE)
- .length()
- + Action.ADD_NODE.length()
- + Constants.UUID_FORMATTED_LENGTH
- + 2;
+ /**
+ * Adds a node to the index.
+ *
+ * @inheritDoc
+ */
+ public void execute(MultiIndex index) throws IOException
+ {
+ if (doc == null)
+ {
+ try
+ {
+ doc = index.createDocument(uuid);
+ }
+ catch (RepositoryException e)
+ {
+ // node does not exist anymore
+ log.debug(e.getMessage());
+ }
+ }
+ if (doc != null)
+ {
+ index.volatileIndex.addDocuments(new Document[]{doc});
+ }
+ }
- /**
- * The uuid of the node to add.
- */
- private final String uuid;
+ /**
+ * @inheritDoc
+ */
+ public String toString()
+ {
+ StringBuffer logLine = new StringBuffer(ENTRY_LENGTH);
+ logLine.append(Long.toString(getTransactionId()));
+ logLine.append(' ');
+ logLine.append(Action.ADD_NODE);
+ logLine.append(' ');
+ logLine.append(uuid);
+ return logLine.toString();
+ }
+ }
- /**
- * The document to add to the index, or <code>null</code> if not
- * available.
- */
- private Document doc;
+ /**
+ * Commits a transaction.
+ */
+ private static class Commit extends Action
+ {
- /**
- * Creates a new AddNode action.
- *
- * @param transactionId
- * the id of the transaction that executes this action.
- * @param uuid
- * the uuid of the node to add.
- */
- AddNode(long transactionId, String uuid) {
- super(transactionId, Action.TYPE_ADD_NODE);
- this.uuid = uuid;
- }
+ /**
+ * Creates a new Commit action.
+ *
+ * @param transactionId
+ * the id of the transaction that is committed.
+ */
+ Commit(long transactionId)
+ {
+ super(transactionId, Action.TYPE_COMMIT);
+ }
- /**
- * Creates a new AddNode action.
- *
- * @param transactionId
- * the id of the transaction that executes this action.
- * @param doc
- * the document to add.
- */
- AddNode(long transactionId, Document doc) {
- this(transactionId, doc.get(FieldNames.UUID));
- this.doc = doc;
- }
+ /**
+ * Creates a new Commit action.
+ *
+ * @param transactionId
+ * the id of the transaction that executes this action.
+ * @param arguments
+ * ignored by this method.
+ * @return the Commit action.
+ */
+ static Commit fromString(long transactionId, String arguments)
+ {
+ return new Commit(transactionId);
+ }
- /**
- * Creates a new AddNode action.
- *
- * @param transactionId
- * the id of the transaction that executes this action.
- * @param arguments
- * the arguments to this action. The uuid of the node to add
- * @return the AddNode action.
- * @throws IllegalArgumentException
- * if the arguments are malformed. Not a UUID.
- */
- static AddNode fromString(long transactionId, String arguments)
- throws IllegalArgumentException {
- // simple length check
- if (arguments.length() != Constants.UUID_FORMATTED_LENGTH) {
- throw new IllegalArgumentException("arguments is not a uuid");
- }
- return new AddNode(transactionId, arguments);
- }
+ /**
+ * Touches the last flush time (sets it to the current time).
+ *
+ * @inheritDoc
+ */
+ public void execute(MultiIndex index) throws IOException
+ {
+ index.lastFlushTime = System.currentTimeMillis();
+ }
- /**
- * Adds a node to the index.
- *
- * @inheritDoc
- */
- public void execute(MultiIndex index) throws IOException {
- if (doc == null) {
- try {
- doc = index.createDocument(uuid);
- } catch (RepositoryException e) {
- // node does not exist anymore
- log.debug(e.getMessage());
- }
- }
- if (doc != null) {
- index.volatileIndex.addDocuments(new Document[] { doc });
- }
- }
+ /**
+ * @inheritDoc
+ */
+ public String toString()
+ {
+ return Long.toString(getTransactionId()) + ' ' + Action.COMMIT;
+ }
+ }
- /**
- * @inheritDoc
- */
- public String toString() {
- StringBuffer logLine = new StringBuffer(ENTRY_LENGTH);
- logLine.append(Long.toString(getTransactionId()));
- logLine.append(' ');
- logLine.append(Action.ADD_NODE);
- logLine.append(' ');
- logLine.append(uuid);
- return logLine.toString();
- }
- }
+ /**
+ * Creates an new sub index but does not add it to the active persistent
+ * index list.
+ */
+ private static class CreateIndex extends Action
+ {
- /**
- * Commits a transaction.
- */
- private static class Commit extends Action {
+ /**
+ * The name of the index to add.
+ */
+ private String indexName;
- /**
- * Creates a new Commit action.
- *
- * @param transactionId
- * the id of the transaction that is committed.
- */
- Commit(long transactionId) {
- super(transactionId, Action.TYPE_COMMIT);
- }
+ /**
+ * Creates a new CreateIndex action.
+ *
+ * @param transactionId
+ * the id of the transaction that executes this action.
+ * @param indexName
+ * the name of the index to add, or <code>null</code> if an
+ * index with a new name should be created.
+ */
+ CreateIndex(long transactionId, String indexName)
+ {
+ super(transactionId, Action.TYPE_CREATE_INDEX);
+ this.indexName = indexName;
+ }
- /**
- * Creates a new Commit action.
- *
- * @param transactionId
- * the id of the transaction that executes this action.
- * @param arguments
- * ignored by this method.
- * @return the Commit action.
- */
- static Commit fromString(long transactionId, String arguments) {
- return new Commit(transactionId);
- }
+ /**
+ * Creates a new CreateIndex action.
+ *
+ * @param transactionId
+ * the id of the transaction that executes this action.
+ * @param arguments
+ * the name of the index to create.
+ * @return the AddIndex action.
+ * @throws IllegalArgumentException
+ * if the arguments are malformed.
+ */
+ static CreateIndex fromString(long transactionId, String arguments)
+ {
+ // when created from String, this action is executed as redo action
+ return new CreateIndex(transactionId, arguments);
+ }
- /**
- * Touches the last flush time (sets it to the current time).
- *
- * @inheritDoc
- */
- public void execute(MultiIndex index) throws IOException {
- index.lastFlushTime = System.currentTimeMillis();
- }
+ /**
+ * Creates a new index.
+ *
+ * @inheritDoc
+ */
+ public void execute(MultiIndex index) throws IOException
+ {
+ PersistentIndex idx = index.getOrCreateIndex(indexName);
+ indexName = idx.getName();
+ }
- /**
- * @inheritDoc
- */
- public String toString() {
- return Long.toString(getTransactionId()) + ' ' + Action.COMMIT;
- }
- }
+ /**
+ * @inheritDoc
+ */
+ public void undo(MultiIndex index) throws IOException
+ {
+ if (index.hasIndex(indexName))
+ {
+ PersistentIndex idx = index.getOrCreateIndex(indexName);
+ idx.close();
+ index.deleteIndex(idx);
+ }
+ }
- /**
- * Creates an new sub index but does not add it to the active persistent
- * index list.
- */
- private static class CreateIndex extends Action {
+ /**
+ * @inheritDoc
+ */
+ public String toString()
+ {
+ StringBuffer logLine = new StringBuffer();
+ logLine.append(Long.toString(getTransactionId()));
+ logLine.append(' ');
+ logLine.append(Action.CREATE_INDEX);
+ logLine.append(' ');
+ logLine.append(indexName);
+ return logLine.toString();
+ }
- /**
- * The name of the index to add.
- */
- private String indexName;
+ /**
+ * Returns the index name that has been created. If this method is
+ * called before {@link #execute(MultiIndex)} it will return
+ * <code>null</code>.
+ *
+ * @return the name of the index that has been created.
+ */
+ String getIndexName()
+ {
+ return indexName;
+ }
+ }
- /**
- * Creates a new CreateIndex action.
- *
- * @param transactionId
- * the id of the transaction that executes this action.
- * @param indexName
- * the name of the index to add, or <code>null</code> if an
- * index with a new name should be created.
- */
- CreateIndex(long transactionId, String indexName) {
- super(transactionId, Action.TYPE_CREATE_INDEX);
- this.indexName = indexName;
- }
+ /**
+ * Closes and deletes an index that is no longer in use.
+ */
+ private static class DeleteIndex extends Action
+ {
- /**
- * Creates a new CreateIndex action.
- *
- * @param transactionId
- * the id of the transaction that executes this action.
- * @param arguments
- * the name of the index to create.
- * @return the AddIndex action.
- * @throws IllegalArgumentException
- * if the arguments are malformed.
- */
- static CreateIndex fromString(long transactionId, String arguments) {
- // when created from String, this action is executed as redo action
- return new CreateIndex(transactionId, arguments);
- }
+ /**
+ * The name of the index to add.
+ */
+ private String indexName;
- /**
- * Creates a new index.
- *
- * @inheritDoc
- */
- public void execute(MultiIndex index) throws IOException {
- PersistentIndex idx = index.getOrCreateIndex(indexName);
- indexName = idx.getName();
- }
+ /**
+ * Creates a new DeleteIndex action.
+ *
+ * @param transactionId
+ * the id of the transaction that executes this action.
+ * @param indexName
+ * the name of the index to delete.
+ */
+ DeleteIndex(long transactionId, String indexName)
+ {
+ super(transactionId, Action.TYPE_DELETE_INDEX);
+ this.indexName = indexName;
+ }
- /**
- * @inheritDoc
- */
- public void undo(MultiIndex index) throws IOException {
- if (index.hasIndex(indexName)) {
- PersistentIndex idx = index.getOrCreateIndex(indexName);
- idx.close();
- index.deleteIndex(idx);
- }
- }
+ /**
+ * Creates a new DeleteIndex action.
+ *
+ * @param transactionId
+ * the id of the transaction that executes this action.
+ * @param arguments
+ * the name of the index to delete.
+ * @return the DeleteIndex action.
+ * @throws IllegalArgumentException
+ * if the arguments are malformed.
+ */
+ static DeleteIndex fromString(long transactionId, String arguments)
+ {
+ return new DeleteIndex(transactionId, arguments);
+ }
- /**
- * @inheritDoc
- */
- public String toString() {
- StringBuffer logLine = new StringBuffer();
- logLine.append(Long.toString(getTransactionId()));
- logLine.append(' ');
- logLine.append(Action.CREATE_INDEX);
- logLine.append(' ');
- logLine.append(indexName);
- return logLine.toString();
- }
+ /**
+ * Removes a sub index from <code>index</code>.
+ *
+ * @inheritDoc
+ */
+ public void execute(MultiIndex index) throws IOException
+ {
+ // get index if it exists
+ for (Iterator it = index.indexes.iterator(); it.hasNext();)
+ {
+ PersistentIndex idx = (PersistentIndex)it.next();
+ if (idx.getName().equals(indexName))
+ {
+ idx.close();
+ index.deleteIndex(idx);
+ break;
+ }
+ }
+ }
- /**
- * Returns the index name that has been created. If this method is
- * called before {@link #execute(MultiIndex)} it will return
- * <code>null</code>.
- *
- * @return the name of the index that has been created.
- */
- String getIndexName() {
- return indexName;
- }
- }
+ /**
+ * @inheritDoc
+ */
+ public String toString()
+ {
+ StringBuffer logLine = new StringBuffer();
+ logLine.append(Long.toString(getTransactionId()));
+ logLine.append(' ');
+ logLine.append(Action.DELETE_INDEX);
+ logLine.append(' ');
+ logLine.append(indexName);
+ return logLine.toString();
+ }
+ }
- /**
- * Closes and deletes an index that is no longer in use.
- */
- private static class DeleteIndex extends Action {
+ /**
+ * Deletes a node from the index.
+ */
+ private static class DeleteNode extends Action
+ {
- /**
- * The name of the index to add.
- */
- private String indexName;
+ /**
+ * The maximum length of a DeleteNode String.
+ */
+ private static final int ENTRY_LENGTH =
+ Long.toString(Long.MAX_VALUE).length() + Action.DELETE_NODE.length() + Constants.UUID_FORMATTED_LENGTH + 2;
- /**
- * Creates a new DeleteIndex action.
- *
- * @param transactionId
- * the id of the transaction that executes this action.
- * @param indexName
- * the name of the index to delete.
- */
- DeleteIndex(long transactionId, String indexName) {
- super(transactionId, Action.TYPE_DELETE_INDEX);
- this.indexName = indexName;
- }
+ /**
+ * The uuid of the node to remove.
+ */
+ private final String uuid;
- /**
- * Creates a new DeleteIndex action.
- *
- * @param transactionId
- * the id of the transaction that executes this action.
- * @param arguments
- * the name of the index to delete.
- * @return the DeleteIndex action.
- * @throws IllegalArgumentException
- * if the arguments are malformed.
- */
- static DeleteIndex fromString(long transactionId, String arguments) {
- return new DeleteIndex(transactionId, arguments);
- }
+ /**
+ * Creates a new DeleteNode action.
+ *
+ * @param transactionId
+ * the id of the transaction that executes this action.
+ * @param uuid
+ * the uuid of the node to delete.
+ */
+ DeleteNode(long transactionId, String uuid)
+ {
+ super(transactionId, Action.TYPE_DELETE_NODE);
+ this.uuid = uuid;
+ }
- /**
- * Removes a sub index from <code>index</code>.
- *
- * @inheritDoc
- */
- public void execute(MultiIndex index) throws IOException {
- // get index if it exists
- for (Iterator it = index.indexes.iterator(); it.hasNext();) {
- PersistentIndex idx = (PersistentIndex) it.next();
- if (idx.getName().equals(indexName)) {
- idx.close();
- index.deleteIndex(idx);
- break;
- }
- }
- }
+ /**
+ * Creates a new DeleteNode action.
+ *
+ * @param transactionId
+ * the id of the transaction that executes this action.
+ * @param arguments
+ * the uuid of the node to delete.
+ * @return the DeleteNode action.
+ * @throws IllegalArgumentException
+ * if the arguments are malformed. Not a UUID.
+ */
+ static DeleteNode fromString(long transactionId, String arguments)
+ {
+ // simple length check
+ if (arguments.length() != Constants.UUID_FORMATTED_LENGTH)
+ {
+ throw new IllegalArgumentException("arguments is not a uuid");
+ }
+ return new DeleteNode(transactionId, arguments);
+ }
- /**
- * @inheritDoc
- */
- public String toString() {
- StringBuffer logLine = new StringBuffer();
- logLine.append(Long.toString(getTransactionId()));
- logLine.append(' ');
- logLine.append(Action.DELETE_INDEX);
- logLine.append(' ');
- logLine.append(indexName);
- return logLine.toString();
- }
- }
+ /**
+ * Deletes a node from the index.
+ *
+ * @inheritDoc
+ */
+ public void execute(MultiIndex index) throws IOException
+ {
+ String uuidString = uuid.toString();
+ // check if indexing queue is still working on
+ // this node from a previous update
+ Document doc = index.indexingQueue.removeDocument(uuidString);
+ if (doc != null)
+ {
+ Util.disposeDocument(doc);
+ }
+ Term idTerm = new Term(FieldNames.UUID, uuidString);
+ // if the document cannot be deleted from the volatile index
+ // delete it from one of the persistent indexes.
+ int num = index.volatileIndex.removeDocument(idTerm);
+ if (num == 0)
+ {
+ for (int i = index.indexes.size() - 1; i >= 0; i--)
+ {
+ // only look in registered indexes
+ PersistentIndex idx = (PersistentIndex)index.indexes.get(i);
+ if (index.indexNames.contains(idx.getName()))
+ {
+ num = idx.removeDocument(idTerm);
+ if (num > 0)
+ {
+ return;
+ }
+ }
+ }
+ }
+ }
- /**
- * Deletes a node from the index.
- */
- private static class DeleteNode extends Action {
+ /**
+ * @inheritDoc
+ */
+ public String toString()
+ {
+ StringBuffer logLine = new StringBuffer(ENTRY_LENGTH);
+ logLine.append(Long.toString(getTransactionId()));
+ logLine.append(' ');
+ logLine.append(Action.DELETE_NODE);
+ logLine.append(' ');
+ logLine.append(uuid);
+ return logLine.toString();
+ }
+ }
- /**
- * The maximum length of a DeleteNode String.
- */
- private static final int ENTRY_LENGTH = Long.toString(Long.MAX_VALUE)
- .length()
- + Action.DELETE_NODE.length()
- + Constants.UUID_FORMATTED_LENGTH
- + 2;
+ /**
+ * Starts a transaction.
+ */
+ private static class Start extends Action
+ {
- /**
- * The uuid of the node to remove.
- */
- private final String uuid;
+ /**
+ * Creates a new Start transaction action.
+ *
+ * @param transactionId
+ * the id of the transaction that started.
+ */
+ Start(long transactionId)
+ {
+ super(transactionId, Action.TYPE_START);
+ }
- /**
- * Creates a new DeleteNode action.
- *
- * @param transactionId
- * the id of the transaction that executes this action.
- * @param uuid
- * the uuid of the node to delete.
- */
- DeleteNode(long transactionId, String uuid) {
- super(transactionId, Action.TYPE_DELETE_NODE);
- this.uuid = uuid;
- }
+ /**
+ * Creates a new Start action.
+ *
+ * @param transactionId
+ * the id of the transaction that executes this action.
+ * @param arguments
+ * ignored by this method.
+ * @return the Start action.
+ */
+ static Start fromString(long transactionId, String arguments)
+ {
+ return new Start(transactionId);
+ }
- /**
- * Creates a new DeleteNode action.
- *
- * @param transactionId
- * the id of the transaction that executes this action.
- * @param arguments
- * the uuid of the node to delete.
- * @return the DeleteNode action.
- * @throws IllegalArgumentException
- * if the arguments are malformed. Not a UUID.
- */
- static DeleteNode fromString(long transactionId, String arguments) {
- // simple length check
- if (arguments.length() != Constants.UUID_FORMATTED_LENGTH) {
- throw new IllegalArgumentException("arguments is not a uuid");
- }
- return new DeleteNode(transactionId, arguments);
- }
+ /**
+ * Sets the current transaction id on <code>index</code>.
+ *
+ * @inheritDoc
+ */
+ public void execute(MultiIndex index) throws IOException
+ {
+ index.currentTransactionId = getTransactionId();
+ }
- /**
- * Deletes a node from the index.
- *
- * @inheritDoc
- */
- public void execute(MultiIndex index) throws IOException {
- String uuidString = uuid.toString();
- // check if indexing queue is still working on
- // this node from a previous update
- Document doc = index.indexingQueue.removeDocument(uuidString);
- if (doc != null) {
- Util.disposeDocument(doc);
- }
- Term idTerm = new Term(FieldNames.UUID, uuidString);
- // if the document cannot be deleted from the volatile index
- // delete it from one of the persistent indexes.
- int num = index.volatileIndex.removeDocument(idTerm);
- if (num == 0) {
- for (int i = index.indexes.size() - 1; i >= 0; i--) {
- // only look in registered indexes
- PersistentIndex idx = (PersistentIndex) index.indexes
- .get(i);
- if (index.indexNames.contains(idx.getName())) {
- num = idx.removeDocument(idTerm);
- if (num > 0) {
- return;
- }
- }
- }
- }
- }
+ /**
+ * @inheritDoc
+ */
+ public String toString()
+ {
+ return Long.toString(getTransactionId()) + ' ' + Action.START;
+ }
+ }
- /**
- * @inheritDoc
- */
- public String toString() {
- StringBuffer logLine = new StringBuffer(ENTRY_LENGTH);
- logLine.append(Long.toString(getTransactionId()));
- logLine.append(' ');
- logLine.append(Action.DELETE_NODE);
- logLine.append(' ');
- logLine.append(uuid);
- return logLine.toString();
- }
- }
+ /**
+ * Commits the volatile index to disk.
+ */
+ private static class VolatileCommit extends Action
+ {
- /**
- * Starts a transaction.
- */
- private static class Start extends Action {
+ /**
+ * The name of the target index to commit to.
+ */
+ private final String targetIndex;
- /**
- * Creates a new Start transaction action.
- *
- * @param transactionId
- * the id of the transaction that started.
- */
- Start(long transactionId) {
- super(transactionId, Action.TYPE_START);
- }
+ /**
+ * Creates a new VolatileCommit action.
+ *
+ * @param transactionId
+ * the id of the transaction that executes this action.
+ */
+ VolatileCommit(long transactionId, String targetIndex)
+ {
+ super(transactionId, Action.TYPE_VOLATILE_COMMIT);
+ this.targetIndex = targetIndex;
+ }
- /**
- * Creates a new Start action.
- *
- * @param transactionId
- * the id of the transaction that executes this action.
- * @param arguments
- * ignored by this method.
- * @return the Start action.
- */
- static Start fromString(long transactionId, String arguments) {
- return new Start(transactionId);
- }
+ /**
+ * Creates a new VolatileCommit action.
+ *
+ * @param transactionId
+ * the id of the transaction that executes this action.
+ * @param arguments
+ * ignored by this implementation.
+ * @return the VolatileCommit action.
+ */
+ static VolatileCommit fromString(long transactionId, String arguments)
+ {
+ return new VolatileCommit(transactionId, arguments);
+ }
- /**
- * Sets the current transaction id on <code>index</code>.
- *
- * @inheritDoc
- */
- public void execute(MultiIndex index) throws IOException {
- index.currentTransactionId = getTransactionId();
- }
+ /**
+ * Commits the volatile index to disk.
+ *
+ * @inheritDoc
+ */
+ public void execute(MultiIndex index) throws IOException
+ {
+ VolatileIndex volatileIndex = index.getVolatileIndex();
+ PersistentIndex persistentIndex = index.getOrCreateIndex(targetIndex);
+ persistentIndex.copyIndex(volatileIndex);
+ index.resetVolatileIndex();
+ }
- /**
- * @inheritDoc
- */
- public String toString() {
- return Long.toString(getTransactionId()) + ' ' + Action.START;
- }
- }
+ /**
+ * @inheritDoc
+ */
+ public String toString()
+ {
+ StringBuffer logLine = new StringBuffer();
+ logLine.append(Long.toString(getTransactionId()));
+ logLine.append(' ');
+ logLine.append(Action.VOLATILE_COMMIT);
+ logLine.append(' ');
+ logLine.append(targetIndex);
+ return logLine.toString();
+ }
+ }
- /**
- * Commits the volatile index to disk.
- */
- private static class VolatileCommit extends Action {
+ /**
+ * Set indexer io mode.
+ * @param ioMode
+ * @throws IOException
+ */
+ public void setIndexerIoMode(IndexerIoMode ioMode) throws IOException
+ {
+ log.info("Indexer io mode=" + ioMode);
+ //do some thing if changed
+ if (!this.ioMode.equals(ioMode))
+ {
+ this.ioMode = ioMode;
+ switch (ioMode)
+ {
+ case READ_ONLY :
+ setReadOny();
+ break;
+ case READ_WRITE :
+ setReadWrite();
+ break;
+ }
+ }
- /**
- * The name of the target index to commit to.
- */
- private final String targetIndex;
+ }
- /**
- * Creates a new VolatileCommit action.
- *
- * @param transactionId
- * the id of the transaction that executes this action.
- */
- VolatileCommit(long transactionId, String targetIndex) {
- super(transactionId, Action.TYPE_VOLATILE_COMMIT);
- this.targetIndex = targetIndex;
- }
+ /**
+ * Sets mode to READ_ONLY, discarding flush task
+ */
+ protected void setReadOny()
+ {
+ // try to stop merger in safe way
+ merger.dispose();
+ flushTask.cancel();
+ FLUSH_TIMER.purge();
+ this.redoLog = null;
+ }
- /**
- * Creates a new VolatileCommit action.
- *
- * @param transactionId
- * the id of the transaction that executes this action.
- * @param arguments
- * ignored by this implementation.
- * @return the VolatileCommit action.
- */
- static VolatileCommit fromString(long transactionId, String arguments) {
- return new VolatileCommit(transactionId, arguments);
- }
+ /**
+ * Sets mode to READ_WRITE, initiating recovery process
+ *
+ * @throws IOException
+ */
+ protected void setReadWrite() throws IOException
+ {
+ this.redoLog = new RedoLog(indexDir);
+ redoLogApplied = redoLog.hasEntries();
- /**
- * Commits the volatile index to disk.
- *
- * @inheritDoc
- */
- public void execute(MultiIndex index) throws IOException {
- VolatileIndex volatileIndex = index.getVolatileIndex();
- PersistentIndex persistentIndex = index
- .getOrCreateIndex(targetIndex);
- persistentIndex.copyIndex(volatileIndex);
- index.resetVolatileIndex();
- }
+ // run recovery
+ Recovery.run(this, redoLog);
- /**
- * @inheritDoc
- */
- public String toString() {
- StringBuffer logLine = new StringBuffer();
- logLine.append(Long.toString(getTransactionId()));
- logLine.append(' ');
- logLine.append(Action.VOLATILE_COMMIT);
- logLine.append(' ');
- logLine.append(targetIndex);
- return logLine.toString();
- }
- }
+ // enqueue unused segments for deletion
+ enqueueUnusedSegments();
+ attemptDelete();
+
+ // now that we are ready, start index merger
+ merger.start();
+ if (redoLogApplied)
+ {
+ // wait for the index merge to finish pending jobs
+ try
+ {
+ merger.waitUntilIdle();
+ }
+ catch (InterruptedException e)
+ {
+ // move on
+ }
+ flush();
+ }
+
+ if (indexNames.size() > 0)
+ {
+ scheduleFlushTask();
+ }
+ }
+
+ /**
+ * Temporary solution for indexer in cluster. This method re-reads list of indexes from FS.
+ * @throws IOException
+ */
+ protected void refreshIndexesList() throws IOException
+ {
+ log.info("Refreshing list of indexes...");
+ // release reader if any
+ releaseMultiReader();
+ // get new indexInfo
+ IndexInfos newIndexNames = new IndexInfos("indexes");
+ if (newIndexNames.exists(indexDir))
+ {
+ newIndexNames.read(indexDir);
+ }
+ // prepare added/removed sets
+ Set<String> removed = new HashSet<String>(indexNames.getNames());
+ removed.removeAll(newIndexNames.getNames());
+
+ Set<String> added = new HashSet<String>(newIndexNames.getNames());
+ added.removeAll(indexNames.getNames());
+
+ // remove removed indexes
+ Iterator<PersistentIndex> iterator = indexes.iterator();
+ while (iterator.hasNext())
+ {
+ PersistentIndex index = iterator.next();
+ if (removed.contains(((PersistentIndex)index).getName()))
+ {
+ ((PersistentIndex)index).close();
+ iterator.remove();
+ }
+ }
+ // add added indexes
+ for (String name : added)
+ {
+ // only open if it still exists
+ // it is possible that indexNames still contains a name for
+ // an index that has been deleted, but indexNames has not been
+ // written to disk.
+ if (!directoryManager.hasDirectory(name))
+ {
+ log.debug("index does not exist anymore: " + name);
+ // move on to next index
+ continue;
+ }
+ PersistentIndex index =
+ new PersistentIndex(name, handler.getTextAnalyzer(), handler.getSimilarity(), cache, indexingQueue,
+ directoryManager);
+ index.setMaxFieldLength(handler.getMaxFieldLength());
+ index.setUseCompoundFile(handler.getUseCompoundFile());
+ index.setTermInfosIndexDivisor(handler.getTermInfosIndexDivisor());
+ indexes.add(index);
+ }
+ indexNames = newIndexNames;
+ }
}
Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/NodeIndexer.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/NodeIndexer.java 2009-12-22 10:32:33 UTC (rev 1143)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/NodeIndexer.java 2009-12-22 13:29:21 UTC (rev 1144)
@@ -402,8 +402,9 @@
// WARN. DON'T USE access item BY PATH - it's may be a node in case of
// residual definitions in NT
List<ValueData> data =
- prop.getValues().size() > 0 ? prop.getValues() : ((PropertyData)stateProvider.getItemData(prop
- .getIdentifier())).getValues();
+ prop.getValues().size() > 0 ? prop.getValues() : ((PropertyData)stateProvider.getItemData(
+ (NodeData)stateProvider.getItemData(prop.getParentIdentifier()), prop.getQPath().getEntries()[prop
+ .getQPath().getEntries().length - 1])).getValues();
if (data == null)
log.warn("null value found at property " + prop.getQPath().getAsString());
Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java 2009-12-22 10:32:33 UTC (rev 1143)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java 2009-12-22 13:29:21 UTC (rev 1144)
@@ -52,6 +52,7 @@
import org.exoplatform.services.jcr.impl.core.query.DefaultQueryNodeFactory;
import org.exoplatform.services.jcr.impl.core.query.ErrorLog;
import org.exoplatform.services.jcr.impl.core.query.ExecutableQuery;
+import org.exoplatform.services.jcr.impl.core.query.IndexerIoMode;
import org.exoplatform.services.jcr.impl.core.query.QueryHandler;
import org.exoplatform.services.jcr.impl.core.query.QueryHandlerContext;
import org.exoplatform.services.jcr.impl.core.query.SearchIndexConfigurationHelper;
@@ -514,42 +515,44 @@
indexingConfig = createIndexingConfiguration(nsMappings);
analyzer.setIndexingConfig(indexingConfig);
- index = new MultiIndex(this, context.getIndexingTree());
- if (index.numDocs() == 0 && context.isCreateInitialIndex())
+ index = new MultiIndex(this, context.getIndexingTree(), ioMode);
+ // if RW mode, create initial index and start check
+ if (ioMode == IndexerIoMode.READ_WRITE)
{
-
- index.createInitialIndex(context.getItemStateManager());
- }
- if (consistencyCheckEnabled && (index.getRedoLogApplied() || forceConsistencyCheck))
- {
- log.info("Running consistency check...");
- try
+ if (index.numDocs() == 0 && context.isCreateInitialIndex())
{
- ConsistencyCheck check = ConsistencyCheck.run(index, context.getItemStateManager());
- if (autoRepair)
+ index.createInitialIndex(context.getItemStateManager());
+ }
+ if (consistencyCheckEnabled && (index.getRedoLogApplied() || forceConsistencyCheck))
+ {
+ log.info("Running consistency check...");
+ try
{
- check.repair(true);
- }
- else
- {
- List<ConsistencyCheckError> errors = check.getErrors();
- if (errors.size() == 0)
+ ConsistencyCheck check = ConsistencyCheck.run(index, context.getItemStateManager());
+ if (autoRepair)
{
- log.info("No errors detected.");
+ check.repair(true);
}
- for (Iterator<ConsistencyCheckError> it = errors.iterator(); it.hasNext();)
+ else
{
- ConsistencyCheckError err = it.next();
- log.info(err.toString());
+ List<ConsistencyCheckError> errors = check.getErrors();
+ if (errors.size() == 0)
+ {
+ log.info("No errors detected.");
+ }
+ for (Iterator<ConsistencyCheckError> it = errors.iterator(); it.hasNext();)
+ {
+ ConsistencyCheckError err = it.next();
+ log.info(err.toString());
+ }
}
}
+ catch (Exception e)
+ {
+ log.warn("Failed to run consistency check on index: " + e);
+ }
}
- catch (Exception e)
- {
- log.warn("Failed to run consistency check on index: " + e);
- }
}
-
// initialize spell checker
spellChecker = createSpellChecker();
@@ -2639,4 +2642,30 @@
return new LuceneQueryHits(reader, searcher, query);
}
+ /**
+ * @throws IOException
+ * @see org.exoplatform.services.jcr.impl.core.query.QueryHandler#setIndexerIoMode(org.exoplatform.services.jcr.impl.core.query.IndexerIoMode)
+ */
+ public void setIndexerIoMode(IndexerIoMode ioMode) throws IOException
+ {
+ log.info("Indexer io mode=" + ioMode);
+ //do some thing if changed
+ if (!this.ioMode.equals(ioMode))
+ {
+ this.ioMode = ioMode;
+ if (index != null)
+ {
+ switch (ioMode)
+ {
+ case READ_ONLY :
+ index.setIndexerIoMode(ioMode);
+ break;
+ case READ_WRITE :
+ index.setIndexerIoMode(ioMode);
+ break;
+ }
+ }
+ }
+
+ }
}
Added: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jbosscache/AbstractWriteOnlyCacheLoader.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jbosscache/AbstractWriteOnlyCacheLoader.java (rev 0)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jbosscache/AbstractWriteOnlyCacheLoader.java 2009-12-22 13:29:21 UTC (rev 1144)
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2003-2009 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.storage.jbosscache;
+
+import org.jboss.cache.Fqn;
+import org.jboss.cache.Modification;
+import org.jboss.cache.config.CacheLoaderConfig.IndividualCacheLoaderConfig;
+import org.jboss.cache.loader.AbstractCacheLoader;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Created by The eXo Platform SAS.
+ *
+ * <br/>
+ * Date: 06.11.2009
+ *
+ * @author <a href="mailto:alex.reshetnyak@exoplatform.com.ua">Alex Reshetnyak</a>
+ * @version $Id: AbstractWriteOnlyCacheLoader.java 480 2009-11-06 10:17:07Z pnedonosko $
+ */
+public abstract class AbstractWriteOnlyCacheLoader
+ extends AbstractCacheLoader
+{
+ private IndividualCacheLoaderConfig config;
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean exists(Fqn arg0) throws Exception
+ {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map<Object, Object> get(Fqn arg0) throws Exception
+ {
+ return Collections.emptyMap();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Set<Object> getChildrenNames(Fqn arg0) throws Exception
+ {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public IndividualCacheLoaderConfig getConfig()
+ {
+ return config;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void put(Fqn arg0, Map<Object, Object> arg1) throws Exception
+ {
+ throw new WriteOnlyCacheLoaderException("The method 'put(Fqn arg0, Map<Object, Object> arg1))' should not be called.");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object put(Fqn arg0, Object arg1, Object arg2) throws Exception
+ {
+ throw new WriteOnlyCacheLoaderException("The method 'put(Fqn arg0, Object arg1, Object arg2)' should not be called.");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void remove(Fqn arg0) throws Exception
+ {
+ throw new WriteOnlyCacheLoaderException("The method 'remove(Fqn arg0)' should not be called.");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object remove(Fqn arg0, Object arg1) throws Exception
+ {
+ throw new WriteOnlyCacheLoaderException("The method 'remove(Fqn arg0, Object arg1)' should not be called.");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void removeData(Fqn arg0) throws Exception
+ {
+ throw new WriteOnlyCacheLoaderException("The method 'removeData(Fqn arg0)' should not be called.");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setConfig(IndividualCacheLoaderConfig config)
+ {
+ this.config = config;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract void put(List<Modification> modifications) throws Exception ;
+
+}
Property changes on: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jbosscache/AbstractWriteOnlyCacheLoader.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jbosscache/WriteOnlyCacheLoaderException.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jbosscache/WriteOnlyCacheLoaderException.java (rev 0)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jbosscache/WriteOnlyCacheLoaderException.java 2009-12-22 13:29:21 UTC (rev 1144)
@@ -0,0 +1,48 @@
+package org.exoplatform.services.jcr.impl.storage.jbosscache;
+
+public class WriteOnlyCacheLoaderException
+ extends Exception
+{
+ /**
+ * Constructs an Exception without a message.
+ */
+ public WriteOnlyCacheLoaderException()
+ {
+ super();
+ }
+
+ /**
+ * Constructs an Exception with a detailed message.
+ *
+ * @param Message
+ * The message associated with the exception.
+ */
+ public WriteOnlyCacheLoaderException(String message)
+ {
+ super(message);
+ }
+
+ /**
+ * Constructs an Exception with a detailed message and base exception.
+ *
+ * @param Message
+ * The message associated with the exception.
+ * @param cause
+ * Throwable, the base exception.
+ */
+ public WriteOnlyCacheLoaderException(String message, Throwable cause)
+ {
+ super(message, cause);
+ }
+
+ /**
+ * WriteOnlyCacheLoaderException constructor.
+ *
+ * @param cause
+ * Throwable, the base exception.
+ */
+ public WriteOnlyCacheLoaderException(Throwable cause)
+ {
+ super(cause);
+ }
+}
Property changes on: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jbosscache/WriteOnlyCacheLoaderException.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Modified: jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/api/core/query/lucene/SlowQueryHandler.java
===================================================================
--- jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/api/core/query/lucene/SlowQueryHandler.java 2009-12-22 10:32:33 UTC (rev 1143)
+++ jcr/branches/1.12.0-JBCCACHE/exo.jcr.component.core/src/test/java/org/exoplatform/services/jcr/api/core/query/lucene/SlowQueryHandler.java 2009-12-22 13:29:21 UTC (rev 1144)
@@ -22,6 +22,7 @@
import org.exoplatform.services.jcr.impl.core.SessionImpl;
import org.exoplatform.services.jcr.impl.core.query.AbstractQueryHandler;
import org.exoplatform.services.jcr.impl.core.query.ExecutableQuery;
+import org.exoplatform.services.jcr.impl.core.query.IndexerIoMode;
import org.exoplatform.services.jcr.impl.core.query.QueryHandlerContext;
import org.exoplatform.services.jcr.impl.core.query.lucene.QueryHits;
@@ -78,7 +79,7 @@
}
- public void setContext(QueryHandlerContext context) throws IOException
+ public void setContext(QueryHandlerContext context)
{
// TODO Auto-generated method stub
@@ -93,4 +94,13 @@
return null;
}
+ /**
+ * @see org.exoplatform.services.jcr.impl.core.query.QueryHandler#setIndexerIoMode(org.exoplatform.services.jcr.impl.core.query.IndexerIoMode)
+ */
+ public void setIndexerIoMode(IndexerIoMode ioMode) throws IOException
+ {
+ // TODO Auto-generated method stub
+
+ }
+
}
16 years, 7 months
exo-jcr SVN: r1143 - jcr/trunk/exo.jcr.component.webdav/src/main/java/org/exoplatform/services/jcr/webdav.
by do-not-reply@jboss.org
Author: dkatayev
Date: 2009-12-22 05:32:33 -0500 (Tue, 22 Dec 2009)
New Revision: 1143
Modified:
jcr/trunk/exo.jcr.component.webdav/src/main/java/org/exoplatform/services/jcr/webdav/WebDavServiceImpl.java
Log:
EXOJCR-337 - Fixed
Modified: jcr/trunk/exo.jcr.component.webdav/src/main/java/org/exoplatform/services/jcr/webdav/WebDavServiceImpl.java
===================================================================
--- jcr/trunk/exo.jcr.component.webdav/src/main/java/org/exoplatform/services/jcr/webdav/WebDavServiceImpl.java 2009-12-21 18:20:39 UTC (rev 1142)
+++ jcr/trunk/exo.jcr.component.webdav/src/main/java/org/exoplatform/services/jcr/webdav/WebDavServiceImpl.java 2009-12-22 10:32:33 UTC (rev 1143)
@@ -1216,26 +1216,10 @@
{
try
{
- if (element.contains(":"))
- {
- element = element.replaceAll(":", URLEncoder.encode(":", "UTF-8"));
- }
- if (element.contains("["))
- {
- element = element.replaceAll("\\[", URLEncoder.encode("[", "UTF-8"));
- }
- if (element.contains("]"))
- {
- element = element.replaceAll("]", URLEncoder.encode("]", "UTF-8"));
- }
if (element.contains("'"))
{
element = element.replaceAll("'", URLEncoder.encode("'", "UTF-8"));
}
- if (element.contains("\""))
- {
- element = element.replaceAll("\"", URLEncoder.encode("\"", "UTF-8"));
- }
escapedPath.append(element + "/");
}
catch (Exception e)
16 years, 7 months