diff --git a/search-services/alfresco-solrclient-lib/source/java/org/alfresco/solr/AclReport.java b/search-services/alfresco-solrclient-lib/source/java/org/alfresco/solr/AclReport.java
new file mode 100644
index 000000000..152831582
--- /dev/null
+++ b/search-services/alfresco-solrclient-lib/source/java/org/alfresco/solr/AclReport.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2005-2010 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco 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 Alfresco. If not, see .
+ */
+package org.alfresco.solr;
+
+/**
+ * @author Andy
+ *
+ */
+public class AclReport
+{
+
+ private Long aclId;
+
+ private boolean existsInDb;
+
+ private Long indexAclDoc;
+
+ private Long indexAclTx;
+
+ /**
+ * @return the aclId
+ */
+ public Long getAclId()
+ {
+ return aclId;
+ }
+
+ /**
+ * @param aclId the aclId to set
+ */
+ public void setAclId(Long aclId)
+ {
+ this.aclId = aclId;
+ }
+
+ /**
+ * @return the existsInDb
+ */
+ public boolean isExistsInDb()
+ {
+ return existsInDb;
+ }
+
+ /**
+ * @param existsInDb the existsInDb to set
+ */
+ public void setExistsInDb(boolean existsInDb)
+ {
+ this.existsInDb = existsInDb;
+ }
+
+ /**
+ * @return the indexAclDoc
+ */
+ public Long getIndexAclDoc()
+ {
+ return indexAclDoc;
+ }
+
+ /**
+ * @param indexAclDoc the indexAclDoc to set
+ */
+ public void setIndexAclDoc(Long indexAclDoc)
+ {
+ this.indexAclDoc = indexAclDoc;
+ }
+
+ /**
+ * @return the indexAclTx
+ */
+ public Long getIndexAclTx()
+ {
+ return indexAclTx;
+ }
+
+ /**
+ * @param indexAclTx the indexAclTx to set
+ */
+ public void setIndexAclTx(Long indexAclTx)
+ {
+ this.indexAclTx = indexAclTx;
+ }
+
+
+
+}
diff --git a/search-services/alfresco-solrclient-lib/source/java/org/alfresco/solr/BoundedDeque.java b/search-services/alfresco-solrclient-lib/source/java/org/alfresco/solr/BoundedDeque.java
new file mode 100644
index 000000000..b01ee3572
--- /dev/null
+++ b/search-services/alfresco-solrclient-lib/source/java/org/alfresco/solr/BoundedDeque.java
@@ -0,0 +1,61 @@
+
+package org.alfresco.solr;
+
+import java.util.Iterator;
+import java.util.concurrent.LinkedBlockingDeque;
+
+public class BoundedDeque implements Iterable
+{
+ private LinkedBlockingDeque deque;
+
+ private int max = 10;
+
+ public BoundedDeque(int max)
+ {
+ this.max = max;
+ setDeque(new LinkedBlockingDeque());
+ }
+
+ /**
+ * @return
+ */
+ public int size()
+ {
+ return getDeque().size();
+ }
+
+ public void add(T add)
+ {
+ while (getDeque().size() > (max - 1))
+ {
+ getDeque().removeLast();
+ }
+ getDeque().addFirst(add);
+ }
+
+ public T getLast()
+ {
+ return getDeque().getFirst();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see java.lang.Iterable#iterator()
+ */
+ @Override
+ public Iterator iterator()
+ {
+ return getDeque().iterator();
+ }
+
+ public LinkedBlockingDeque getDeque()
+ {
+ return deque;
+ }
+
+ public void setDeque(LinkedBlockingDeque deque)
+ {
+ this.deque = deque;
+ }
+
+}
\ No newline at end of file
diff --git a/search-services/alfresco-solrclient-lib/source/java/org/alfresco/solr/IndexTrackingShutdownException.java b/search-services/alfresco-solrclient-lib/source/java/org/alfresco/solr/IndexTrackingShutdownException.java
new file mode 100644
index 000000000..0184b3f9a
--- /dev/null
+++ b/search-services/alfresco-solrclient-lib/source/java/org/alfresco/solr/IndexTrackingShutdownException.java
@@ -0,0 +1,11 @@
+package org.alfresco.solr;
+
+public class IndexTrackingShutdownException extends RuntimeException
+{
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -1294455847013444397L;
+
+}
diff --git a/search-services/alfresco-solrclient-lib/source/java/org/alfresco/solr/InformationServer.java b/search-services/alfresco-solrclient-lib/source/java/org/alfresco/solr/InformationServer.java
new file mode 100644
index 000000000..9beab8428
--- /dev/null
+++ b/search-services/alfresco-solrclient-lib/source/java/org/alfresco/solr/InformationServer.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2014 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco 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 Alfresco. If not, see .
+ */
+package org.alfresco.solr;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.alfresco.httpclient.AuthenticationException;
+import org.alfresco.repo.dictionary.DictionaryComponent;
+import org.alfresco.repo.dictionary.M2Model;
+import org.alfresco.repo.dictionary.NamespaceDAO;
+import org.alfresco.service.namespace.QName;
+import org.alfresco.solr.adapters.IOpenBitSet;
+import org.alfresco.solr.adapters.ISimpleOrderedMap;
+import org.alfresco.solr.client.AclChangeSet;
+import org.alfresco.solr.client.AclReaders;
+import org.alfresco.solr.client.AlfrescoModel;
+import org.alfresco.solr.client.Node;
+import org.alfresco.solr.client.Transaction;
+import org.alfresco.solr.tracker.Tracker;
+import org.json.JSONException;
+
+/**
+ * This is the interface to the information server, whether it be Solr or some other search server.
+ * @author Ahmed Owian
+ *
+ */
+public interface InformationServer
+{
+
+ void rollback() throws IOException;
+
+ void commit() throws IOException;
+
+ void indexAclTransaction(AclChangeSet changeSet, boolean overwrite) throws IOException;
+
+ void indexTransaction(Transaction info, boolean overwrite) throws IOException;
+
+ void deleteByTransactionId(Long transactionId) throws IOException;
+
+ void deleteByAclChangeSetId(Long aclChangeSetId) throws IOException;
+
+ void deleteByAclId(Long aclId) throws IOException;
+
+ void deleteByNodeId(Long nodeId) throws IOException;
+
+ void indexNode(Node node, boolean overwrite) throws IOException, AuthenticationException, JSONException;
+
+ NodeReport checkNodeCommon(NodeReport nodeReport);
+
+ long indexAcl(List aclReaderList, boolean overwrite) throws IOException;
+
+ TrackerState getTrackerInitialState() throws IOException;
+
+ int getDocSetSize(String targetTxId, String targetTxCommitTime) throws IOException;
+
+ int getRegisteredSearcherCount();
+
+ TrackerState getTrackerState();
+
+ void checkCache() throws IOException;
+
+ boolean isInIndex(String fieldType, long id) throws IOException;
+
+ Set getErrorDocIds() throws IOException;
+
+ Iterable> getCoreStats() throws IOException;
+
+ Tracker getTracker();
+
+ Map> getModelErrors();
+
+ IOpenBitSet getOpenBitSetInstance();
+
+ ISimpleOrderedMap getSimpleOrderedMapInstance();
+
+ DictionaryComponent getDictionaryService(String alternativeDictionary);
+
+ NamespaceDAO getNamespaceDAO();
+
+ List getAlfrescoModels();
+
+ void afterInitModels();
+
+ boolean putModel(M2Model model);
+
+ M2Model getM2Model(QName modelQName);
+
+}
diff --git a/search-services/alfresco-solrclient-lib/source/java/org/alfresco/solr/NodeReport.java b/search-services/alfresco-solrclient-lib/source/java/org/alfresco/solr/NodeReport.java
new file mode 100644
index 000000000..8e6965ffa
--- /dev/null
+++ b/search-services/alfresco-solrclient-lib/source/java/org/alfresco/solr/NodeReport.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2005-2010 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco 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 Alfresco. If not, see .
+ */
+package org.alfresco.solr;
+
+import org.alfresco.solr.client.Node.SolrApiNodeStatus;
+
+/**
+ * @author Andy
+ */
+public class NodeReport
+{
+ private Long dbid;
+
+ private Long dbTx;
+
+ private SolrApiNodeStatus dbNodeStatus;
+
+ private Long indexLeafDoc;
+
+ private Long indexAuxDoc;
+
+ private Long indexLeafTx;
+
+ private Long indexAuxTx;
+
+
+ /**
+ * @return the dbid
+ */
+ public Long getDbid()
+ {
+ return dbid;
+ }
+
+ /**
+ * @param dbid
+ * the dbid to set
+ */
+ public void setDbid(Long dbid)
+ {
+ this.dbid = dbid;
+ }
+
+ /**
+ * @return the dbTx
+ */
+ public Long getDbTx()
+ {
+ return dbTx;
+ }
+
+ /**
+ * @param dbTx
+ * the dbTx to set
+ */
+ public void setDbTx(Long dbTx)
+ {
+ this.dbTx = dbTx;
+ }
+
+ /**
+ * @return the dbNodeStatus
+ */
+ public SolrApiNodeStatus getDbNodeStatus()
+ {
+ return dbNodeStatus;
+ }
+
+ /**
+ * @param dbNodeStatus
+ * the dbNodeStatus to set
+ */
+ public void setDbNodeStatus(SolrApiNodeStatus dbNodeStatus)
+ {
+ this.dbNodeStatus = dbNodeStatus;
+ }
+
+ /**
+ * @return the indexLeafDoc
+ */
+ public Long getIndexLeafDoc()
+ {
+ return indexLeafDoc;
+ }
+
+ /**
+ * @param indexLeafDoc
+ * the indexLeafDoc to set
+ */
+ public void setIndexLeafDoc(Long indexLeafDoc)
+ {
+ this.indexLeafDoc = indexLeafDoc;
+ }
+
+ /**
+ * @return the indexAuxDoc
+ */
+ public Long getIndexAuxDoc()
+ {
+ return indexAuxDoc;
+ }
+
+ /**
+ * @param indexAuxDoc
+ * the indexAuxDoc to set
+ */
+ public void setIndexAuxDoc(Long indexAuxDoc)
+ {
+ this.indexAuxDoc = indexAuxDoc;
+ }
+
+ /**
+ * @return the indexLeafTx
+ */
+ public Long getIndexLeafTx()
+ {
+ return indexLeafTx;
+ }
+
+ /**
+ * @param indexLeafTx the indexLeafTx to set
+ */
+ public void setIndexLeafTx(Long indexLeafTx)
+ {
+ this.indexLeafTx = indexLeafTx;
+ }
+
+ /**
+ * @return the indexAuxTx
+ */
+ public Long getIndexAuxTx()
+ {
+ return indexAuxTx;
+ }
+
+ /**
+ * @param indexAuxTx the indexAuxTx to set
+ */
+ public void setIndexAuxTx(Long indexAuxTx)
+ {
+ this.indexAuxTx = indexAuxTx;
+ }
+
+
+
+}
diff --git a/search-services/alfresco-solrclient-lib/source/java/org/alfresco/solr/TrackerState.java b/search-services/alfresco-solrclient-lib/source/java/org/alfresco/solr/TrackerState.java
new file mode 100644
index 000000000..06d7f6c61
--- /dev/null
+++ b/search-services/alfresco-solrclient-lib/source/java/org/alfresco/solr/TrackerState.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2014 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco 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 Alfresco. If not, see .
+ */
+package org.alfresco.solr;
+
+
+/**
+ * This class was moved from org.alfresco.solr.tracker.CoreTracker
+ */
+public class TrackerState
+{
+ private volatile long lastChangeSetIdOnServer;
+
+ private volatile long lastChangeSetCommitTimeOnServer;
+
+ private volatile long lastIndexedChangeSetId;
+
+ private volatile long lastIndexedTxCommitTime = 0;
+
+ private volatile long lastIndexedTxId = 0;
+
+ private volatile long lastIndexedChangeSetCommitTime = 0;
+
+ private volatile long lastTxCommitTimeOnServer = 0;
+
+ private volatile long lastTxIdOnServer = 0;
+
+ private volatile long lastIndexedTxIdBeforeHoles = -1;
+
+ private volatile long lastIndexedChangeSetIdBeforeHoles = -1;
+
+ private volatile boolean running = false;
+
+ private volatile boolean checkedFirstTransactionTime = false;
+
+ private volatile boolean check = false;
+
+ private long timeToStopIndexing;
+
+ private long lastGoodChangeSetCommitTimeInIndex;
+
+ private long lastGoodTxCommitTimeInIndex ;
+
+ private long timeBeforeWhichThereCanBeNoHoles;
+
+ public long getLastChangeSetIdOnServer()
+ {
+ return lastChangeSetIdOnServer;
+ }
+
+ public void setLastChangeSetIdOnServer(long lastChangeSetIdOnServer)
+ {
+ this.lastChangeSetIdOnServer = lastChangeSetIdOnServer;
+ }
+
+ public long getLastChangeSetCommitTimeOnServer()
+ {
+ return lastChangeSetCommitTimeOnServer;
+ }
+
+ public void setLastChangeSetCommitTimeOnServer(long lastChangeSetCommitTimeOnServer)
+ {
+ this.lastChangeSetCommitTimeOnServer = lastChangeSetCommitTimeOnServer;
+ }
+
+ public long getLastIndexedChangeSetId()
+ {
+ return lastIndexedChangeSetId;
+ }
+
+ public void setLastIndexedChangeSetId(long lastIndexedChangeSetId)
+ {
+ this.lastIndexedChangeSetId = lastIndexedChangeSetId;
+ }
+
+ public long getLastIndexedTxCommitTime()
+ {
+ return lastIndexedTxCommitTime;
+ }
+
+ public void setLastIndexedTxCommitTime(long lastIndexedTxCommitTime)
+ {
+ this.lastIndexedTxCommitTime = lastIndexedTxCommitTime;
+ }
+
+ public long getLastIndexedTxId()
+ {
+ return lastIndexedTxId;
+ }
+
+ public void setLastIndexedTxId(long lastIndexedTxId)
+ {
+ this.lastIndexedTxId = lastIndexedTxId;
+ }
+
+ public long getLastIndexedChangeSetCommitTime()
+ {
+ return lastIndexedChangeSetCommitTime;
+ }
+
+ public void setLastIndexedChangeSetCommitTime(long lastIndexedChangeSetCommitTime)
+ {
+ this.lastIndexedChangeSetCommitTime = lastIndexedChangeSetCommitTime;
+ }
+
+ public long getLastTxCommitTimeOnServer()
+ {
+ return lastTxCommitTimeOnServer;
+ }
+
+ public void setLastTxCommitTimeOnServer(long lastTxCommitTimeOnServer)
+ {
+ this.lastTxCommitTimeOnServer = lastTxCommitTimeOnServer;
+ }
+
+ public long getLastTxIdOnServer()
+ {
+ return lastTxIdOnServer;
+ }
+
+ public void setLastTxIdOnServer(long lastTxIdOnServer)
+ {
+ this.lastTxIdOnServer = lastTxIdOnServer;
+ }
+
+ public long getLastIndexedTxIdBeforeHoles()
+ {
+ return lastIndexedTxIdBeforeHoles;
+ }
+
+ public void setLastIndexedTxIdBeforeHoles(long lastIndexedTxIdBeforeHoles)
+ {
+ this.lastIndexedTxIdBeforeHoles = lastIndexedTxIdBeforeHoles;
+ }
+
+ public long getLastIndexedChangeSetIdBeforeHoles()
+ {
+ return lastIndexedChangeSetIdBeforeHoles;
+ }
+
+ public void setLastIndexedChangeSetIdBeforeHoles(long lastIndexedChangeSetIdBeforeHoles)
+ {
+ this.lastIndexedChangeSetIdBeforeHoles = lastIndexedChangeSetIdBeforeHoles;
+ }
+
+ public boolean isRunning()
+ {
+ return running;
+ }
+
+ public void setRunning(boolean running)
+ {
+ this.running = running;
+ }
+
+ public boolean isCheckedFirstTransactionTime()
+ {
+ return checkedFirstTransactionTime;
+ }
+
+ public void setCheckedFirstTransactionTime(boolean checkedFirstTransactionTime)
+ {
+ this.checkedFirstTransactionTime = checkedFirstTransactionTime;
+ }
+
+ public boolean isCheck()
+ {
+ return check;
+ }
+
+ public void setCheck(boolean check)
+ {
+ this.check = check;
+ }
+
+ public long getTimeToStopIndexing()
+ {
+ return timeToStopIndexing;
+ }
+
+ public void setTimeToStopIndexing(long timeToStopIndexing)
+ {
+ this.timeToStopIndexing = timeToStopIndexing;
+ }
+
+ public long getLastGoodChangeSetCommitTimeInIndex()
+ {
+ return lastGoodChangeSetCommitTimeInIndex;
+ }
+
+ public void setLastGoodChangeSetCommitTimeInIndex(long lastGoodChangeSetCommitTimeInIndex)
+ {
+ this.lastGoodChangeSetCommitTimeInIndex = lastGoodChangeSetCommitTimeInIndex;
+ }
+
+ public long getLastGoodTxCommitTimeInIndex()
+ {
+ return lastGoodTxCommitTimeInIndex;
+ }
+
+ public void setLastGoodTxCommitTimeInIndex(long lastGoodTxCommitTimeInIndex)
+ {
+ this.lastGoodTxCommitTimeInIndex = lastGoodTxCommitTimeInIndex;
+ }
+
+ public long getTimeBeforeWhichThereCanBeNoHoles()
+ {
+ return timeBeforeWhichThereCanBeNoHoles;
+ }
+
+ public void setTimeBeforeWhichThereCanBeNoHoles(long timeBeforeWhichThereCanBeNoHoles)
+ {
+ this.timeBeforeWhichThereCanBeNoHoles = timeBeforeWhichThereCanBeNoHoles;
+ }
+}
+
diff --git a/search-services/alfresco-solrclient-lib/source/java/org/alfresco/solr/adapters/IOpenBitSet.java b/search-services/alfresco-solrclient-lib/source/java/org/alfresco/solr/adapters/IOpenBitSet.java
new file mode 100644
index 000000000..a34aecefa
--- /dev/null
+++ b/search-services/alfresco-solrclient-lib/source/java/org/alfresco/solr/adapters/IOpenBitSet.java
@@ -0,0 +1,15 @@
+
+package org.alfresco.solr.adapters;
+
+public interface IOpenBitSet
+{
+
+ void set(long txid);
+
+ void or(IOpenBitSet duplicatedTxInIndex);
+
+ long nextSetBit(long l);
+
+ long cardinality();
+
+}
\ No newline at end of file
diff --git a/search-services/alfresco-solrclient-lib/source/java/org/alfresco/solr/adapters/ISimpleOrderedMap.java b/search-services/alfresco-solrclient-lib/source/java/org/alfresco/solr/adapters/ISimpleOrderedMap.java
new file mode 100644
index 000000000..8485f9a91
--- /dev/null
+++ b/search-services/alfresco-solrclient-lib/source/java/org/alfresco/solr/adapters/ISimpleOrderedMap.java
@@ -0,0 +1,9 @@
+package org.alfresco.solr.adapters;
+
+
+public interface ISimpleOrderedMap
+{
+
+ void add(String name, T val);
+
+}
diff --git a/search-services/alfresco-solrclient-lib/source/java/org/alfresco/solr/tracker/IndexHealthReport.java b/search-services/alfresco-solrclient-lib/source/java/org/alfresco/solr/tracker/IndexHealthReport.java
new file mode 100644
index 000000000..40390c7f3
--- /dev/null
+++ b/search-services/alfresco-solrclient-lib/source/java/org/alfresco/solr/tracker/IndexHealthReport.java
@@ -0,0 +1,428 @@
+/*
+ * Copyright (C) 2005-2014 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco 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 Alfresco. If not, see .
+ */
+package org.alfresco.solr.tracker;
+
+import org.alfresco.solr.InformationServer;
+import org.alfresco.solr.adapters.IOpenBitSet;
+
+
+public class IndexHealthReport
+{
+ long dbTransactionCount;
+
+ IOpenBitSet missingTxFromIndex;
+
+ IOpenBitSet duplicatedTxInIndex;
+
+ IOpenBitSet txInIndexButNotInDb;
+
+ IOpenBitSet duplicatedLeafInIndex;
+
+ IOpenBitSet duplicatedAuxInIndex;
+
+ long transactionDocsInIndex;
+
+ long uniqueTransactionDocsInIndex;
+
+ long uniqueAclTransactionDocsInIndex;
+
+ long aclTransactionDocsInIndex;
+
+ long leafDocCountInIndex;
+
+ long auxDocCountInIndex;
+
+ long lastIndexedCommitTime;
+
+ long lastIndexedIdBeforeHoles;
+
+ long dbAclTransactionCount;
+
+ IOpenBitSet missingAclTxFromIndex;
+
+ IOpenBitSet duplicatedAclTxInIndex;
+
+ IOpenBitSet aclTxInIndexButNotInDb;
+
+ IOpenBitSet duplicatedErrorInIndex;
+
+ IOpenBitSet duplicatedUnindexedInIndex;
+
+ long errorDocCountInIndex;
+
+ long unindexedDocCountInIndex;
+
+ public IndexHealthReport(InformationServer srv)
+ {
+ this.missingTxFromIndex = srv.getOpenBitSetInstance();
+ this.duplicatedTxInIndex = srv.getOpenBitSetInstance();
+ this.txInIndexButNotInDb = srv.getOpenBitSetInstance();
+ this.duplicatedLeafInIndex = srv.getOpenBitSetInstance();
+ this.duplicatedAuxInIndex = srv.getOpenBitSetInstance();
+
+ this.missingAclTxFromIndex = srv.getOpenBitSetInstance();
+ this.duplicatedAclTxInIndex = srv.getOpenBitSetInstance();
+ this.aclTxInIndexButNotInDb = srv.getOpenBitSetInstance();
+ this.duplicatedErrorInIndex = srv.getOpenBitSetInstance();
+ this.duplicatedUnindexedInIndex = srv.getOpenBitSetInstance();
+ }
+
+ /**
+ * @return the transactionDocsInIndex
+ */
+ public long getTransactionDocsInIndex()
+ {
+ return transactionDocsInIndex;
+ }
+
+ public long getAclTransactionDocsInIndex()
+ {
+ return aclTransactionDocsInIndex;
+ }
+
+ /**
+ * @param leafCount
+ */
+ public void setLeafDocCountInIndex(long leafDocCountInIndex)
+ {
+ this.leafDocCountInIndex = leafDocCountInIndex;
+ }
+
+ /**
+ * @return the leafDocCountInIndex
+ */
+ public long getLeafDocCountInIndex()
+ {
+ return leafDocCountInIndex;
+ }
+
+ /**
+ * @param auxCount
+ */
+ public void setAuxDocCountInIndex(long auxDocCountInIndex)
+ {
+ this.auxDocCountInIndex = auxDocCountInIndex;
+ }
+
+ /**
+ * @return the leafDocCountInIndex
+ */
+ public long getAuxDocCountInIndex()
+ {
+ return auxDocCountInIndex;
+ }
+
+ /**
+ * @param txid
+ */
+ public void setDuplicatedLeafInIndex(long txid)
+ {
+ duplicatedLeafInIndex.set(txid);
+
+ }
+
+ /**
+ * @return the duplicatedLeafInIndex
+ */
+ public IOpenBitSet getDuplicatedLeafInIndex()
+ {
+ return duplicatedLeafInIndex;
+ }
+
+ /**
+ * @param txid
+ */
+ public void setDuplicatedAuxInIndex(long txid)
+ {
+ duplicatedAuxInIndex.set(txid);
+
+ }
+
+ /**
+ * @return the duplicatedLeafInIndex
+ */
+ public IOpenBitSet getDuplicatedAuxInIndex()
+ {
+ return duplicatedAuxInIndex;
+ }
+
+ /**
+ * @param transactionDocsInIndex
+ * the transactionDocsInIndex to set
+ */
+ public void setTransactionDocsInIndex(long transactionDocsInIndex)
+ {
+ this.transactionDocsInIndex = transactionDocsInIndex;
+ }
+
+ /**
+ * @param transactionDocsInIndex
+ * the transactionDocsInIndex to set
+ */
+ public void setAclTransactionDocsInIndex(long aclTransactionDocsInIndex)
+ {
+ this.aclTransactionDocsInIndex = aclTransactionDocsInIndex;
+ }
+
+ /**
+ * @return the missingFromIndex
+ */
+ public IOpenBitSet getMissingTxFromIndex()
+ {
+ return missingTxFromIndex;
+ }
+
+ /**
+ * @return the missingFromIndex
+ */
+ public IOpenBitSet getMissingAclTxFromIndex()
+ {
+ return missingAclTxFromIndex;
+ }
+
+ /**
+ * @return the duplicatedInIndex
+ */
+ public IOpenBitSet getDuplicatedTxInIndex()
+ {
+ return duplicatedTxInIndex;
+ }
+
+ /**
+ * @return the duplicatedInIndex
+ */
+ public IOpenBitSet getDuplicatedAclTxInIndex()
+ {
+ return duplicatedAclTxInIndex;
+ }
+
+ /**
+ * @return the inIndexButNotInDb
+ */
+ public IOpenBitSet getTxInIndexButNotInDb()
+ {
+ return txInIndexButNotInDb;
+ }
+
+ /**
+ * @return the inIndexButNotInDb
+ */
+ public IOpenBitSet getAclTxInIndexButNotInDb()
+ {
+ return aclTxInIndexButNotInDb;
+ }
+
+ /**
+ * @return the dbTransactionCount
+ */
+ public long getDbTransactionCount()
+ {
+ return dbTransactionCount;
+ }
+
+ /**
+ * @param dbTransactionCount
+ * the dbTransactionCount to set
+ */
+ public void setDbTransactionCount(long dbTransactionCount)
+ {
+ this.dbTransactionCount = dbTransactionCount;
+ }
+
+ public void setMissingTxFromIndex(long txid)
+ {
+ missingTxFromIndex.set(txid);
+ }
+
+ public void setMissingAclTxFromIndex(long txid)
+ {
+ missingAclTxFromIndex.set(txid);
+ }
+
+ public void setDuplicatedTxInIndex(long txid)
+ {
+ duplicatedTxInIndex.set(txid);
+ }
+
+ public void setDuplicatedAclTxInIndex(long txid)
+ {
+ duplicatedAclTxInIndex.set(txid);
+ }
+
+ public void setTxInIndexButNotInDb(long txid)
+ {
+ txInIndexButNotInDb.set(txid);
+ }
+
+ public void setAclTxInIndexButNotInDb(long txid)
+ {
+ aclTxInIndexButNotInDb.set(txid);
+ }
+
+ /**
+ * @param lastIndexCommitTime
+ * the lastIndexCommitTime to set
+ */
+ public void setLastIndexedCommitTime(long lastIndexedCommitTime)
+ {
+ this.lastIndexedCommitTime = lastIndexedCommitTime;
+ }
+
+ /**
+ * @return the lastIndexedIdBeforeHoles
+ */
+ public long getLastIndexedIdBeforeHoles()
+ {
+ return lastIndexedIdBeforeHoles;
+ }
+
+ /**
+ * @param lastIndexedIdBeforeHoles
+ * the lastIndexedIdBeforeHoles to set
+ */
+ public void setLastIndexedIdBeforeHoles(long lastIndexedIdBeforeHoles)
+ {
+ this.lastIndexedIdBeforeHoles = lastIndexedIdBeforeHoles;
+ }
+
+ /**
+ * @param cardinality
+ */
+ public void setDbAclTransactionCount(long dbAclTransactionCount)
+ {
+ this.dbAclTransactionCount = dbAclTransactionCount;
+ }
+
+ /**
+ * @return the dbAclTransactionCount
+ */
+ public long getDbAclTransactionCount()
+ {
+ return dbAclTransactionCount;
+ }
+
+ /**
+ * @return the uniqueTransactionDocsInIndex
+ */
+ public long getUniqueTransactionDocsInIndex()
+ {
+ return uniqueTransactionDocsInIndex;
+ }
+
+ /**
+ * @param uniqueTransactionDocsInIndex the uniqueTransactionDocsInIndex to set
+ */
+ public void setUniqueTransactionDocsInIndex(long uniqueTransactionDocsInIndex)
+ {
+ this.uniqueTransactionDocsInIndex = uniqueTransactionDocsInIndex;
+ }
+
+ /**
+ * @return the uniqueAclTransactionDocsInIndex
+ */
+ public long getUniqueAclTransactionDocsInIndex()
+ {
+ return uniqueAclTransactionDocsInIndex;
+ }
+
+ /**
+ * @param uniqueAclTransactionDocsInIndex the uniqueAclTransactionDocsInIndex to set
+ */
+ public void setUniqueAclTransactionDocsInIndex(long uniqueAclTransactionDocsInIndex)
+ {
+ this.uniqueAclTransactionDocsInIndex = uniqueAclTransactionDocsInIndex;
+ }
+
+ /**
+ * @return the lastIndexedCommitTime
+ */
+ public long getLastIndexedCommitTime()
+ {
+ return lastIndexedCommitTime;
+ }
+
+ /**
+ * @param unindexedCount
+ */
+ public void setUnindexedDocCountInIndex(long unindexedDocCountInIndex)
+ {
+ this.unindexedDocCountInIndex = unindexedDocCountInIndex;
+ }
+
+ /**
+ * @param txid
+ */
+ public void setDuplicatedUnindexedInIndex(long txid)
+ {
+ duplicatedUnindexedInIndex.set(txid);
+
+ }
+
+ /**
+ * @param errorCount
+ */
+ public void setErrorDocCountInIndex(long errorDocCountInIndex)
+ {
+ this.errorDocCountInIndex = errorDocCountInIndex;
+ }
+
+ /**
+ * @param txid
+ */
+ public void setDuplicatedErrorInIndex(long txid)
+ {
+ duplicatedErrorInIndex.set(txid);
+
+ }
+
+ /**
+ * @return the duplicatedErrorInIndex
+ */
+ public IOpenBitSet getDuplicatedErrorInIndex()
+ {
+ return duplicatedErrorInIndex;
+ }
+
+ /**
+ * @return the duplicatedUnindexedInIndex
+ */
+ public IOpenBitSet getDuplicatedUnindexedInIndex()
+ {
+ return duplicatedUnindexedInIndex;
+ }
+
+ /**
+ * @return the errorDocCountInIndex
+ */
+ public long getErrorDocCountInIndex()
+ {
+ return errorDocCountInIndex;
+ }
+
+ /**
+ * @return the unindexedDocCountInIndex
+ */
+ public long getUnindexedDocCountInIndex()
+ {
+ return unindexedDocCountInIndex;
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/search-services/alfresco-solrclient-lib/source/java/org/alfresco/solr/tracker/Tracker.java b/search-services/alfresco-solrclient-lib/source/java/org/alfresco/solr/tracker/Tracker.java
new file mode 100644
index 000000000..aa485d689
--- /dev/null
+++ b/search-services/alfresco-solrclient-lib/source/java/org/alfresco/solr/tracker/Tracker.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2014 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco 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 Alfresco. If not, see .
+ */
+
+package org.alfresco.solr.tracker;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.alfresco.httpclient.AuthenticationException;
+import org.alfresco.service.namespace.QName;
+import org.alfresco.solr.AclReport;
+import org.alfresco.solr.NodeReport;
+import org.alfresco.solr.client.Node;
+import org.alfresco.solr.client.NodeMetaData;
+import org.alfresco.solr.client.NodeMetaDataParameters;
+import org.alfresco.solr.client.SOLRAPIClient.GetTextContentResponse;
+import org.json.JSONException;
+
+public interface Tracker
+{
+
+ int getMaxLiveSearchers();
+
+ void updateIndex();
+
+ void indexAclChangeSets() throws AuthenticationException, IOException, JSONException;
+
+ void indexAcls() throws AuthenticationException, IOException, JSONException;
+
+ void reindexAclChangeSets() throws AuthenticationException, IOException, JSONException;
+
+ void reindexAcls() throws AuthenticationException, IOException, JSONException;
+
+ void purgeAclChangeSets() throws AuthenticationException, IOException, JSONException;
+
+ void purgeAcls() throws AuthenticationException, IOException, JSONException;
+
+ void addTransactionToReindex(Long transactionToReindex);
+
+ void addTransactionToIndex(Long transactionToIndex);
+
+ void addTransactionToPurge(Long transactionToPurge);
+
+ void addNodeToReindex(Long nodeToReindex);
+
+ void addNodeToIndex(Long nodeToIndex);
+
+ void addNodeToPurge(Long nodeToPurge);
+
+ void addAclChangeSetToReindex(Long aclChangeSetToReindex);
+
+ void addAclChangeSetToIndex(Long aclChangeSetToIndex);
+
+ void addAclChangeSetToPurge(Long aclChangeSetToPurge);
+
+ void addAclToReindex(Long aclToReindex);
+
+ void addAclToIndex(Long aclToIndex);
+
+ void addAclToPurge(Long aclToPurge);
+
+ void trackRepository() throws IOException, AuthenticationException, JSONException;
+
+ IndexHealthReport checkIndex(Long fromTx, Long toTx, Long fromAclTx, Long toAclTx, Long fromTime,
+ Long toTime) throws AuthenticationException, IOException, JSONException;
+
+ NodeReport checkNode(Node node);
+
+ NodeReport checkNode(Long dbid);
+
+ List getFullNodesForDbTransaction(Long txid);
+
+ List getAclsForDbAclTransaction(Long acltxid);
+
+ AclReport checkAcl(Long aclid);
+
+ void close();
+
+ void trackModels(boolean onlyFirstTime) throws AuthenticationException, IOException, JSONException;
+
+ void ensureFirstModelSync();
+
+ void setShutdown(boolean shutdown);
+
+ List getNodesMetaData(NodeMetaDataParameters params, int maxResults)
+ throws AuthenticationException, IOException, JSONException;
+
+ GetTextContentResponse getTextContent(Long nodeId, QName propertyQName, Long modifiedSince)
+ throws AuthenticationException, IOException;
+
+ boolean canAddContentPropertyToDoc();
+
+ TrackerStats getTrackerStats();
+
+ String getAlfrescoVersion();
+
+}
\ No newline at end of file
diff --git a/search-services/alfresco-solrclient-lib/source/java/org/alfresco/solr/tracker/TrackerStats.java b/search-services/alfresco-solrclient-lib/source/java/org/alfresco/solr/tracker/TrackerStats.java
new file mode 100644
index 000000000..6fa12161d
--- /dev/null
+++ b/search-services/alfresco-solrclient-lib/source/java/org/alfresco/solr/tracker/TrackerStats.java
@@ -0,0 +1,857 @@
+/*
+ * Copyright (C) 2005-2014 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco 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 Alfresco. If not, see .
+ */
+package org.alfresco.solr.tracker;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.alfresco.solr.InformationServer;
+import org.alfresco.solr.adapters.ISimpleOrderedMap;
+import org.alfresco.util.Pair;
+
+/**
+ * @author Andy
+ */
+public class TrackerStats
+{
+ public static final int TIME_SCALE = 1000000;
+
+ ConcurrentHashMap modelTimes = new ConcurrentHashMap();
+
+ ConcurrentHashMap aclTimes = new ConcurrentHashMap();
+
+ ConcurrentHashMap changeSetAcls = new ConcurrentHashMap();
+
+ ConcurrentHashMap txDocs = new ConcurrentHashMap();
+
+ ConcurrentHashMap docTransformationTimes = new ConcurrentHashMap();
+
+ ConcurrentHashMap nodeTimes = new ConcurrentHashMap();
+
+ private InformationServer infoSrv;
+
+ public TrackerStats(InformationServer server)
+ {
+ infoSrv = server;
+ }
+
+ /**
+ * @return the modelTimes
+ */
+ public SimpleStats getModelTimes()
+ {
+ return aggregateResults(modelTimes);
+ }
+
+ /**
+ * @param modelTimes2
+ * @return
+ */
+ private SimpleStats aggregateResults(ConcurrentHashMap all)
+ {
+ SimpleStats answer = null;
+
+ for (String key : all.keySet())
+ {
+ IncrementalStats next = all.get(key);
+ IncrementalStats stats = next.copy();
+ if (answer == null)
+ {
+ answer = new SimpleStats(stats.scale, this.infoSrv);
+ answer .start = stats.start;
+ answer.moments[0] = stats.moments[0];
+ answer.moments[1] = stats.moments[1];
+ answer.moments[2] = stats.moments[2];
+ answer.max = stats.max;
+ answer.min = stats.min;
+ answer.copies.put(key, stats);
+ }
+ else
+ {
+ SimpleStats newAnswer = new SimpleStats(answer.scale, this.infoSrv);
+
+ newAnswer.moments[0] = answer.moments[0] + stats.moments[0];
+
+ newAnswer.moments[1] = answer.moments[1] * answer.moments[0] + stats.moments[1] * stats.moments[0];
+ newAnswer.moments[1] /= answer.moments[0] + stats.moments[0];
+
+ newAnswer.moments[2] = answer.moments[2] * answer.moments[0];
+ newAnswer.moments[2] += (answer.moments[1] - newAnswer.moments[1]) * (answer.moments[1] - newAnswer.moments[1]) * answer.moments[0];
+ newAnswer.moments[2] += stats.moments[2] * stats.moments[0];
+ newAnswer.moments[2] += (stats.moments[1] - newAnswer.moments[1]) * (stats.moments[1] - newAnswer.moments[1]) * stats.moments[0];
+ newAnswer.moments[2] /= answer.moments[0] + stats.moments[0];
+
+ newAnswer.min = (stats.min < answer.min) ? stats.min : answer.min;
+ newAnswer.max = (stats.max > answer.max) ? stats.max : answer.max;
+
+ newAnswer.start = (stats.start.compareTo(answer.start) < 1) ? stats.start : answer.start;
+
+ newAnswer.copies.putAll(answer.copies);
+ newAnswer.copies.put(key, stats);
+
+ answer = newAnswer;
+ }
+
+ }
+
+ if (answer == null)
+ {
+ answer = new SimpleStats(1, this.infoSrv);
+ }
+
+ return answer;
+ }
+
+ /**
+ * @return the aclTxTimes
+ */
+ public SimpleStats getAclTimes()
+ {
+ return aggregateResults(aclTimes);
+ }
+
+ public SimpleStats getChangeSetAcls()
+ {
+ return aggregateResults(changeSetAcls);
+ }
+
+ public SimpleStats getNodeTimes()
+ {
+ return aggregateResults(nodeTimes);
+ }
+
+ /**
+ * @return the txDocs
+ */
+ public SimpleStats getTxDocs()
+ {
+ return aggregateResults(txDocs);
+ }
+
+ /**
+ * @return the docTransformationTimes
+ */
+ public SimpleStats getDocTransformationTimes()
+ {
+ return aggregateResults(docTransformationTimes);
+ }
+
+ public double getMeanModelSyncTime()
+ {
+ return aggregateResults(modelTimes).getMean();
+ }
+
+ public double getMeanNodeIndexTime()
+ {
+ return aggregateResults(nodeTimes).getMean();
+ }
+
+ public double getNodeIndexingThreadCount()
+ {
+ return nodeTimes.size();
+ }
+
+ public double getMeanAclIndexTime()
+ {
+ return aggregateResults(nodeTimes).getMean();
+ }
+
+ public double getMeanDocsPerTx()
+ {
+ return aggregateResults(txDocs).getMean();
+ }
+
+ public double getMeanAclsPerChangeSet()
+ {
+ return aggregateResults(changeSetAcls).getMean();
+ }
+
+ public static class SimpleStats
+ {
+ HashMap copies = new HashMap();
+ private InformationServer server;
+ int scale;
+
+ SimpleStats(int scale, InformationServer server)
+ {
+ this.scale = scale;
+ this.server = server;
+ }
+
+ double[] moments = new double[3];
+
+ double min = 0D;
+
+ double max = 0D;
+
+ Date start = null;
+
+ synchronized long getN()
+ {
+ return (long) moments[0];
+ }
+
+ synchronized double getMin()
+ {
+ return min;
+ }
+
+ synchronized double getMax()
+ {
+ return max;
+ }
+
+ synchronized double getMean()
+ {
+ return moments[1];
+ }
+
+ synchronized double getVarience()
+ {
+ if (moments[0] > 1)
+ {
+ return moments[2] * moments[0] / (moments[0] - 1);
+ }
+ else
+ {
+ return Double.NaN;
+ }
+ }
+
+ synchronized double getStandardDeviation()
+ {
+ return Math.sqrt(getVarience());
+ }
+
+ public synchronized ISimpleOrderedMap