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 getNamedList(boolean incdludeDetail, boolean includeHist, boolean includeValues) + { + ISimpleOrderedMap map = this.server.getSimpleOrderedMapInstance(); + map.add("Start", start); + map.add("N", getN()); + map.add("Min", getMin()); + map.add("Max", getMax()); + map.add("Mean", getMean()); + map.add("Varience", getVarience()); + map.add("StdDev", getStandardDeviation()); + if (incdludeDetail) + { + for (String key : copies.keySet()) + { + IncrementalStats value = copies.get(key); + map.add(key, value.getNamedList(includeHist, includeValues)); + } + } + + return map; + } + + /* + * (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() + { + return "SimpleStats [" + + "\n getN()=" + getN() + ",\n getMin()=" + getMin() + ",\n getMax()=" + getMax() + ",\n getMean()=" + + getMean() + ",\n getVarience()=" + getVarience() + ",\n getStandardDeviation()=" + getStandardDeviation() + ",\n copies=" + + copies + ",\n]"; + } + + } + + static class Bucket + { + IncrementalStats incrementalStats; + + double leftBoundary; + + double rightBoundary; + + double countLeft; + + double countRight; + + Bucket(IncrementalStats incrementalStats, double leftBoundary, double rightBoundary) + { + this(incrementalStats, leftBoundary, rightBoundary, 0D, 0D); + } + + Bucket(IncrementalStats incrementalStats, double leftBoundary, double rightBoundary, double countLeft, double countRight) + { + this.incrementalStats = incrementalStats; + this.leftBoundary = leftBoundary; + this.rightBoundary = rightBoundary; + this.countLeft = countLeft; + this.countRight = countRight; + } + + public void add(double x) + { + if ((x - leftBoundary) < (rightBoundary - x)) + { + countLeft++; + } + else + { + countRight++; + } + } + + public double mergeError(Bucket o) + { + double f_m = (this.countLeft + this.countRight + o.countLeft + o.countRight) / 4.0d; + double t1 = this.countLeft - f_m; + double t2 = this.countRight - f_m; + double o1 = o.countLeft - f_m; + double o2 = o.countRight - f_m; + + return (t1 * t1) + (t2 * t2) + (o1 * o1) + (o2 * o2); + } + + public double error() + { + double f_m = (this.countLeft + this.countRight) / 2.0d; + double t1 = this.countLeft - f_m; + double t2 = this.countRight - f_m; + return (t1 * t1) + (t2 * t2); + + } + + /* + * (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() + { + double mark = (leftBoundary + rightBoundary) / 2.0D; + double width = rightBoundary - leftBoundary; + return "Bucket [(" + + leftBoundary + " TO " + mark + " = " + countLeft / incrementalStats.getN() / width + ") : (" + mark + " TO " + rightBoundary + " = " + countRight + / incrementalStats.getN() / width + "]"; + } + + } + + static class IncrementalStats + { + Date start = new Date(); + + int scale; + + int buckets; + + double[] moments = new double[5]; + + double min = 0D; + + double max = 0D; + + List values; + + List hist; + + InformationServer server; + + IncrementalStats(int scale, int buckets, InformationServer infoSrv) + { + this.scale = scale; + this.buckets = buckets; + values = new ArrayList(buckets); + hist = new ArrayList(buckets + 1); + this.server = infoSrv; + } + + /** + * @return + */ + public ISimpleOrderedMap getNamedList(boolean includeHist, boolean includeValues) + { + ISimpleOrderedMap map = this.server.getSimpleOrderedMapInstance(); + map.add("Start", start); + map.add("N", getN()); + map.add("Min", getMin()); + map.add("Max", getMax()); + map.add("Mean", getMean()); + map.add("Varience", getVarience()); + map.add("StdDev", getStandardDeviation()); + map.add("Skew", getSkew()); + map.add("Kurtosis", getKurtosis()); + + if (includeHist) + { + int i = 0; + ISimpleOrderedMap buckets = this.server.getSimpleOrderedMapInstance(); + for (Bucket b : hist) + { + double mark = (b.leftBoundary + b.rightBoundary) / 2.0D; + double width = b.rightBoundary - b.leftBoundary; + + // SimpleOrderedMap bucket = new SimpleOrderedMap(); + // bucket.add("Lower", b.leftBoundary); + // bucket.add("Upper", mark); + // bucket.add("ProbabilityDensity", b.countLeft/b.incrementalStats.getN()/width); + buckets.add("" + i++, (b.leftBoundary + mark) / 2.0D + "," + b.countLeft / b.incrementalStats.getN() / width); + + // bucket = new SimpleOrderedMap(); + // bucket.add("Lower", mark); + // bucket.add("Upper", b.rightBoundary); + // bucket.add("ProbabilityDensity", b.countRight/b.incrementalStats.getN()/width); + buckets.add("" + i++, (mark + b.rightBoundary) / 2.0D + "," + b.countRight / b.incrementalStats.getN() / width); + } + map.add("Buckets", buckets); + } + + if (includeValues) + { + int i = 0; + ISimpleOrderedMap valuesMap = this.server.getSimpleOrderedMapInstance(); + for (Double value : values) + { + valuesMap.add("" + i++, value); + } + map.add("Values", valuesMap); + } + + return map; + } + + synchronized void reset() + { + moments = new double[5]; + + min = 0D; + + max = 0D; + + values = new ArrayList(buckets); + + hist = new ArrayList(buckets + 1); + + start = new Date(); + } + + synchronized void add(double xUnscaled) + { + double x = xUnscaled / scale; + if ((moments[0] == 0) || (x > max)) + { + max = x; + } + if ((moments[0] == 0L) || (x < min)) + { + min = x; + } + double n = moments[0]; + double nPlus1 = n + 1; + double n2 = n * n; + double d = (moments[1] - x) / nPlus1; + double d2 = d * d; + double d3 = d2 * d; + double n_nPlus1 = n / nPlus1; + + moments[4] += 4 * d * moments[3] + 6 * d2 * moments[2] + (1 + n * n2) * d2 * d2; + moments[4] *= n_nPlus1; + + moments[3] += 3 * d * moments[2] + (1 - n2) * d3; + moments[3] *= n_nPlus1; + + moments[2] += (1 + n) * d2; + moments[2] *= n_nPlus1; + + moments[1] -= d; + + moments[0] = nPlus1; + + if (buckets > 1) + { + if (moments[0] < buckets) + { + values.add(Double.valueOf(x)); + } + else if (moments[0] == buckets) + { + values.add(Double.valueOf(x)); + + // generate initial bucket list + Collections.sort(values); + FOUND: for (int i = 0; i < values.size(); i++) + { + for (Bucket b : hist) + { + if ((b.leftBoundary <= values.get(i)) && (values.get(i) < b.rightBoundary)) + { + b.add(values.get(i)); + continue FOUND; + } + + } + if (i < values.size() - 1) + { + double start = values.get(i); + double end = start + 1.0D; + + END: for (int j = i + 1; j < values.size(); j++) + { + if (values.get(j) > start) + { + end = values.get(j); + break END; + } + } + + Bucket b = new Bucket(this, start, end); + hist.add(b); + } + else + { + double first = values.get(0); + double last = values.get(values.size() - 1); + double width = 1.0D; + if (values.size() > 1) + { + width = (last - first) / (values.size() - 1); + } + Bucket b = new Bucket(this, last, last + width); + hist.add(b); + } + } + } + else + { + values.set((int) moments[0] % buckets, x); + if (x < hist.get(0).leftBoundary) + { + double delta = (hist.get(0).leftBoundary - x) / 3.0; + Bucket b = new Bucket(this, x - delta, hist.get(0).leftBoundary); + hist.add(0, b); + b.add(x); + Pair bestToMerge = findBestToMerge(); + if (hist.size() > buckets) + { + merge(bestToMerge.getFirst()); + } + } + else if (x > hist.get(hist.size() - 1).rightBoundary) + { + double delta = (x - hist.get(hist.size() - 1).rightBoundary) / 3.0; + Bucket b = new Bucket(this, hist.get(hist.size() - 1).rightBoundary, x + delta); + hist.add(b); + b.add(x); + Pair bestToMerge = findBestToMerge(); + if (hist.size() > buckets) + { + merge(bestToMerge.getFirst()); + } + } + else + { + // find existing + for (Bucket b : hist) + { + if ((b.leftBoundary <= x) && (x < b.rightBoundary)) + { + b.add(x); + break; + } + + } + Pair bestToMerge = findBestToMerge(); + Pair bestToSplit = findBestToSplit(); + if (bestToMerge.getSecond() - bestToSplit.getSecond() < 0) + { + merge(bestToMerge.getFirst()); + split(bestToMerge.getFirst() < bestToSplit.getFirst() ? bestToSplit.getFirst() - 1 : bestToSplit.getFirst()); + } + } + } + } + } + + void merge(int position) + { + Bucket lower = hist.get(position); + Bucket upper = hist.get(position + 1); + Bucket merged = new Bucket(this, lower.leftBoundary, upper.rightBoundary, lower.countLeft + lower.countRight, upper.countLeft + upper.countRight); + hist.remove(position); + hist.set(position, merged); + + } + + void split(int position) + { + Bucket toSplit = hist.get(position); + double mark = (toSplit.leftBoundary + toSplit.rightBoundary) / 2.0D; + Bucket lower = new Bucket(this, toSplit.leftBoundary, mark, toSplit.countLeft / 2.0D, toSplit.countLeft / 2.0D); + Bucket upper = new Bucket(this, mark, toSplit.rightBoundary, toSplit.countRight / 2.0D, toSplit.countRight / 2.0D); + hist.set(position, upper); + hist.add(position, lower); + } + + Pair findBestToMerge() + { + double minMergeError = Double.MAX_VALUE; + int bucket = 0; + for (int i = 0; i < hist.size() - 1; i++) + { + double mergeError = hist.get(i).mergeError(hist.get(i + 1)); + if (mergeError < minMergeError) + { + minMergeError = mergeError; + bucket = i; + } + } + return new Pair(bucket, minMergeError); + } + + Pair findBestToSplit() + { + double maxError = Double.MIN_VALUE; + int bucket = 0; + for (int i = 0; i < hist.size(); i++) + { + double error = hist.get(i).error(); + if (error > maxError) + { + maxError = error; + bucket = i; + } + } + return new Pair(bucket, maxError); + } + + 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()); + } + + synchronized double getSkew() + { + if (moments[0] > 2) + { + double v = getVarience(); + return moments[3] * moments[0] * moments[0] / (Math.sqrt(v) * v * (moments[0] - 1) * (moments[0] - 2)); + } + else + { + return Double.NaN; + } + } + + synchronized double getKurtosis() + { + if (moments[0] > 3) + { + double div = (moments[0] - 2) * (moments[0] - 3); + double nMinus1 = moments[0] - 1; + double v = getVarience(); + double z = ((moments[4] * moments[0] * moments[0] * (moments[0] + 1)) / (v * v * nMinus1)); + z -= 3 * nMinus1 * nMinus1; + z /= div; + return z; + } + else + { + return Double.NaN; + } + } + + synchronized IncrementalStats copy() + { + IncrementalStats copy = new IncrementalStats(this.scale, this.buckets, this.server); + copy.start = this.start; + copy.max = this.max; + copy.min = this.min; + copy.moments[0] = this.moments[0]; + copy.moments[1] = this.moments[1]; + copy.moments[2] = this.moments[2]; + copy.moments[3] = this.moments[3]; + copy.moments[4] = this.moments[4]; + for (Double x : this.values) + { + copy.values.add(x); + } + for (Bucket b : this.hist) + { + copy.hist.add(new Bucket(copy, b.leftBoundary, b.rightBoundary, b.countLeft, b.countRight)); + } + return copy; + } + + /* + * (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() + { + return "IncrementalStats [getN()=" + + getN() + ", getMin()=" + getMin() + ", getMax()=" + getMax() + ", getMean()=" + getMean() + ", getVarience()=" + getVarience() + ", getStandardDeviation()=" + + getStandardDeviation() + ", getSkew()=" + getSkew() + ", getKurtosis()=" + getKurtosis() + ", values=" + values + ", hist=" + hist + "]"; + } + + } + + /** + * @param l + */ + public void addModelTime(long time) + { + IncrementalStats stats = modelTimes.get(Thread.currentThread().getName()); + if (stats == null) + { + stats = new IncrementalStats(TIME_SCALE, 50, this.infoSrv); + modelTimes.put(Thread.currentThread().getName(), stats); + } + stats.add(time); + } + + /** + * @param l + */ + public void addAclTime(long time) + { + IncrementalStats stats = aclTimes.get(Thread.currentThread().getName()); + if (stats == null) + { + stats = new IncrementalStats(TIME_SCALE, 50, this.infoSrv); + aclTimes.put(Thread.currentThread().getName(), stats); + } + stats.add(time); + } + + /** + * @param l + */ + public void addNodeTime(long time) + { + IncrementalStats stats = nodeTimes.get(Thread.currentThread().getName()); + if (stats == null) + { + stats = new IncrementalStats(TIME_SCALE, 50, this.infoSrv); + nodeTimes.put(Thread.currentThread().getName(), stats); + } + stats.add(time); + } + + /** + * @param size + */ + public void addTxDocs(int size) + { + IncrementalStats stats = txDocs.get(Thread.currentThread().getName()); + if (stats == null) + { + stats = new IncrementalStats(1, 50, this.infoSrv); + txDocs.put(Thread.currentThread().getName(), stats); + } + stats.add(size); + } + + /** + * @param size + */ + public void addChangeSetAcls(int size) + { + IncrementalStats stats = changeSetAcls.get(Thread.currentThread().getName()); + if (stats == null) + { + stats = new IncrementalStats(1, 50, this.infoSrv); + changeSetAcls.put(Thread.currentThread().getName(), stats); + } + stats.add(size); + } + + /** + * @param l + */ + public void addDocTransformationTime(long time) + { + IncrementalStats stats = docTransformationTimes.get(Thread.currentThread().getName()); + if (stats == null) + { + stats = new IncrementalStats(TIME_SCALE, 50, this.infoSrv); + docTransformationTimes.put(Thread.currentThread().getName(), stats); + } + stats.add(time); + } + + /* + * (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() + { + return "TrackerStats [modelTimes=" + + modelTimes + ", aclTimes=" + aclTimes + ", changeSetAcls=" + changeSetAcls + ", txDocs=" + txDocs + ", docTransformationTimes=" + docTransformationTimes + + ", nodeTimes=" + nodeTimes + "]"; + } + + /** + * + */ + public void reset() + { + modelTimes.clear(); + aclTimes.clear(); + changeSetAcls.clear(); + txDocs.clear(); + docTransformationTimes.clear(); + nodeTimes.clear(); + } + +}