diff --git a/source/java/org/alfresco/repo/search/impl/lucene/index/IndexEntry.java b/source/java/org/alfresco/repo/search/impl/lucene/index/IndexEntry.java
new file mode 100644
index 0000000000..56c8942ce8
--- /dev/null
+++ b/source/java/org/alfresco/repo/search/impl/lucene/index/IndexEntry.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2005 Alfresco, Inc.
+ *
+ * Licensed under the Mozilla Public License version 1.1
+ * with a permitted attribution clause. You may obtain a
+ * copy of the License at
+ *
+ * http://www.alfresco.org/legal/license.txt
+ *
+ * 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.alfresco.repo.search.impl.lucene.index;
+
+/**
+ * Describes an entry in an index
+ *
+ * @author Andy Hind
+ */
+class IndexEntry
+{
+ /**
+ * The type of the index entry
+ */
+ IndexType type;
+
+ /**
+ * The unique name of the index entry
+ */
+ String name;
+
+ /**
+ * The preceeding index name.
+ * Allows deltas etc to apply to the index or an overlay for example.
+ */
+ String parentName;
+
+ /**
+ * The status of the inedx entry
+ */
+ TransactionStatus status;
+
+ /**
+ * If merging, the id where the result is going
+ */
+ String mergeId;
+
+ IndexEntry(IndexType type, String name, String parentName, TransactionStatus status, String mergeId)
+ {
+ this.type = type;
+ this.name = name;
+ this.parentName = parentName;
+ this.status = status;
+ this.mergeId = mergeId;
+ }
+
+ public String getMergeId()
+ {
+ return mergeId;
+ }
+
+ public void setMergeId(String mergeId)
+ {
+ this.mergeId = mergeId;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+ public String getParentName()
+ {
+ return parentName;
+ }
+
+ public void setParentName(String parentName)
+ {
+ this.parentName = parentName;
+ }
+
+ public TransactionStatus getStatus()
+ {
+ return status;
+ }
+
+ public void setStatus(TransactionStatus status)
+ {
+ this.status = status;
+ }
+
+ public IndexType getType()
+ {
+ return type;
+ }
+
+ public void setType(IndexType type)
+ {
+ this.type = type;
+ }
+
+
+}
\ No newline at end of file
diff --git a/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfo.java b/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfo.java
new file mode 100644
index 0000000000..8120d2608d
--- /dev/null
+++ b/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfo.java
@@ -0,0 +1,650 @@
+/*
+ * Copyright (C) 2005 Alfresco, Inc.
+ *
+ * Licensed under the Mozilla Public License version 1.1
+ * with a permitted attribution clause. You may obtain a
+ * copy of the License at
+ *
+ * http://www.alfresco.org/legal/license.txt
+ *
+ * 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.alfresco.repo.search.impl.lucene.index;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileLock;
+import java.nio.channels.FileChannel.MapMode;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Set;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.zip.CRC32;
+
+import org.alfresco.error.AlfrescoRuntimeException;
+import org.alfresco.repo.search.impl.lucene.LuceneAnalyser;
+import org.alfresco.service.cmr.dictionary.DictionaryService;
+import org.alfresco.util.GUID;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.Term;
+
+/**
+ * The information that makes up an index.
+ *
+ * IndexInfoVersion
+ *
+ * Repeated information of the form
+ *
+ *
Index Type.
+ *
sub-directory name.
+ *
Status
+ *
+ *
Indexes, sub indexes, and overlays must be committed. Status is ACTIVE, MERGING, COMPLETING_INDEX
+ *
Delta: Transaction status
+ *
Overlay: Transaction status
+ *
+ *
+ *
+ * Merges always take place to new indexes so we can detect merge failure or partial merges. Or we do not know what has merged.
+ *
+ * Incomplete delete merging does not matter - the overlay would still exist and be treated as such. So a document may be deleted in the index as well as in the applied overlay. It
+ * is still correctly deleted.
+ *
+ * TODO: Write element status into individual directories. This would be enough for recovery if both index files are lost or corrupted.
+ *
+ * TODO: Tidy up index status at start up or after some time. How long would you leave a merge to run?
+ *
+ * @author Andy Hind
+ */
+public class IndexInfo
+{
+
+ private static final boolean useNIOMemoryMapping = true;
+
+ /**
+ * The default name for the file that holds the index information
+ */
+ private static String INDEX_INFO = "IndexInfo";
+
+ /**
+ * The default name for the back up file that holds the index information
+ */
+ private static String INDEX_INFO_BACKUP = "IndexInfoBackup";
+
+ /**
+ * The directory that holds the index
+ */
+ private File indexDirectory;
+
+ /**
+ * The file holding the index information
+ */
+ private RandomAccessFile indexInfoRAF;
+
+ /**
+ * And its file channel
+ */
+ private FileChannel indexInfoChannel;
+
+ /**
+ * The file holding the backup index information.
+ */
+
+ private RandomAccessFile indexInfoBackupRAF;
+
+ /**
+ * And its file channel
+ */
+ private FileChannel indexInfoBackupChannel;
+
+ /**
+ * The file version. Negative is not yet written.
+ */
+ private long version = -1;
+
+ /**
+ * The index entries that make up this index. Map entries are looked up by name. These are maintained in order so document order is maintained.
+ */
+ private LinkedHashMap indexEntries = new LinkedHashMap();
+
+ /**
+ * Lock for the index entries
+ */
+ ReentrantReadWriteLock entriesReadWriteLock = new ReentrantReadWriteLock();
+
+ /**
+ * Lock for switching over the main cached reader
+ */
+ ReentrantReadWriteLock mainIndexReaderReadWriteLock = new ReentrantReadWriteLock();
+
+ /**
+ * Read only index readers that also do reference counting.
+ */
+ private HashMap referenceCountingReadOnlyIndexReaders = new HashMap();
+
+ /**
+ * Index writers
+ */
+ private HashMap indexWriters = new HashMap();
+
+ /**
+ * Index Readers
+ */
+ private HashMap indexReaders = new HashMap();
+
+ private DictionaryService dictionaryService;
+
+ public IndexInfo(File indexDirectory)
+ {
+ super();
+ this.indexDirectory = indexDirectory;
+
+ if (!this.indexDirectory.exists())
+ {
+ if (this.indexDirectory.mkdirs())
+ {
+ throw new AlfrescoRuntimeException("Failed to create index directory");
+ }
+ }
+ if (!this.indexDirectory.isDirectory())
+ {
+ throw new AlfrescoRuntimeException("The index must be held in a directory");
+ }
+
+ File indexInfoFile = new File(this.indexDirectory, INDEX_INFO);
+ File indexInfoBackupFile = new File(this.indexDirectory, INDEX_INFO_BACKUP);
+ if (createFile(indexInfoFile) && createFile(indexInfoBackupFile))
+ {
+ version = 0;
+ }
+
+ this.indexInfoRAF = openFile(indexInfoFile);
+ this.indexInfoChannel = this.indexInfoRAF.getChannel();
+
+ this.indexInfoBackupRAF = openFile(indexInfoBackupFile);
+ this.indexInfoBackupChannel = this.indexInfoBackupRAF.getChannel();
+
+ if (version == -1)
+ {
+ entriesReadWriteLock.writeLock().lock();
+ try
+ {
+ doWithFileLock(new LockWork