Lucene config and TX fixes

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@2293 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Andrew Hind
2006-02-03 13:25:42 +00:00
parent 29488351b1
commit f9ccb9ad25
5 changed files with 192 additions and 167 deletions

View File

@@ -246,6 +246,16 @@
<property name="indexerMaxFieldLength"> <property name="indexerMaxFieldLength">
<value>${lucene.indexer.maxFieldLength}</value> <value>${lucene.indexer.maxFieldLength}</value>
</property> </property>
<property name="writeLockTimeout">
<value>${lucene.write.lock.timeout}</value>
</property>
<property name="commitLockTimeout">
<value>${lucene.commit.lock.timeout}</value>
</property>
<property name="lockPollInterval">
<value>${lucene.lock.poll.interval}</value>
</property>
</bean> </bean>
<!-- Indexer and searchers for lucene --> <!-- Indexer and searchers for lucene -->

View File

@@ -42,6 +42,10 @@ lucene.indexer.maxMergeDocs=100000
# #
lucene.indexer.maxFieldLength=10000 lucene.indexer.maxFieldLength=10000
lucene.write.lock.timeout=10000
lucene.commit.lock.timeout=100000
lucene.lock.poll.interval=100
# Database configuration # Database configuration
db.driver=org.gjt.mm.mysql.Driver db.driver=org.gjt.mm.mysql.Driver
@@ -50,6 +54,11 @@ db.url=jdbc:mysql:///${db.name}
db.username=alfresco db.username=alfresco
db.password=alfresco db.password=alfresco
#db.name=alfresco
#db.url=jdbc:mysql://qasi/${db.name}
#db.username=alfresco
#db.password=alfresco
# Email configuration # Email configuration
mail.host= mail.host=

View File

@@ -35,12 +35,10 @@ import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory; import org.apache.lucene.store.FSDirectory;
/** /**
* Common support for abstracting the lucene indexer from its configuration and * Common support for abstracting the lucene indexer from its configuration and management requirements.
* management requirements.
* *
* <p> * <p>
* This class defines where the indexes are stored. This should be via a * This class defines where the indexes are stored. This should be via a configurable Bean property in Spring.
* configurable Bean property in Spring.
* *
* <p> * <p>
* The default file structure is * The default file structure is
@@ -51,13 +49,10 @@ import org.apache.lucene.store.FSDirectory;
* </ol> * </ol>
* *
* <p> * <p>
* The IndexWriter and IndexReader for a given index are toggled (one should be * The IndexWriter and IndexReader for a given index are toggled (one should be used for delete and the other for write). These are reused/closed/initialised as required.
* used for delete and the other for write). These are reused/closed/initialised
* as required.
* *
* <p> * <p>
* The index deltas are buffered to memory and persisted in the file system as * The index deltas are buffered to memory and persisted in the file system as required.
* required.
* *
* @author Andy Hind * @author Andy Hind
* *
@@ -86,15 +81,13 @@ public abstract class LuceneBase implements Lockable
private File undoDir; private File undoDir;
/** /**
* The index reader for the on file delta. (This should no coexist with the * The index reader for the on file delta. (This should no coexist with the writer)
* writer)
*/ */
private IndexReader deltaReader; private IndexReader deltaReader;
/** /**
* The writer for the delta to file. (This should no coexist with the * The writer for the delta to file. (This should no coexist with the reader)
* reader)
*/ */
private IndexWriter deltaWriter; private IndexWriter deltaWriter;
@@ -134,8 +127,7 @@ public abstract class LuceneBase implements Lockable
// "lucene-indexes"; // "lucene-indexes";
/** /**
* Initialise the configuration elements of the lucene store indexers and * Initialise the configuration elements of the lucene store indexers and searchers.
* searchers.
* *
* @param store * @param store
* @param deltaId * @param deltaId
@@ -192,8 +184,7 @@ public abstract class LuceneBase implements Lockable
} }
/** /**
* Utility method to find the path to the transactional store for this index * Utility method to find the path to the transactional store for this index delta
* delta
* *
* @return * @return
*/ */
@@ -226,8 +217,7 @@ public abstract class LuceneBase implements Lockable
} }
/** /**
* Utility method to initiliase a lucene FSDirectorya at a given location. * Utility method to initiliase a lucene FSDirectorya at a given location. We may try and delete the directory when the JVM exits.
* We may try and delete the directory when the JVM exits.
* *
* @param path * @param path
* @param temp * @param temp
@@ -267,9 +257,7 @@ public abstract class LuceneBase implements Lockable
} }
/** /**
* Get a searcher for the main index TODO: Split out support for the main * Get a searcher for the main index TODO: Split out support for the main index. We really only need this if we want to search over the changing index before it is committed
* index. We really only need this if we want to search over the changing
* index before it is committed
* *
* @return * @return
* @throws IOException * @throws IOException
@@ -511,8 +499,7 @@ public abstract class LuceneBase implements Lockable
} }
/** /**
* Save the in memory delta to the disk, make sure there is nothing held in * Save the in memory delta to the disk, make sure there is nothing held in memory
* memory
* *
* @throws IOException * @throws IOException
*/ */
@@ -527,9 +514,7 @@ public abstract class LuceneBase implements Lockable
/** /**
* Get all the locks so we can expect a merge to succeed * Get all the locks so we can expect a merge to succeed
* *
* The delta should be thread local so we do not have to worry about * The delta should be thread local so we do not have to worry about contentention TODO: Worry about main index contentention of readers and writers @
* contentention TODO: Worry about main index contentention of readers and
* writers @
* @throws IOException * @throws IOException
*/ */
protected void prepareToMergeIntoMain() throws LuceneIndexException protected void prepareToMergeIntoMain() throws LuceneIndexException
@@ -569,8 +554,7 @@ public abstract class LuceneBase implements Lockable
* Merge the delta in the main index. The delta still exists on disk. * Merge the delta in the main index. The delta still exists on disk.
* *
* @param terms * @param terms
* A list of terms that identifiy documents to be deleted from * A list of terms that identifiy documents to be deleted from the main index before the delta os merged in.
* the main index before the delta os merged in.
* *
* @throws IOException * @throws IOException
*/ */
@@ -581,43 +565,44 @@ public abstract class LuceneBase implements Lockable
throw new LuceneIndexException("Must hold the write lock to merge"); throw new LuceneIndexException("Must hold the write lock to merge");
} }
if (!indexExists(baseDir)) try
{ {
if (s_logger.isDebugEnabled()) if (!indexExists(baseDir))
{ {
s_logger.debug("Creating base index " + baseDir); if (s_logger.isDebugEnabled())
{
s_logger.debug("Creating base index " + baseDir);
}
try
{
mainWriter = new IndexWriter(baseDir, new LuceneAnalyser(dictionaryService), true);
mainWriter.setUseCompoundFile(true);
mainWriter.close();
if (s_logger.isDebugEnabled())
{
s_logger.debug("Created base index " + baseDir);
}
}
catch (IOException e)
{
s_logger.error("Error", e);
throw new LuceneIndexException("Failed to create empty base index at " + baseDir, e);
}
} }
try try
{ {
mainWriter = new IndexWriter(baseDir, new LuceneAnalyser(dictionaryService), true); mainReader = IndexReader.open(baseDir);
mainWriter.setUseCompoundFile(true);
mainWriter.close();
if (s_logger.isDebugEnabled()) if (s_logger.isDebugEnabled())
{ {
s_logger.debug("Created base index " + baseDir); s_logger.debug("Opened base index for deletes " + baseDir);
} }
} }
catch (IOException e) catch (IOException e)
{ {
s_logger.error("Error", e); s_logger.error("Error", e);
throw new LuceneIndexException("Failed to create empty base index at " + baseDir, e); throw new LuceneIndexException("Failed to create base index reader at " + baseDir, e);
} }
}
try
{
mainReader = IndexReader.open(baseDir);
if (s_logger.isDebugEnabled())
{
s_logger.debug("Opened base index for deletes " + baseDir);
}
}
catch (IOException e)
{
s_logger.error("Error", e);
throw new LuceneIndexException("Failed to create base index reader at " + baseDir, e);
}
try
{
// Do the deletions // Do the deletions
try try
{ {
@@ -740,11 +725,9 @@ public abstract class LuceneBase implements Lockable
/** /**
* Delete the delta and make this instance unusable * Delete the delta and make this instance unusable
* *
* This tries to tidy up all it can. It is possible some stuff will remain * This tries to tidy up all it can. It is possible some stuff will remain if errors are throws else where
* if errors are throws else where
* *
* TODO: Support for cleaning up transactions - need to support recovery and * TODO: Support for cleaning up transactions - need to support recovery and knowing of we are prepared
* knowing of we are prepared
* *
*/ */
protected void deleteDelta() throws LuceneIndexException protected void deleteDelta() throws LuceneIndexException

View File

@@ -50,7 +50,9 @@ import org.alfresco.util.GUID;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.store.Lock;
import org.quartz.Job; import org.quartz.Job;
import org.quartz.JobDataMap; import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext; import org.quartz.JobExecutionContext;
@@ -853,6 +855,21 @@ public class LuceneIndexerAndSearcherFactory implements LuceneIndexerAndSearcher
BooleanQuery.setMaxClauseCount(this.queryMaxClauses); BooleanQuery.setMaxClauseCount(this.queryMaxClauses);
} }
public void setWriteLockTimeout(long timeout)
{
IndexWriter.WRITE_LOCK_TIMEOUT = timeout;
}
public void setCommitLockTimeout(long timeout)
{
IndexWriter.COMMIT_LOCK_TIMEOUT = timeout;
}
public void setLockPollInterval(long time)
{
Lock.LOCK_POLL_INTERVAL = time;
}
public int getIndexerMaxFieldLength() public int getIndexerMaxFieldLength()
{ {
return indexerMaxFieldLength; return indexerMaxFieldLength;

View File

@@ -77,8 +77,7 @@ import org.apache.lucene.search.Searcher;
import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.TermQuery;
/** /**
* The implementation of the lucene based indexer. Supports basic transactional * The implementation of the lucene based indexer. Supports basic transactional behaviour if used on its own.
* behaviour if used on its own.
* *
* @author andyh * @author andyh
* *
@@ -112,8 +111,7 @@ public class LuceneIndexerImpl extends LuceneBase implements LuceneIndexer
private ContentService contentService; private ContentService contentService;
/** /**
* A list of all deletions we have made - at merge these deletions need to * A list of all deletions we have made - at merge these deletions need to be made against the main index.
* be made against the main index.
* *
* TODO: Consider if this information needs to be persisted for recovery * TODO: Consider if this information needs to be persisted for recovery
*/ */
@@ -133,9 +131,8 @@ public class LuceneIndexerImpl extends LuceneBase implements LuceneIndexer
private boolean isModified = false; private boolean isModified = false;
/** /**
* Flag to indicte if we are doing an in transactional delta or a batch * Flag to indicte if we are doing an in transactional delta or a batch update to the index. If true, we are just fixing up non atomically indexed things from one or more other
* update to the index. If true, we are just fixing up non atomically * updates.
* indexed things from one or more other updates.
*/ */
private Boolean isFTSUpdate = null; private Boolean isFTSUpdate = null;
@@ -199,13 +196,12 @@ public class LuceneIndexerImpl extends LuceneBase implements LuceneIndexer
this.contentService = contentService; this.contentService = contentService;
} }
/*************************************************************************** /*******************************************************************************************************************************************************************************
* * Indexer Implementation * ************************** * * Indexer Implementation * **************************
*/ */
/** /**
* Utility method to check we are in the correct state to do work Also keeps * Utility method to check we are in the correct state to do work Also keeps track of the dirty flag.
* track of the dirty flag.
* *
*/ */
@@ -557,92 +553,106 @@ public class LuceneIndexerImpl extends LuceneBase implements LuceneIndexer
try try
{ {
mainReader = getReader(); try
deltaReader = getDeltaReader();
mainSearcher = new IndexSearcher(mainReader);
deltaSearcher = new IndexSearcher(deltaReader);
for (Helper helper : toFTSIndex)
{ {
BooleanQuery query = new BooleanQuery(); mainReader = getReader();
query.add(new TermQuery(new Term("ID", helper.nodeRef.toString())), true, false); deltaReader = getDeltaReader();
query.add(new TermQuery(new Term("TX", helper.tx)), true, false); mainSearcher = new IndexSearcher(mainReader);
query.add(new TermQuery(new Term("ISNODE", "T")), false, false); deltaSearcher = new IndexSearcher(deltaReader);
try for (Helper helper : toFTSIndex)
{ {
Hits hits = mainSearcher.search(query); BooleanQuery query = new BooleanQuery();
if (hits.length() > 0) query.add(new TermQuery(new Term("ID", helper.nodeRef.toString())), true, false);
query.add(new TermQuery(new Term("TX", helper.tx)), true, false);
query.add(new TermQuery(new Term("ISNODE", "T")), false, false);
try
{ {
// No change Hits hits = mainSearcher.search(query);
for (int i = 0; i < hits.length(); i++) if (hits.length() > 0)
{ {
mainReader.delete(hits.id(i)); // No change
for (int i = 0; i < hits.length(); i++)
{
mainReader.delete(hits.id(i));
}
}
else
{
hits = deltaSearcher.search(query);
for (int i = 0; i < hits.length(); i++)
{
deltaReader.delete(hits.id(i));
}
} }
} }
else catch (IOException e)
{ {
hits = deltaSearcher.search(query); throw new LuceneIndexException("Failed to delete an FTS update from the original index", e);
for (int i = 0; i < hits.length(); i++)
{
deltaReader.delete(hits.id(i));
}
} }
} }
catch (IOException e)
}
finally
{
if (deltaSearcher != null)
{ {
throw new LuceneIndexException("Failed to delete an FTS update from the original index", e); try
{
deltaSearcher.close();
}
catch (IOException e)
{
s_logger.warn("Failed to close delta searcher", e);
}
}
if (mainSearcher != null)
{
try
{
mainSearcher.close();
}
catch (IOException e)
{
s_logger.warn("Failed to close main searcher", e);
}
}
try
{
closeDeltaReader();
}
catch (LuceneIndexException e)
{
s_logger.warn("Failed to close delta reader", e);
}
if (mainReader != null)
{
try
{
mainReader.close();
}
catch (IOException e)
{
s_logger.warn("Failed to close main reader", e);
}
} }
} }
mergeDeltaIntoMain(new LinkedHashSet<Term>());
}
catch (LuceneIndexException e)
{
// If anything goes wrong we try and do a roll back
rollback();
throw new LuceneIndexException("Commit failed", e);
} }
finally finally
{ {
if (deltaSearcher != null) // Make sure we tidy up
{ deleteDelta();
try
{
deltaSearcher.close();
}
catch (IOException e)
{
s_logger.warn("Failed to close delta searcher", e);
}
}
if (mainSearcher != null)
{
try
{
mainSearcher.close();
}
catch (IOException e)
{
s_logger.warn("Failed to close main searcher", e);
}
}
try
{
closeDeltaReader();
}
catch (LuceneIndexException e)
{
s_logger.warn("Failed to close delta reader", e);
}
if (mainReader != null)
{
try
{
mainReader.close();
}
catch (IOException e)
{
s_logger.warn("Failed to close main reader", e);
}
}
} }
mergeDeltaIntoMain(new LinkedHashSet<Term>());
} }
/** /**
@@ -650,8 +660,7 @@ public class LuceneIndexerImpl extends LuceneBase implements LuceneIndexer
* *
* At the moment this makes sure we have all the locks * At the moment this makes sure we have all the locks
* *
* TODO: This is not doing proper serialisation against the index as would a * TODO: This is not doing proper serialisation against the index as would a data base transaction.
* data base transaction.
* *
* @return * @return
*/ */
@@ -749,8 +758,7 @@ public class LuceneIndexerImpl extends LuceneBase implements LuceneIndexer
} }
/** /**
* Mark this index for roll back only. This action can not be reversed. It * Mark this index for roll back only. This action can not be reversed. It will reject all other work and only allow roll back.
* will reject all other work and only allow roll back.
* *
*/ */
@@ -1072,8 +1080,7 @@ public class LuceneIndexerImpl extends LuceneBase implements LuceneIndexer
try try
{ {
writer.addDocument(doc /* writer.addDocument(doc /*
* TODO: Select the language based * TODO: Select the language based analyser
* analyser
*/); */);
} }
catch (IOException e) catch (IOException e)
@@ -1396,7 +1403,8 @@ public class LuceneIndexerImpl extends LuceneBase implements LuceneIndexer
if (index) if (index)
{ {
// store mimetype in index - even if content does not index it is useful // store mimetype in index - even if content does not index it is useful
doc.add(new Field(attributeName+".mimetype", contentData.getMimetype(), false, true, false)); doc.add(new Field(attributeName + ".mimetype", contentData.getMimetype(), false, true,
false));
ContentReader reader = contentService.getReader(nodeRef, propertyName); ContentReader reader = contentService.getReader(nodeRef, propertyName);
if (reader != null && reader.exists()) if (reader != null && reader.exists())
@@ -1454,7 +1462,7 @@ public class LuceneIndexerImpl extends LuceneBase implements LuceneIndexer
InputStream ris = reader.getContentInputStream(); InputStream ris = reader.getContentInputStream();
try try
{ {
isr = new InputStreamReader(ris,"UTF-8"); isr = new InputStreamReader(ris, "UTF-8");
} }
catch (UnsupportedEncodingException e) catch (UnsupportedEncodingException e)
{ {
@@ -1465,7 +1473,7 @@ public class LuceneIndexerImpl extends LuceneBase implements LuceneIndexer
ris = reader.getReader().getContentInputStream(); ris = reader.getReader().getContentInputStream();
try try
{ {
isr = new InputStreamReader(ris,"UTF-8"); isr = new InputStreamReader(ris, "UTF-8");
} }
catch (UnsupportedEncodingException e) catch (UnsupportedEncodingException e)
{ {
@@ -1726,9 +1734,7 @@ public class LuceneIndexerImpl extends LuceneBase implements LuceneIndexer
try try
{ {
writer.addDocument(doc /* writer.addDocument(doc /*
* TODO: Select the * TODO: Select the language based analyser
* language based
* analyser
*/); */);
} }
catch (IOException e) catch (IOException e)