mirror of
https://github.com/Alfresco/SearchServices.git
synced 2025-09-17 14:21:20 +00:00
Merge branch 'master' of git.alfresco.com:search_discovery/insightengine into feature/contentStoreReplication
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,484 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
|
||||||
*
|
|
||||||
* This file is part of the Alfresco software.
|
|
||||||
* If the software was purchased under a paid Alfresco license, the terms of
|
|
||||||
* the paid license agreement will prevail. Otherwise, the software is
|
|
||||||
* provided under the following open source license terms:
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package org.alfresco.solr;
|
|
||||||
|
|
||||||
import org.alfresco.httpclient.AuthenticationException;
|
|
||||||
import org.alfresco.service.cmr.repository.datatype.Duration;
|
|
||||||
import org.alfresco.solr.client.Node;
|
|
||||||
import org.alfresco.solr.tracker.*;
|
|
||||||
import org.alfresco.util.CachingDateFormat;
|
|
||||||
import org.apache.commons.codec.EncoderException;
|
|
||||||
import org.apache.solr.common.util.NamedList;
|
|
||||||
import org.apache.solr.common.util.SimpleOrderedMap;
|
|
||||||
import org.json.JSONException;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Methods taken from AlfrescoCoreAdminHandler that deal with building reports
|
|
||||||
*/
|
|
||||||
public class HandlerReportBuilder {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds AclReport
|
|
||||||
* @param tracker
|
|
||||||
* @param aclid
|
|
||||||
* @return
|
|
||||||
* @throws IOException
|
|
||||||
* @throws JSONException
|
|
||||||
*/
|
|
||||||
public static NamedList<Object> buildAclReport(AclTracker tracker, Long aclid) throws IOException, JSONException
|
|
||||||
{
|
|
||||||
AclReport aclReport = tracker.checkAcl(aclid);
|
|
||||||
|
|
||||||
NamedList<Object> nr = new SimpleOrderedMap<Object>();
|
|
||||||
nr.add("Acl Id", aclReport.getAclId());
|
|
||||||
nr.add("Acl doc in index", aclReport.getIndexAclDoc());
|
|
||||||
if (aclReport.getIndexAclDoc() != null)
|
|
||||||
{
|
|
||||||
nr.add("Acl tx in Index", aclReport.getIndexAclTx());
|
|
||||||
}
|
|
||||||
|
|
||||||
return nr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds TxReport
|
|
||||||
* @param trackerRegistry
|
|
||||||
* @param srv
|
|
||||||
* @param coreName
|
|
||||||
* @param tracker
|
|
||||||
* @param txid
|
|
||||||
* @return
|
|
||||||
* @throws AuthenticationException
|
|
||||||
* @throws IOException
|
|
||||||
* @throws JSONException
|
|
||||||
* @throws EncoderException
|
|
||||||
*/
|
|
||||||
public static NamedList<Object> buildTxReport(TrackerRegistry trackerRegistry, InformationServer srv, String coreName, MetadataTracker tracker, Long txid)
|
|
||||||
throws AuthenticationException, IOException, JSONException, EncoderException
|
|
||||||
{
|
|
||||||
NamedList<Object> nr = new SimpleOrderedMap<Object>();
|
|
||||||
nr.add("TXID", txid);
|
|
||||||
nr.add("transaction", buildTrackerReport(trackerRegistry, srv, coreName, txid, txid, 0l, 0l, null, null));
|
|
||||||
NamedList<Object> nodes = new SimpleOrderedMap<Object>();
|
|
||||||
// add node reports ....
|
|
||||||
List<Node> dbNodes = tracker.getFullNodesForDbTransaction(txid);
|
|
||||||
for (Node node : dbNodes)
|
|
||||||
{
|
|
||||||
nodes.add("DBID " + node.getId(), buildNodeReport(tracker, node));
|
|
||||||
}
|
|
||||||
|
|
||||||
nr.add("txDbNodeCount", dbNodes.size());
|
|
||||||
nr.add("nodes", nodes);
|
|
||||||
return nr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds AclTxReport
|
|
||||||
* @param trackerRegistry
|
|
||||||
* @param srv
|
|
||||||
* @param coreName
|
|
||||||
* @param tracker
|
|
||||||
* @param acltxid
|
|
||||||
* @return
|
|
||||||
* @throws AuthenticationException
|
|
||||||
* @throws IOException
|
|
||||||
* @throws JSONException
|
|
||||||
* @throws EncoderException
|
|
||||||
*/
|
|
||||||
public static NamedList<Object> buildAclTxReport(TrackerRegistry trackerRegistry, InformationServer srv, String coreName, AclTracker tracker, Long acltxid)
|
|
||||||
throws AuthenticationException, IOException, JSONException, EncoderException
|
|
||||||
{
|
|
||||||
NamedList<Object> nr = new SimpleOrderedMap<Object>();
|
|
||||||
nr.add("TXID", acltxid);
|
|
||||||
nr.add("transaction", buildTrackerReport(trackerRegistry, srv, coreName, 0l, 0l, acltxid, acltxid, null, null));
|
|
||||||
NamedList<Object> nodes = new SimpleOrderedMap<Object>();
|
|
||||||
// add node reports ....
|
|
||||||
List<Long> dbAclIds = tracker.getAclsForDbAclTransaction(acltxid);
|
|
||||||
for (Long aclid : dbAclIds)
|
|
||||||
{
|
|
||||||
nodes.add("ACLID " + aclid, buildAclReport(tracker, aclid));
|
|
||||||
}
|
|
||||||
nr.add("aclTxDbAclCount", dbAclIds.size());
|
|
||||||
nr.add("nodes", nodes);
|
|
||||||
return nr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds Node report
|
|
||||||
* @param tracker
|
|
||||||
* @param node
|
|
||||||
* @return
|
|
||||||
* @throws IOException
|
|
||||||
* @throws JSONException
|
|
||||||
*/
|
|
||||||
public static NamedList<Object> buildNodeReport(MetadataTracker tracker, Node node) throws IOException, JSONException
|
|
||||||
{
|
|
||||||
NodeReport nodeReport = tracker.checkNode(node);
|
|
||||||
|
|
||||||
NamedList<Object> nr = new SimpleOrderedMap<Object>();
|
|
||||||
nr.add("Node DBID", nodeReport.getDbid());
|
|
||||||
nr.add("DB TX", nodeReport.getDbTx());
|
|
||||||
nr.add("DB TX status", nodeReport.getDbNodeStatus().toString());
|
|
||||||
if (nodeReport.getIndexLeafDoc() != null)
|
|
||||||
{
|
|
||||||
nr.add("Leaf tx in Index", nodeReport.getIndexLeafTx());
|
|
||||||
}
|
|
||||||
if (nodeReport.getIndexAuxDoc() != null)
|
|
||||||
{
|
|
||||||
nr.add("Aux tx in Index", nodeReport.getIndexAuxTx());
|
|
||||||
}
|
|
||||||
nr.add("Indexed Node Doc Count", nodeReport.getIndexedNodeDocCount());
|
|
||||||
return nr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds Node Report
|
|
||||||
* @param tracker
|
|
||||||
* @param dbid
|
|
||||||
* @return
|
|
||||||
* @throws IOException
|
|
||||||
* @throws JSONException
|
|
||||||
*/
|
|
||||||
public static NamedList<Object> buildNodeReport(MetadataTracker tracker, Long dbid) throws IOException, JSONException
|
|
||||||
{
|
|
||||||
NodeReport nodeReport = tracker.checkNode(dbid);
|
|
||||||
|
|
||||||
NamedList<Object> nr = new SimpleOrderedMap<Object>();
|
|
||||||
nr.add("Node DBID", nodeReport.getDbid());
|
|
||||||
nr.add("DB TX", nodeReport.getDbTx());
|
|
||||||
nr.add("DB TX status", nodeReport.getDbNodeStatus().toString());
|
|
||||||
if (nodeReport.getIndexLeafDoc() != null)
|
|
||||||
{
|
|
||||||
nr.add("Leaf tx in Index", nodeReport.getIndexLeafTx());
|
|
||||||
}
|
|
||||||
if (nodeReport.getIndexAuxDoc() != null)
|
|
||||||
{
|
|
||||||
nr.add("Aux tx in Index", nodeReport.getIndexAuxTx());
|
|
||||||
}
|
|
||||||
nr.add("Indexed Node Doc Count", nodeReport.getIndexedNodeDocCount());
|
|
||||||
return nr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds Tracker report
|
|
||||||
* @param trackerRegistry
|
|
||||||
* @param srv
|
|
||||||
* @param coreName
|
|
||||||
* @param fromTx
|
|
||||||
* @param toTx
|
|
||||||
* @param fromAclTx
|
|
||||||
* @param toAclTx
|
|
||||||
* @param fromTime
|
|
||||||
* @param toTime
|
|
||||||
* @return
|
|
||||||
* @throws IOException
|
|
||||||
* @throws JSONException
|
|
||||||
* @throws AuthenticationException
|
|
||||||
* @throws EncoderException
|
|
||||||
*/
|
|
||||||
public static NamedList<Object> buildTrackerReport(TrackerRegistry trackerRegistry, InformationServer srv, String coreName, Long fromTx, Long toTx, Long fromAclTx, Long toAclTx,
|
|
||||||
Long fromTime, Long toTime) throws IOException, JSONException, AuthenticationException, EncoderException
|
|
||||||
{
|
|
||||||
// ACL
|
|
||||||
AclTracker aclTracker = trackerRegistry.getTrackerForCore(coreName, AclTracker.class);
|
|
||||||
IndexHealthReport aclReport = aclTracker.checkIndex(toTx, toAclTx, fromTime, toTime);
|
|
||||||
NamedList<Object> ihr = new SimpleOrderedMap<Object>();
|
|
||||||
ihr.add("Alfresco version", aclTracker.getAlfrescoVersion());
|
|
||||||
ihr.add("DB acl transaction count", aclReport.getDbAclTransactionCount());
|
|
||||||
ihr.add("Count of duplicated acl transactions in the index", aclReport.getDuplicatedAclTxInIndex()
|
|
||||||
.cardinality());
|
|
||||||
if (aclReport.getDuplicatedAclTxInIndex().cardinality() > 0)
|
|
||||||
{
|
|
||||||
ihr.add("First duplicate acl tx", aclReport.getDuplicatedAclTxInIndex().nextSetBit(0L));
|
|
||||||
}
|
|
||||||
ihr.add("Count of acl transactions in the index but not the DB", aclReport.getAclTxInIndexButNotInDb()
|
|
||||||
.cardinality());
|
|
||||||
if (aclReport.getAclTxInIndexButNotInDb().cardinality() > 0)
|
|
||||||
{
|
|
||||||
ihr.add("First acl transaction in the index but not the DB", aclReport.getAclTxInIndexButNotInDb()
|
|
||||||
.nextSetBit(0L));
|
|
||||||
}
|
|
||||||
ihr.add("Count of missing acl transactions from the Index", aclReport.getMissingAclTxFromIndex()
|
|
||||||
.cardinality());
|
|
||||||
if (aclReport.getMissingAclTxFromIndex().cardinality() > 0)
|
|
||||||
{
|
|
||||||
ihr.add("First acl transaction missing from the Index", aclReport.getMissingAclTxFromIndex()
|
|
||||||
.nextSetBit(0L));
|
|
||||||
}
|
|
||||||
ihr.add("Index acl transaction count", aclReport.getAclTransactionDocsInIndex());
|
|
||||||
ihr.add("Index unique acl transaction count", aclReport.getAclTransactionDocsInIndex());
|
|
||||||
TrackerState aclState = aclTracker.getTrackerState();
|
|
||||||
ihr.add("Last indexed change set commit time", aclState.getLastIndexedChangeSetCommitTime());
|
|
||||||
Date lastChangeSetDate = new Date(aclState.getLastIndexedChangeSetCommitTime());
|
|
||||||
ihr.add("Last indexed change set commit date", CachingDateFormat.getDateFormat().format(lastChangeSetDate));
|
|
||||||
ihr.add("Last changeset id before holes", aclState.getLastIndexedChangeSetIdBeforeHoles());
|
|
||||||
|
|
||||||
// Metadata
|
|
||||||
MetadataTracker metadataTracker = trackerRegistry.getTrackerForCore(coreName, MetadataTracker.class);
|
|
||||||
IndexHealthReport metaReport = metadataTracker.checkIndex(toTx, toAclTx, fromTime, toTime);
|
|
||||||
ihr.add("DB transaction count", metaReport.getDbTransactionCount());
|
|
||||||
ihr.add("Count of duplicated transactions in the index", metaReport.getDuplicatedTxInIndex()
|
|
||||||
.cardinality());
|
|
||||||
if (metaReport.getDuplicatedTxInIndex().cardinality() > 0)
|
|
||||||
{
|
|
||||||
ihr.add("First duplicate", metaReport.getDuplicatedTxInIndex().nextSetBit(0L));
|
|
||||||
}
|
|
||||||
ihr.add("Count of transactions in the index but not the DB", metaReport.getTxInIndexButNotInDb()
|
|
||||||
.cardinality());
|
|
||||||
if (metaReport.getTxInIndexButNotInDb().cardinality() > 0)
|
|
||||||
{
|
|
||||||
ihr.add("First transaction in the index but not the DB", metaReport.getTxInIndexButNotInDb()
|
|
||||||
.nextSetBit(0L));
|
|
||||||
}
|
|
||||||
ihr.add("Count of missing transactions from the Index", metaReport.getMissingTxFromIndex().cardinality());
|
|
||||||
if (metaReport.getMissingTxFromIndex().cardinality() > 0)
|
|
||||||
{
|
|
||||||
ihr.add("First transaction missing from the Index", metaReport.getMissingTxFromIndex()
|
|
||||||
.nextSetBit(0L));
|
|
||||||
}
|
|
||||||
ihr.add("Index transaction count", metaReport.getTransactionDocsInIndex());
|
|
||||||
ihr.add("Index unique transaction count", metaReport.getTransactionDocsInIndex());
|
|
||||||
ihr.add("Index node count", metaReport.getLeafDocCountInIndex());
|
|
||||||
ihr.add("Count of duplicate nodes in the index", metaReport.getDuplicatedLeafInIndex().cardinality());
|
|
||||||
if (metaReport.getDuplicatedLeafInIndex().cardinality() > 0)
|
|
||||||
{
|
|
||||||
ihr.add("First duplicate node id in the index", metaReport.getDuplicatedLeafInIndex().nextSetBit(0L));
|
|
||||||
}
|
|
||||||
ihr.add("Index error count", metaReport.getErrorDocCountInIndex());
|
|
||||||
ihr.add("Count of duplicate error docs in the index", metaReport.getDuplicatedErrorInIndex()
|
|
||||||
.cardinality());
|
|
||||||
if (metaReport.getDuplicatedErrorInIndex().cardinality() > 0)
|
|
||||||
{
|
|
||||||
ihr.add("First duplicate error in the index", SolrInformationServer.PREFIX_ERROR
|
|
||||||
+ metaReport.getDuplicatedErrorInIndex().nextSetBit(0L));
|
|
||||||
}
|
|
||||||
ihr.add("Index unindexed count", metaReport.getUnindexedDocCountInIndex());
|
|
||||||
ihr.add("Count of duplicate unindexed docs in the index", metaReport.getDuplicatedUnindexedInIndex()
|
|
||||||
.cardinality());
|
|
||||||
if (metaReport.getDuplicatedUnindexedInIndex().cardinality() > 0)
|
|
||||||
{
|
|
||||||
ihr.add("First duplicate unindexed in the index",
|
|
||||||
metaReport.getDuplicatedUnindexedInIndex().nextSetBit(0L));
|
|
||||||
}
|
|
||||||
TrackerState metaState = metadataTracker.getTrackerState();
|
|
||||||
ihr.add("Last indexed transaction commit time", metaState.getLastIndexedTxCommitTime());
|
|
||||||
Date lastTxDate = new Date(metaState.getLastIndexedTxCommitTime());
|
|
||||||
ihr.add("Last indexed transaction commit date", CachingDateFormat.getDateFormat().format(lastTxDate));
|
|
||||||
ihr.add("Last TX id before holes", metaState.getLastIndexedTxIdBeforeHoles());
|
|
||||||
|
|
||||||
srv.addFTSStatusCounts(ihr);
|
|
||||||
|
|
||||||
return ihr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a core summary
|
|
||||||
* @param cname
|
|
||||||
* @param detail
|
|
||||||
* @param hist
|
|
||||||
* @param values
|
|
||||||
* @param srv
|
|
||||||
* @param report
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public static void addCoreSummary(TrackerRegistry trackerRegistry, String cname, boolean detail, boolean hist, boolean values,
|
|
||||||
InformationServer srv, NamedList<Object> report) throws IOException
|
|
||||||
{
|
|
||||||
NamedList<Object> coreSummary = new SimpleOrderedMap<Object>();
|
|
||||||
coreSummary.addAll((SimpleOrderedMap<Object>) srv.getCoreStats());
|
|
||||||
|
|
||||||
MetadataTracker metaTrkr = trackerRegistry.getTrackerForCore(cname, MetadataTracker.class);
|
|
||||||
TrackerState metadataTrkrState = metaTrkr.getTrackerState();
|
|
||||||
long lastIndexTxCommitTime = metadataTrkrState.getLastIndexedTxCommitTime();
|
|
||||||
|
|
||||||
long lastIndexedTxId = metadataTrkrState.getLastIndexedTxId();
|
|
||||||
long lastTxCommitTimeOnServer = metadataTrkrState.getLastTxCommitTimeOnServer();
|
|
||||||
long lastTxIdOnServer = metadataTrkrState.getLastTxIdOnServer();
|
|
||||||
Date lastIndexTxCommitDate = new Date(lastIndexTxCommitTime);
|
|
||||||
Date lastTxOnServerDate = new Date(lastTxCommitTimeOnServer);
|
|
||||||
long transactionsToDo = lastTxIdOnServer - lastIndexedTxId;
|
|
||||||
if (transactionsToDo < 0)
|
|
||||||
{
|
|
||||||
transactionsToDo = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
AclTracker aclTrkr = trackerRegistry.getTrackerForCore(cname, AclTracker.class);
|
|
||||||
TrackerState aclTrkrState = aclTrkr.getTrackerState();
|
|
||||||
long lastIndexChangeSetCommitTime = aclTrkrState.getLastIndexedChangeSetCommitTime();
|
|
||||||
long lastIndexedChangeSetId = aclTrkrState.getLastIndexedChangeSetId();
|
|
||||||
long lastChangeSetCommitTimeOnServer = aclTrkrState.getLastChangeSetCommitTimeOnServer();
|
|
||||||
long lastChangeSetIdOnServer = aclTrkrState.getLastChangeSetIdOnServer();
|
|
||||||
Date lastIndexChangeSetCommitDate = new Date(lastIndexChangeSetCommitTime);
|
|
||||||
Date lastChangeSetOnServerDate = new Date(lastChangeSetCommitTimeOnServer);
|
|
||||||
long changeSetsToDo = lastChangeSetIdOnServer - lastIndexedChangeSetId;
|
|
||||||
if (changeSetsToDo < 0)
|
|
||||||
{
|
|
||||||
changeSetsToDo = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
long nodesToDo = 0;
|
|
||||||
long remainingTxTimeMillis = 0;
|
|
||||||
if (transactionsToDo > 0)
|
|
||||||
{
|
|
||||||
// We now use the elapsed time as seen by the single thread farming out metadata indexing
|
|
||||||
double meanDocsPerTx = srv.getTrackerStats().getMeanDocsPerTx();
|
|
||||||
double meanNodeElaspedIndexTime = srv.getTrackerStats().getMeanNodeElapsedIndexTime();
|
|
||||||
nodesToDo = (long)(transactionsToDo * meanDocsPerTx);
|
|
||||||
remainingTxTimeMillis = (long) (nodesToDo * meanNodeElaspedIndexTime);
|
|
||||||
}
|
|
||||||
Date now = new Date();
|
|
||||||
Date end = new Date(now.getTime() + remainingTxTimeMillis);
|
|
||||||
Duration remainingTx = new Duration(now, end);
|
|
||||||
|
|
||||||
long remainingChangeSetTimeMillis = 0;
|
|
||||||
if (changeSetsToDo > 0)
|
|
||||||
{
|
|
||||||
// We now use the elapsed time as seen by the single thread farming out alc indexing
|
|
||||||
double meanAclsPerChangeSet = srv.getTrackerStats().getMeanAclsPerChangeSet();
|
|
||||||
double meanAclElapsedIndexTime = srv.getTrackerStats().getMeanAclElapsedIndexTime();
|
|
||||||
remainingChangeSetTimeMillis = (long) (changeSetsToDo * meanAclsPerChangeSet * meanAclElapsedIndexTime);
|
|
||||||
}
|
|
||||||
now = new Date();
|
|
||||||
end = new Date(now.getTime() + remainingChangeSetTimeMillis);
|
|
||||||
Duration remainingChangeSet = new Duration(now, end);
|
|
||||||
|
|
||||||
NamedList<Object> ftsSummary = new SimpleOrderedMap<Object>();
|
|
||||||
long remainingContentTimeMillis = 0;
|
|
||||||
srv.addFTSStatusCounts(ftsSummary);
|
|
||||||
long cleanCount = ((Long)ftsSummary.get("Node count with FTSStatus Clean")).longValue();
|
|
||||||
long dirtyCount = ((Long)ftsSummary.get("Node count with FTSStatus Dirty")).longValue();
|
|
||||||
long newCount = ((Long)ftsSummary.get("Node count with FTSStatus New")).longValue();
|
|
||||||
long nodesInIndex = ((Long)coreSummary.get("Alfresco Nodes in Index"));
|
|
||||||
long contentYetToSee = nodesInIndex > 0 ? nodesToDo * (cleanCount + dirtyCount + newCount)/nodesInIndex : 0;;
|
|
||||||
if (dirtyCount + newCount + contentYetToSee > 0)
|
|
||||||
{
|
|
||||||
// We now use the elapsed time as seen by the single thread farming out alc indexing
|
|
||||||
double meanContentElapsedIndexTime = srv.getTrackerStats().getMeanContentElapsedIndexTime();
|
|
||||||
remainingContentTimeMillis = (long) ((dirtyCount + newCount + contentYetToSee) * meanContentElapsedIndexTime);
|
|
||||||
}
|
|
||||||
now = new Date();
|
|
||||||
end = new Date(now.getTime() + remainingContentTimeMillis);
|
|
||||||
Duration remainingContent = new Duration(now, end);
|
|
||||||
coreSummary.add("FTS",ftsSummary);
|
|
||||||
|
|
||||||
Duration txLag = new Duration(lastIndexTxCommitDate, lastTxOnServerDate);
|
|
||||||
if (lastIndexTxCommitDate.compareTo(lastTxOnServerDate) > 0)
|
|
||||||
{
|
|
||||||
txLag = new Duration();
|
|
||||||
}
|
|
||||||
long txLagSeconds = (lastTxCommitTimeOnServer - lastIndexTxCommitTime) / 1000;
|
|
||||||
if (txLagSeconds < 0)
|
|
||||||
{
|
|
||||||
txLagSeconds = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Duration changeSetLag = new Duration(lastIndexChangeSetCommitDate, lastChangeSetOnServerDate);
|
|
||||||
if (lastIndexChangeSetCommitDate.compareTo(lastChangeSetOnServerDate) > 0)
|
|
||||||
{
|
|
||||||
changeSetLag = new Duration();
|
|
||||||
}
|
|
||||||
long changeSetLagSeconds = (lastChangeSetCommitTimeOnServer - lastIndexChangeSetCommitTime) / 1000;
|
|
||||||
if (txLagSeconds < 0)
|
|
||||||
{
|
|
||||||
txLagSeconds = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ContentTracker contentTrkr = trackerRegistry.getTrackerForCore(cname, ContentTracker.class);
|
|
||||||
TrackerState contentTrkrState = contentTrkr.getTrackerState();
|
|
||||||
// Leave ModelTracker out of this check, because it is common
|
|
||||||
boolean aTrackerIsRunning = aclTrkrState.isRunning() || metadataTrkrState.isRunning()
|
|
||||||
|| contentTrkrState.isRunning();
|
|
||||||
coreSummary.add("Active", aTrackerIsRunning);
|
|
||||||
|
|
||||||
ModelTracker modelTrkr = trackerRegistry.getModelTracker();
|
|
||||||
TrackerState modelTrkrState = modelTrkr.getTrackerState();
|
|
||||||
coreSummary.add("ModelTracker Active", modelTrkrState.isRunning());
|
|
||||||
coreSummary.add("ContentTracker Active", contentTrkrState.isRunning());
|
|
||||||
coreSummary.add("MetadataTracker Active", metadataTrkrState.isRunning());
|
|
||||||
coreSummary.add("AclTracker Active", aclTrkrState.isRunning());
|
|
||||||
|
|
||||||
// TX
|
|
||||||
|
|
||||||
coreSummary.add("Last Index TX Commit Time", lastIndexTxCommitTime);
|
|
||||||
coreSummary.add("Last Index TX Commit Date", lastIndexTxCommitDate);
|
|
||||||
coreSummary.add("TX Lag", txLagSeconds + " s");
|
|
||||||
coreSummary.add("TX Duration", txLag.toString());
|
|
||||||
coreSummary.add("Timestamp for last TX on server", lastTxCommitTimeOnServer);
|
|
||||||
coreSummary.add("Date for last TX on server", lastTxOnServerDate);
|
|
||||||
coreSummary.add("Id for last TX on server", lastTxIdOnServer);
|
|
||||||
coreSummary.add("Id for last TX in index", lastIndexedTxId);
|
|
||||||
coreSummary.add("Approx transactions remaining", transactionsToDo);
|
|
||||||
coreSummary.add("Approx transaction indexing time remaining", remainingTx.largestComponentformattedString());
|
|
||||||
|
|
||||||
// Change set
|
|
||||||
|
|
||||||
coreSummary.add("Last Index Change Set Commit Time", lastIndexChangeSetCommitTime);
|
|
||||||
coreSummary.add("Last Index Change Set Commit Date", lastIndexChangeSetCommitDate);
|
|
||||||
coreSummary.add("Change Set Lag", changeSetLagSeconds + " s");
|
|
||||||
coreSummary.add("Change Set Duration", changeSetLag.toString());
|
|
||||||
coreSummary.add("Timestamp for last Change Set on server", lastChangeSetCommitTimeOnServer);
|
|
||||||
coreSummary.add("Date for last Change Set on server", lastChangeSetOnServerDate);
|
|
||||||
coreSummary.add("Id for last Change Set on server", lastChangeSetIdOnServer);
|
|
||||||
coreSummary.add("Id for last Change Set in index", lastIndexedChangeSetId);
|
|
||||||
coreSummary.add("Approx change sets remaining", changeSetsToDo);
|
|
||||||
coreSummary.add("Approx change set indexing time remaining",
|
|
||||||
remainingChangeSet.largestComponentformattedString());
|
|
||||||
|
|
||||||
coreSummary.add("Approx content indexing time remaining",
|
|
||||||
remainingContent.largestComponentformattedString());
|
|
||||||
|
|
||||||
// Stats
|
|
||||||
|
|
||||||
coreSummary.add("Model sync times (ms)",
|
|
||||||
srv.getTrackerStats().getModelTimes().getNamedList(detail, hist, values));
|
|
||||||
coreSummary.add("Acl index time (ms)",
|
|
||||||
srv.getTrackerStats().getAclTimes().getNamedList(detail, hist, values));
|
|
||||||
coreSummary.add("Node index time (ms)",
|
|
||||||
srv.getTrackerStats().getNodeTimes().getNamedList(detail, hist, values));
|
|
||||||
coreSummary.add("Docs/Tx", srv.getTrackerStats().getTxDocs().getNamedList(detail, hist, values));
|
|
||||||
coreSummary.add("Doc Transformation time (ms)", srv.getTrackerStats().getDocTransformationTimes()
|
|
||||||
.getNamedList(detail, hist, values));
|
|
||||||
|
|
||||||
// Model
|
|
||||||
|
|
||||||
Map<String, Set<String>> modelErrors = srv.getModelErrors();
|
|
||||||
if (modelErrors.size() > 0)
|
|
||||||
{
|
|
||||||
NamedList<Object> errorList = new SimpleOrderedMap<Object>();
|
|
||||||
for (Map.Entry<String, Set<String>> modelNameToErrors : modelErrors.entrySet())
|
|
||||||
{
|
|
||||||
errorList.add(modelNameToErrors.getKey(), modelNameToErrors.getValue());
|
|
||||||
}
|
|
||||||
coreSummary.add("Model changes are not compatible with the existing data model and have not been applied",
|
|
||||||
errorList);
|
|
||||||
}
|
|
||||||
|
|
||||||
report.add(cname, coreSummary);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -0,0 +1,564 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||||
|
*
|
||||||
|
* This file is part of the Alfresco software.
|
||||||
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
|
* provided under the following open source license terms:
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.alfresco.solr;
|
||||||
|
|
||||||
|
import org.alfresco.error.AlfrescoRuntimeException;
|
||||||
|
import org.alfresco.service.cmr.repository.datatype.Duration;
|
||||||
|
import org.alfresco.solr.client.Node;
|
||||||
|
import org.alfresco.solr.tracker.*;
|
||||||
|
import org.alfresco.util.CachingDateFormat;
|
||||||
|
import org.apache.solr.common.util.NamedList;
|
||||||
|
import org.apache.solr.common.util.SimpleOrderedMap;
|
||||||
|
import org.json.JSONException;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static java.util.Optional.ofNullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Methods taken from AlfrescoCoreAdminHandler that deal with building reports
|
||||||
|
*/
|
||||||
|
class HandlerReportHelper
|
||||||
|
{
|
||||||
|
static NamedList<Object> buildAclReport(AclTracker tracker, Long aclid) throws JSONException
|
||||||
|
{
|
||||||
|
AclReport aclReport = tracker.checkAcl(aclid);
|
||||||
|
|
||||||
|
NamedList<Object> nr = new SimpleOrderedMap<>();
|
||||||
|
nr.add("Acl Id", aclReport.getAclId());
|
||||||
|
nr.add("Acl doc in index", aclReport.getIndexAclDoc());
|
||||||
|
if (aclReport.getIndexAclDoc() != null)
|
||||||
|
{
|
||||||
|
nr.add("Acl tx in Index", aclReport.getIndexAclTx());
|
||||||
|
}
|
||||||
|
|
||||||
|
return nr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NamedList<Object> buildTxReport(TrackerRegistry trackerRegistry, InformationServer srv, String coreName, MetadataTracker tracker, Long txid) throws JSONException
|
||||||
|
{
|
||||||
|
NamedList<Object> nr = new SimpleOrderedMap<>();
|
||||||
|
nr.add("TXID", txid);
|
||||||
|
nr.add("transaction", buildTrackerReport(trackerRegistry, srv, coreName, txid, txid, 0L, 0L, null, null));
|
||||||
|
NamedList<Object> nodes = new SimpleOrderedMap<>();
|
||||||
|
|
||||||
|
// add node reports ....
|
||||||
|
List<Node> dbNodes = tracker.getFullNodesForDbTransaction(txid);
|
||||||
|
for (Node node : dbNodes)
|
||||||
|
{
|
||||||
|
nodes.add("DBID " + node.getId(), buildNodeReport(tracker, node));
|
||||||
|
}
|
||||||
|
|
||||||
|
nr.add("txDbNodeCount", dbNodes.size());
|
||||||
|
nr.add("nodes", nodes);
|
||||||
|
return nr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NamedList<Object> buildAclTxReport(TrackerRegistry trackerRegistry, InformationServer srv, String coreName, AclTracker tracker, Long acltxid) throws JSONException
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
NamedList<Object> nr = new SimpleOrderedMap<>();
|
||||||
|
nr.add("TXID", acltxid);
|
||||||
|
nr.add("transaction", buildTrackerReport(trackerRegistry, srv, coreName, 0L, 0L, acltxid, acltxid, null, null));
|
||||||
|
NamedList<Object> nodes = new SimpleOrderedMap<>();
|
||||||
|
|
||||||
|
// add node reports ....
|
||||||
|
List<Long> dbAclIds = tracker.getAclsForDbAclTransaction(acltxid);
|
||||||
|
for (Long aclid : dbAclIds) {
|
||||||
|
nodes.add("ACLID " + aclid, buildAclReport(tracker, aclid));
|
||||||
|
}
|
||||||
|
nr.add("aclTxDbAclCount", dbAclIds.size());
|
||||||
|
nr.add("nodes", nodes);
|
||||||
|
return nr;
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
throw new AlfrescoRuntimeException("", exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static NamedList<Object> buildNodeReport(MetadataTracker tracker, Node node) throws JSONException
|
||||||
|
{
|
||||||
|
NodeReport nodeReport = tracker.checkNode(node);
|
||||||
|
|
||||||
|
NamedList<Object> nr = new SimpleOrderedMap<>();
|
||||||
|
nr.add("Node DBID", nodeReport.getDbid());
|
||||||
|
nr.add("DB TX", nodeReport.getDbTx());
|
||||||
|
nr.add("DB TX status", nodeReport.getDbNodeStatus().toString());
|
||||||
|
if (nodeReport.getIndexLeafDoc() != null)
|
||||||
|
{
|
||||||
|
nr.add("Leaf tx in Index", nodeReport.getIndexLeafTx());
|
||||||
|
}
|
||||||
|
if (nodeReport.getIndexAuxDoc() != null)
|
||||||
|
{
|
||||||
|
nr.add("Aux tx in Index", nodeReport.getIndexAuxTx());
|
||||||
|
}
|
||||||
|
nr.add("Indexed Node Doc Count", nodeReport.getIndexedNodeDocCount());
|
||||||
|
return nr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NamedList<Object> buildNodeReport(CoreStatePublisher publisher, Long dbid) throws JSONException
|
||||||
|
{
|
||||||
|
NodeReport nodeReport = publisher.checkNode(dbid);
|
||||||
|
|
||||||
|
NamedList<Object> payload = new SimpleOrderedMap<>();
|
||||||
|
payload.add("Node DBID", nodeReport.getDbid());
|
||||||
|
|
||||||
|
if (publisher.isOnMasterOrStandalone())
|
||||||
|
{
|
||||||
|
ofNullable(nodeReport.getDbTx()).ifPresent(value -> payload.add("DB TX", value));
|
||||||
|
ofNullable(nodeReport.getDbNodeStatus()).map(Object::toString).ifPresent(value -> payload.add("DB TX Status", value));
|
||||||
|
ofNullable(nodeReport.getIndexLeafTx()).ifPresent(value -> payload.add("Leaf tx in Index", value));
|
||||||
|
ofNullable(nodeReport.getIndexAuxDoc()).ifPresent(value -> payload.add("Aux tx in Index", value));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
payload.add("WARNING", "This response comes from a slave core and it contains minimal information about the node. " +
|
||||||
|
"Please consider to re-submit the same request to the corresponding Master, in order to get more information.");
|
||||||
|
}
|
||||||
|
|
||||||
|
ofNullable(nodeReport.getIndexedNodeDocCount()).ifPresent(value -> payload.add("Indexed Node Doc Count", value));
|
||||||
|
|
||||||
|
return payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds Tracker report
|
||||||
|
*/
|
||||||
|
static NamedList<Object> buildTrackerReport(TrackerRegistry trackerRegistry, InformationServer srv, String coreName, Long fromTx, Long toTx, Long fromAclTx, Long toAclTx,
|
||||||
|
Long fromTime, Long toTime) throws JSONException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// ACL
|
||||||
|
AclTracker aclTracker = trackerRegistry.getTrackerForCore(coreName, AclTracker.class);
|
||||||
|
IndexHealthReport aclReport = aclTracker.checkIndex(toTx, toAclTx, fromTime, toTime);
|
||||||
|
NamedList<Object> ihr = new SimpleOrderedMap<>();
|
||||||
|
ihr.add("Alfresco version", aclTracker.getAlfrescoVersion());
|
||||||
|
ihr.add("DB acl transaction count", aclReport.getDbAclTransactionCount());
|
||||||
|
ihr.add("Count of duplicated acl transactions in the index", aclReport.getDuplicatedAclTxInIndex()
|
||||||
|
.cardinality());
|
||||||
|
if (aclReport.getDuplicatedAclTxInIndex().cardinality() > 0) {
|
||||||
|
ihr.add("First duplicate acl tx", aclReport.getDuplicatedAclTxInIndex().nextSetBit(0L));
|
||||||
|
}
|
||||||
|
ihr.add("Count of acl transactions in the index but not the DB", aclReport.getAclTxInIndexButNotInDb()
|
||||||
|
.cardinality());
|
||||||
|
if (aclReport.getAclTxInIndexButNotInDb().cardinality() > 0) {
|
||||||
|
ihr.add("First acl transaction in the index but not the DB", aclReport.getAclTxInIndexButNotInDb()
|
||||||
|
.nextSetBit(0L));
|
||||||
|
}
|
||||||
|
ihr.add("Count of missing acl transactions from the Index", aclReport.getMissingAclTxFromIndex()
|
||||||
|
.cardinality());
|
||||||
|
if (aclReport.getMissingAclTxFromIndex().cardinality() > 0) {
|
||||||
|
ihr.add("First acl transaction missing from the Index", aclReport.getMissingAclTxFromIndex()
|
||||||
|
.nextSetBit(0L));
|
||||||
|
}
|
||||||
|
ihr.add("Index acl transaction count", aclReport.getAclTransactionDocsInIndex());
|
||||||
|
ihr.add("Index unique acl transaction count", aclReport.getAclTransactionDocsInIndex());
|
||||||
|
TrackerState aclState = aclTracker.getTrackerState();
|
||||||
|
ihr.add("Last indexed change set commit time", aclState.getLastIndexedChangeSetCommitTime());
|
||||||
|
Date lastChangeSetDate = new Date(aclState.getLastIndexedChangeSetCommitTime());
|
||||||
|
ihr.add("Last indexed change set commit date", CachingDateFormat.getDateFormat().format(lastChangeSetDate));
|
||||||
|
ihr.add("Last changeset id before holes", aclState.getLastIndexedChangeSetIdBeforeHoles());
|
||||||
|
|
||||||
|
// Metadata
|
||||||
|
MetadataTracker metadataTracker = trackerRegistry.getTrackerForCore(coreName, MetadataTracker.class);
|
||||||
|
IndexHealthReport metaReport = metadataTracker.checkIndex(toTx, toAclTx, fromTime, toTime);
|
||||||
|
ihr.add("DB transaction count", metaReport.getDbTransactionCount());
|
||||||
|
ihr.add("Count of duplicated transactions in the index", metaReport.getDuplicatedTxInIndex()
|
||||||
|
.cardinality());
|
||||||
|
if (metaReport.getDuplicatedTxInIndex().cardinality() > 0) {
|
||||||
|
ihr.add("First duplicate", metaReport.getDuplicatedTxInIndex().nextSetBit(0L));
|
||||||
|
}
|
||||||
|
ihr.add("Count of transactions in the index but not the DB", metaReport.getTxInIndexButNotInDb()
|
||||||
|
.cardinality());
|
||||||
|
if (metaReport.getTxInIndexButNotInDb().cardinality() > 0) {
|
||||||
|
ihr.add("First transaction in the index but not the DB", metaReport.getTxInIndexButNotInDb()
|
||||||
|
.nextSetBit(0L));
|
||||||
|
}
|
||||||
|
ihr.add("Count of missing transactions from the Index", metaReport.getMissingTxFromIndex().cardinality());
|
||||||
|
if (metaReport.getMissingTxFromIndex().cardinality() > 0) {
|
||||||
|
ihr.add("First transaction missing from the Index", metaReport.getMissingTxFromIndex()
|
||||||
|
.nextSetBit(0L));
|
||||||
|
}
|
||||||
|
ihr.add("Index transaction count", metaReport.getTransactionDocsInIndex());
|
||||||
|
ihr.add("Index unique transaction count", metaReport.getTransactionDocsInIndex());
|
||||||
|
ihr.add("Index node count", metaReport.getLeafDocCountInIndex());
|
||||||
|
ihr.add("Count of duplicate nodes in the index", metaReport.getDuplicatedLeafInIndex().cardinality());
|
||||||
|
if (metaReport.getDuplicatedLeafInIndex().cardinality() > 0) {
|
||||||
|
ihr.add("First duplicate node id in the index", metaReport.getDuplicatedLeafInIndex().nextSetBit(0L));
|
||||||
|
}
|
||||||
|
ihr.add("Index error count", metaReport.getErrorDocCountInIndex());
|
||||||
|
ihr.add("Count of duplicate error docs in the index", metaReport.getDuplicatedErrorInIndex()
|
||||||
|
.cardinality());
|
||||||
|
if (metaReport.getDuplicatedErrorInIndex().cardinality() > 0) {
|
||||||
|
ihr.add("First duplicate error in the index", SolrInformationServer.PREFIX_ERROR
|
||||||
|
+ metaReport.getDuplicatedErrorInIndex().nextSetBit(0L));
|
||||||
|
}
|
||||||
|
ihr.add("Index unindexed count", metaReport.getUnindexedDocCountInIndex());
|
||||||
|
ihr.add("Count of duplicate unindexed docs in the index", metaReport.getDuplicatedUnindexedInIndex()
|
||||||
|
.cardinality());
|
||||||
|
if (metaReport.getDuplicatedUnindexedInIndex().cardinality() > 0) {
|
||||||
|
ihr.add("First duplicate unindexed in the index",
|
||||||
|
metaReport.getDuplicatedUnindexedInIndex().nextSetBit(0L));
|
||||||
|
}
|
||||||
|
TrackerState metaState = metadataTracker.getTrackerState();
|
||||||
|
ihr.add("Last indexed transaction commit time", metaState.getLastIndexedTxCommitTime());
|
||||||
|
Date lastTxDate = new Date(metaState.getLastIndexedTxCommitTime());
|
||||||
|
ihr.add("Last indexed transaction commit date", CachingDateFormat.getDateFormat().format(lastTxDate));
|
||||||
|
ihr.add("Last TX id before holes", metaState.getLastIndexedTxIdBeforeHoles());
|
||||||
|
|
||||||
|
srv.addFTSStatusCounts(ihr);
|
||||||
|
|
||||||
|
return ihr;
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
throw new AlfrescoRuntimeException("", exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void addSlaveCoreSummary(TrackerRegistry trackerRegistry, String cname, boolean detail, boolean hist, boolean values,
|
||||||
|
InformationServer srv, NamedList<Object> report) throws IOException
|
||||||
|
{
|
||||||
|
NamedList<Object> coreSummary = new SimpleOrderedMap<>();
|
||||||
|
coreSummary.addAll((SimpleOrderedMap<Object>) srv.getCoreStats());
|
||||||
|
|
||||||
|
SlaveCoreStatePublisher statePublisher = trackerRegistry.getTrackerForCore(cname, SlaveCoreStatePublisher.class);
|
||||||
|
TrackerState trackerState = statePublisher.getTrackerState();
|
||||||
|
long lastIndexTxCommitTime = trackerState.getLastIndexedTxCommitTime();
|
||||||
|
|
||||||
|
long lastIndexedTxId = trackerState.getLastIndexedTxId();
|
||||||
|
long lastTxCommitTimeOnServer = trackerState.getLastTxCommitTimeOnServer();
|
||||||
|
long lastTxIdOnServer = trackerState.getLastTxIdOnServer();
|
||||||
|
|
||||||
|
Date lastIndexTxCommitDate = new Date(lastIndexTxCommitTime);
|
||||||
|
Date lastTxOnServerDate = new Date(lastTxCommitTimeOnServer);
|
||||||
|
long transactionsToDo = lastTxIdOnServer - lastIndexedTxId;
|
||||||
|
if (transactionsToDo < 0)
|
||||||
|
{
|
||||||
|
transactionsToDo = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
long nodesToDo = 0;
|
||||||
|
long remainingTxTimeMillis = 0;
|
||||||
|
if (transactionsToDo > 0)
|
||||||
|
{
|
||||||
|
// We now use the elapsed time as seen by the single thread farming out metadata indexing
|
||||||
|
double meanDocsPerTx = srv.getTrackerStats().getMeanDocsPerTx();
|
||||||
|
double meanNodeElaspedIndexTime = srv.getTrackerStats().getMeanNodeElapsedIndexTime();
|
||||||
|
nodesToDo = (long)(transactionsToDo * meanDocsPerTx);
|
||||||
|
remainingTxTimeMillis = (long) (nodesToDo * meanNodeElaspedIndexTime);
|
||||||
|
}
|
||||||
|
Date now = new Date();
|
||||||
|
Date end = new Date(now.getTime() + remainingTxTimeMillis);
|
||||||
|
Duration remainingTx = new Duration(now, end);
|
||||||
|
|
||||||
|
long remainingChangeSetTimeMillis = 0;
|
||||||
|
|
||||||
|
now = new Date();
|
||||||
|
end = new Date(now.getTime() + remainingChangeSetTimeMillis);
|
||||||
|
Duration remainingChangeSet = new Duration(now, end);
|
||||||
|
|
||||||
|
NamedList<Object> ftsSummary = new SimpleOrderedMap<>();
|
||||||
|
long remainingContentTimeMillis = 0;
|
||||||
|
srv.addFTSStatusCounts(ftsSummary);
|
||||||
|
long cleanCount =
|
||||||
|
ofNullable(ftsSummary.get("Node count with FTSStatus Clean"))
|
||||||
|
.map(Number.class::cast)
|
||||||
|
.map(Number::longValue)
|
||||||
|
.orElse(0L);
|
||||||
|
long dirtyCount =
|
||||||
|
ofNullable(ftsSummary.get("Node count with FTSStatus Dirty"))
|
||||||
|
.map(Number.class::cast)
|
||||||
|
.map(Number::longValue)
|
||||||
|
.orElse(0L);
|
||||||
|
long newCount =
|
||||||
|
ofNullable(ftsSummary.get("Node count with FTSStatus New"))
|
||||||
|
.map(Number.class::cast)
|
||||||
|
.map(Number::longValue)
|
||||||
|
.orElse(0L);
|
||||||
|
|
||||||
|
long nodesInIndex =
|
||||||
|
ofNullable(coreSummary.get("Alfresco Nodes in Index"))
|
||||||
|
.map(Number.class::cast)
|
||||||
|
.map(Number::longValue)
|
||||||
|
.orElse(0L);
|
||||||
|
|
||||||
|
long contentYetToSee = nodesInIndex > 0 ? nodesToDo * (cleanCount + dirtyCount + newCount)/nodesInIndex : 0;
|
||||||
|
if (dirtyCount + newCount + contentYetToSee > 0)
|
||||||
|
{
|
||||||
|
// We now use the elapsed time as seen by the single thread farming out alc indexing
|
||||||
|
double meanContentElapsedIndexTime = srv.getTrackerStats().getMeanContentElapsedIndexTime();
|
||||||
|
remainingContentTimeMillis = (long) ((dirtyCount + newCount + contentYetToSee) * meanContentElapsedIndexTime);
|
||||||
|
}
|
||||||
|
now = new Date();
|
||||||
|
end = new Date(now.getTime() + remainingContentTimeMillis);
|
||||||
|
Duration remainingContent = new Duration(now, end);
|
||||||
|
coreSummary.add("FTS",ftsSummary);
|
||||||
|
|
||||||
|
Duration txLag = new Duration(lastIndexTxCommitDate, lastTxOnServerDate);
|
||||||
|
if (lastIndexTxCommitDate.compareTo(lastTxOnServerDate) > 0)
|
||||||
|
{
|
||||||
|
txLag = new Duration();
|
||||||
|
}
|
||||||
|
long txLagSeconds = (lastTxCommitTimeOnServer - lastIndexTxCommitTime) / 1000;
|
||||||
|
if (txLagSeconds < 0)
|
||||||
|
{
|
||||||
|
txLagSeconds = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelTracker modelTrkr = trackerRegistry.getModelTracker();
|
||||||
|
TrackerState modelTrkrState = modelTrkr.getTrackerState();
|
||||||
|
coreSummary.add("ModelTracker Active", modelTrkrState.isRunning());
|
||||||
|
coreSummary.add("NodeState Publisher Active", trackerState.isRunning());
|
||||||
|
|
||||||
|
// TX
|
||||||
|
|
||||||
|
coreSummary.add("Last Index TX Commit Time", lastIndexTxCommitTime);
|
||||||
|
coreSummary.add("Last Index TX Commit Date", lastIndexTxCommitDate);
|
||||||
|
coreSummary.add("TX Lag", txLagSeconds + " s");
|
||||||
|
coreSummary.add("TX Duration", txLag.toString());
|
||||||
|
coreSummary.add("Timestamp for last TX on server", lastTxCommitTimeOnServer);
|
||||||
|
coreSummary.add("Date for last TX on server", lastTxOnServerDate);
|
||||||
|
coreSummary.add("Id for last TX on server", lastTxIdOnServer);
|
||||||
|
coreSummary.add("Id for last TX in index", lastIndexedTxId);
|
||||||
|
coreSummary.add("Approx transactions remaining", transactionsToDo);
|
||||||
|
coreSummary.add("Approx transaction indexing time remaining", remainingTx.largestComponentformattedString());
|
||||||
|
// Stats
|
||||||
|
|
||||||
|
coreSummary.add("Model sync times (ms)", srv.getTrackerStats().getModelTimes().getNamedList(detail, hist, values));
|
||||||
|
coreSummary.add("Docs/Tx", srv.getTrackerStats().getTxDocs().getNamedList(detail, hist, values));
|
||||||
|
|
||||||
|
// Model
|
||||||
|
|
||||||
|
Map<String, Set<String>> modelErrors = srv.getModelErrors();
|
||||||
|
if (modelErrors.size() > 0)
|
||||||
|
{
|
||||||
|
NamedList<Object> errorList = new SimpleOrderedMap<>();
|
||||||
|
for (Map.Entry<String, Set<String>> modelNameToErrors : modelErrors.entrySet())
|
||||||
|
{
|
||||||
|
errorList.add(modelNameToErrors.getKey(), modelNameToErrors.getValue());
|
||||||
|
}
|
||||||
|
coreSummary.add("Model changes are not compatible with the existing data model and have not been applied", errorList);
|
||||||
|
}
|
||||||
|
|
||||||
|
report.add(cname, coreSummary);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void addMasterOrStandaloneCoreSummary(TrackerRegistry trackerRegistry, String cname, boolean detail, boolean hist, boolean values,
|
||||||
|
InformationServer srv, NamedList<Object> report) throws IOException
|
||||||
|
{
|
||||||
|
NamedList<Object> coreSummary = new SimpleOrderedMap<>();
|
||||||
|
coreSummary.addAll((SimpleOrderedMap<Object>) srv.getCoreStats());
|
||||||
|
|
||||||
|
MetadataTracker metaTrkr = trackerRegistry.getTrackerForCore(cname, MetadataTracker.class);
|
||||||
|
TrackerState metadataTrkrState = metaTrkr.getTrackerState();
|
||||||
|
long lastIndexTxCommitTime = metadataTrkrState.getLastIndexedTxCommitTime();
|
||||||
|
|
||||||
|
long lastIndexedTxId = metadataTrkrState.getLastIndexedTxId();
|
||||||
|
long lastTxCommitTimeOnServer = metadataTrkrState.getLastTxCommitTimeOnServer();
|
||||||
|
long lastTxIdOnServer = metadataTrkrState.getLastTxIdOnServer();
|
||||||
|
Date lastIndexTxCommitDate = new Date(lastIndexTxCommitTime);
|
||||||
|
Date lastTxOnServerDate = new Date(lastTxCommitTimeOnServer);
|
||||||
|
long transactionsToDo = lastTxIdOnServer - lastIndexedTxId;
|
||||||
|
if (transactionsToDo < 0)
|
||||||
|
{
|
||||||
|
transactionsToDo = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
AclTracker aclTrkr = trackerRegistry.getTrackerForCore(cname, AclTracker.class);
|
||||||
|
TrackerState aclTrkrState = aclTrkr.getTrackerState();
|
||||||
|
long lastIndexChangeSetCommitTime = aclTrkrState.getLastIndexedChangeSetCommitTime();
|
||||||
|
long lastIndexedChangeSetId = aclTrkrState.getLastIndexedChangeSetId();
|
||||||
|
long lastChangeSetCommitTimeOnServer = aclTrkrState.getLastChangeSetCommitTimeOnServer();
|
||||||
|
long lastChangeSetIdOnServer = aclTrkrState.getLastChangeSetIdOnServer();
|
||||||
|
Date lastIndexChangeSetCommitDate = new Date(lastIndexChangeSetCommitTime);
|
||||||
|
Date lastChangeSetOnServerDate = new Date(lastChangeSetCommitTimeOnServer);
|
||||||
|
long changeSetsToDo = lastChangeSetIdOnServer - lastIndexedChangeSetId;
|
||||||
|
if (changeSetsToDo < 0)
|
||||||
|
{
|
||||||
|
changeSetsToDo = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
long nodesToDo = 0;
|
||||||
|
long remainingTxTimeMillis = 0;
|
||||||
|
if (transactionsToDo > 0)
|
||||||
|
{
|
||||||
|
// We now use the elapsed time as seen by the single thread farming out metadata indexing
|
||||||
|
double meanDocsPerTx = srv.getTrackerStats().getMeanDocsPerTx();
|
||||||
|
double meanNodeElaspedIndexTime = srv.getTrackerStats().getMeanNodeElapsedIndexTime();
|
||||||
|
nodesToDo = (long)(transactionsToDo * meanDocsPerTx);
|
||||||
|
remainingTxTimeMillis = (long) (nodesToDo * meanNodeElaspedIndexTime);
|
||||||
|
}
|
||||||
|
Date now = new Date();
|
||||||
|
Date end = new Date(now.getTime() + remainingTxTimeMillis);
|
||||||
|
Duration remainingTx = new Duration(now, end);
|
||||||
|
|
||||||
|
long remainingChangeSetTimeMillis = 0;
|
||||||
|
if (changeSetsToDo > 0)
|
||||||
|
{
|
||||||
|
// We now use the elapsed time as seen by the single thread farming out alc indexing
|
||||||
|
double meanAclsPerChangeSet = srv.getTrackerStats().getMeanAclsPerChangeSet();
|
||||||
|
double meanAclElapsedIndexTime = srv.getTrackerStats().getMeanAclElapsedIndexTime();
|
||||||
|
remainingChangeSetTimeMillis = (long) (changeSetsToDo * meanAclsPerChangeSet * meanAclElapsedIndexTime);
|
||||||
|
}
|
||||||
|
now = new Date();
|
||||||
|
end = new Date(now.getTime() + remainingChangeSetTimeMillis);
|
||||||
|
Duration remainingChangeSet = new Duration(now, end);
|
||||||
|
|
||||||
|
NamedList<Object> ftsSummary = new SimpleOrderedMap<>();
|
||||||
|
long remainingContentTimeMillis = 0;
|
||||||
|
srv.addFTSStatusCounts(ftsSummary);
|
||||||
|
long cleanCount =
|
||||||
|
ofNullable(ftsSummary.get("Node count with FTSStatus Clean"))
|
||||||
|
.map(Number.class::cast)
|
||||||
|
.map(Number::longValue)
|
||||||
|
.orElse(0L);
|
||||||
|
long dirtyCount =
|
||||||
|
ofNullable(ftsSummary.get("Node count with FTSStatus Dirty"))
|
||||||
|
.map(Number.class::cast)
|
||||||
|
.map(Number::longValue)
|
||||||
|
.orElse(0L);
|
||||||
|
long newCount =
|
||||||
|
ofNullable(ftsSummary.get("Node count with FTSStatus New"))
|
||||||
|
.map(Number.class::cast)
|
||||||
|
.map(Number::longValue)
|
||||||
|
.orElse(0L);
|
||||||
|
|
||||||
|
long nodesInIndex =
|
||||||
|
ofNullable(coreSummary.get("Alfresco Nodes in Index"))
|
||||||
|
.map(Number.class::cast)
|
||||||
|
.map(Number::longValue)
|
||||||
|
.orElse(0L);
|
||||||
|
|
||||||
|
long contentYetToSee = nodesInIndex > 0 ? nodesToDo * (cleanCount + dirtyCount + newCount)/nodesInIndex : 0;
|
||||||
|
if (dirtyCount + newCount + contentYetToSee > 0)
|
||||||
|
{
|
||||||
|
// We now use the elapsed time as seen by the single thread farming out alc indexing
|
||||||
|
double meanContentElapsedIndexTime = srv.getTrackerStats().getMeanContentElapsedIndexTime();
|
||||||
|
remainingContentTimeMillis = (long) ((dirtyCount + newCount + contentYetToSee) * meanContentElapsedIndexTime);
|
||||||
|
}
|
||||||
|
now = new Date();
|
||||||
|
end = new Date(now.getTime() + remainingContentTimeMillis);
|
||||||
|
Duration remainingContent = new Duration(now, end);
|
||||||
|
coreSummary.add("FTS",ftsSummary);
|
||||||
|
|
||||||
|
Duration txLag = new Duration(lastIndexTxCommitDate, lastTxOnServerDate);
|
||||||
|
if (lastIndexTxCommitDate.compareTo(lastTxOnServerDate) > 0)
|
||||||
|
{
|
||||||
|
txLag = new Duration();
|
||||||
|
}
|
||||||
|
long txLagSeconds = (lastTxCommitTimeOnServer - lastIndexTxCommitTime) / 1000;
|
||||||
|
if (txLagSeconds < 0)
|
||||||
|
{
|
||||||
|
txLagSeconds = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Duration changeSetLag = new Duration(lastIndexChangeSetCommitDate, lastChangeSetOnServerDate);
|
||||||
|
if (lastIndexChangeSetCommitDate.compareTo(lastChangeSetOnServerDate) > 0)
|
||||||
|
{
|
||||||
|
changeSetLag = new Duration();
|
||||||
|
}
|
||||||
|
long changeSetLagSeconds = (lastChangeSetCommitTimeOnServer - lastIndexChangeSetCommitTime) / 1000;
|
||||||
|
if (txLagSeconds < 0)
|
||||||
|
{
|
||||||
|
txLagSeconds = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentTracker contentTrkr = trackerRegistry.getTrackerForCore(cname, ContentTracker.class);
|
||||||
|
TrackerState contentTrkrState = contentTrkr.getTrackerState();
|
||||||
|
// Leave ModelTracker out of this check, because it is common
|
||||||
|
boolean aTrackerIsRunning = aclTrkrState.isRunning() || metadataTrkrState.isRunning()
|
||||||
|
|| contentTrkrState.isRunning();
|
||||||
|
coreSummary.add("Active", aTrackerIsRunning);
|
||||||
|
|
||||||
|
ModelTracker modelTrkr = trackerRegistry.getModelTracker();
|
||||||
|
TrackerState modelTrkrState = modelTrkr.getTrackerState();
|
||||||
|
coreSummary.add("ModelTracker Active", modelTrkrState.isRunning());
|
||||||
|
coreSummary.add("ContentTracker Active", contentTrkrState.isRunning());
|
||||||
|
coreSummary.add("MetadataTracker Active", metadataTrkrState.isRunning());
|
||||||
|
coreSummary.add("AclTracker Active", aclTrkrState.isRunning());
|
||||||
|
|
||||||
|
// TX
|
||||||
|
|
||||||
|
coreSummary.add("Last Index TX Commit Time", lastIndexTxCommitTime);
|
||||||
|
coreSummary.add("Last Index TX Commit Date", lastIndexTxCommitDate);
|
||||||
|
coreSummary.add("TX Lag", txLagSeconds + " s");
|
||||||
|
coreSummary.add("TX Duration", txLag.toString());
|
||||||
|
coreSummary.add("Timestamp for last TX on server", lastTxCommitTimeOnServer);
|
||||||
|
coreSummary.add("Date for last TX on server", lastTxOnServerDate);
|
||||||
|
coreSummary.add("Id for last TX on server", lastTxIdOnServer);
|
||||||
|
coreSummary.add("Id for last TX in index", lastIndexedTxId);
|
||||||
|
coreSummary.add("Approx transactions remaining", transactionsToDo);
|
||||||
|
coreSummary.add("Approx transaction indexing time remaining", remainingTx.largestComponentformattedString());
|
||||||
|
|
||||||
|
// Change set
|
||||||
|
|
||||||
|
coreSummary.add("Last Index Change Set Commit Time", lastIndexChangeSetCommitTime);
|
||||||
|
coreSummary.add("Last Index Change Set Commit Date", lastIndexChangeSetCommitDate);
|
||||||
|
coreSummary.add("Change Set Lag", changeSetLagSeconds + " s");
|
||||||
|
coreSummary.add("Change Set Duration", changeSetLag.toString());
|
||||||
|
coreSummary.add("Timestamp for last Change Set on server", lastChangeSetCommitTimeOnServer);
|
||||||
|
coreSummary.add("Date for last Change Set on server", lastChangeSetOnServerDate);
|
||||||
|
coreSummary.add("Id for last Change Set on server", lastChangeSetIdOnServer);
|
||||||
|
coreSummary.add("Id for last Change Set in index", lastIndexedChangeSetId);
|
||||||
|
coreSummary.add("Approx change sets remaining", changeSetsToDo);
|
||||||
|
coreSummary.add("Approx change set indexing time remaining",
|
||||||
|
remainingChangeSet.largestComponentformattedString());
|
||||||
|
|
||||||
|
coreSummary.add("Approx content indexing time remaining",
|
||||||
|
remainingContent.largestComponentformattedString());
|
||||||
|
|
||||||
|
// Stats
|
||||||
|
|
||||||
|
coreSummary.add("Model sync times (ms)",
|
||||||
|
srv.getTrackerStats().getModelTimes().getNamedList(detail, hist, values));
|
||||||
|
coreSummary.add("Acl index time (ms)",
|
||||||
|
srv.getTrackerStats().getAclTimes().getNamedList(detail, hist, values));
|
||||||
|
coreSummary.add("Node index time (ms)",
|
||||||
|
srv.getTrackerStats().getNodeTimes().getNamedList(detail, hist, values));
|
||||||
|
coreSummary.add("Docs/Tx", srv.getTrackerStats().getTxDocs().getNamedList(detail, hist, values));
|
||||||
|
coreSummary.add("Doc Transformation time (ms)", srv.getTrackerStats().getDocTransformationTimes()
|
||||||
|
.getNamedList(detail, hist, values));
|
||||||
|
|
||||||
|
// Model
|
||||||
|
|
||||||
|
Map<String, Set<String>> modelErrors = srv.getModelErrors();
|
||||||
|
if (modelErrors.size() > 0)
|
||||||
|
{
|
||||||
|
NamedList<Object> errorList = new SimpleOrderedMap<>();
|
||||||
|
for (Map.Entry<String, Set<String>> modelNameToErrors : modelErrors.entrySet())
|
||||||
|
{
|
||||||
|
errorList.add(modelNameToErrors.getKey(), modelNameToErrors.getValue());
|
||||||
|
}
|
||||||
|
coreSummary.add("Model changes are not compatible with the existing data model and have not been applied",
|
||||||
|
errorList);
|
||||||
|
}
|
||||||
|
|
||||||
|
report.add(cname, coreSummary);
|
||||||
|
}
|
||||||
|
}
|
@@ -35,7 +35,7 @@ import org.alfresco.solr.tracker.CommitTracker;
|
|||||||
import org.alfresco.solr.tracker.ContentTracker;
|
import org.alfresco.solr.tracker.ContentTracker;
|
||||||
import org.alfresco.solr.tracker.MetadataTracker;
|
import org.alfresco.solr.tracker.MetadataTracker;
|
||||||
import org.alfresco.solr.tracker.ModelTracker;
|
import org.alfresco.solr.tracker.ModelTracker;
|
||||||
import org.alfresco.solr.tracker.SlaveNodeStatePublisher;
|
import org.alfresco.solr.tracker.SlaveCoreStatePublisher;
|
||||||
import org.alfresco.solr.tracker.SolrTrackerScheduler;
|
import org.alfresco.solr.tracker.SolrTrackerScheduler;
|
||||||
import org.alfresco.solr.tracker.Tracker;
|
import org.alfresco.solr.tracker.Tracker;
|
||||||
import org.alfresco.solr.tracker.TrackerRegistry;
|
import org.alfresco.solr.tracker.TrackerRegistry;
|
||||||
@@ -183,7 +183,7 @@ public class SolrCoreLoadListener extends AbstractSolrEventListener
|
|||||||
{
|
{
|
||||||
LOGGER.info("SearchServices Core Trackers have been explicitly disabled on core \"{}\" through \"enable.alfresco.tracking\" configuration property.", core.getName());
|
LOGGER.info("SearchServices Core Trackers have been explicitly disabled on core \"{}\" through \"enable.alfresco.tracking\" configuration property.", core.getName());
|
||||||
|
|
||||||
SlaveNodeStatePublisher statePublisher = new SlaveNodeStatePublisher(false, coreProperties, repositoryClient, core.getName(), informationServer);
|
SlaveCoreStatePublisher statePublisher = new SlaveCoreStatePublisher(false, coreProperties, repositoryClient, core.getName(), informationServer);
|
||||||
trackerRegistry.register(core.getName(), statePublisher);
|
trackerRegistry.register(core.getName(), statePublisher);
|
||||||
scheduler.schedule(statePublisher, core.getName(), coreProperties);
|
scheduler.schedule(statePublisher, core.getName(), coreProperties);
|
||||||
trackers.add(statePublisher);
|
trackers.add(statePublisher);
|
||||||
@@ -198,7 +198,7 @@ public class SolrCoreLoadListener extends AbstractSolrEventListener
|
|||||||
{
|
{
|
||||||
LOGGER.info("SearchServices Core Trackers have been disabled on core \"{}\" because it is a slave core.", core.getName());
|
LOGGER.info("SearchServices Core Trackers have been disabled on core \"{}\" because it is a slave core.", core.getName());
|
||||||
|
|
||||||
SlaveNodeStatePublisher statePublisher = new SlaveNodeStatePublisher(false, coreProperties, repositoryClient, core.getName(), informationServer);
|
SlaveCoreStatePublisher statePublisher = new SlaveCoreStatePublisher(false, coreProperties, repositoryClient, core.getName(), informationServer);
|
||||||
trackerRegistry.register(core.getName(), statePublisher);
|
trackerRegistry.register(core.getName(), statePublisher);
|
||||||
scheduler.schedule(statePublisher, core.getName(), coreProperties);
|
scheduler.schedule(statePublisher, core.getName(), coreProperties);
|
||||||
trackers.add(statePublisher);
|
trackers.add(statePublisher);
|
||||||
|
@@ -41,6 +41,7 @@ import org.alfresco.service.namespace.QName;
|
|||||||
import org.alfresco.solr.AlfrescoCoreAdminHandler;
|
import org.alfresco.solr.AlfrescoCoreAdminHandler;
|
||||||
import org.alfresco.solr.AlfrescoSolrDataModel;
|
import org.alfresco.solr.AlfrescoSolrDataModel;
|
||||||
import org.alfresco.solr.InformationServer;
|
import org.alfresco.solr.InformationServer;
|
||||||
|
import org.alfresco.solr.NodeReport;
|
||||||
import org.alfresco.solr.TrackerState;
|
import org.alfresco.solr.TrackerState;
|
||||||
import org.alfresco.solr.client.SOLRAPIClient;
|
import org.alfresco.solr.client.SOLRAPIClient;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
@@ -59,7 +60,7 @@ import java.util.Properties;
|
|||||||
* @since 1.5
|
* @since 1.5
|
||||||
* @see <a href="https://issues.alfresco.com/jira/browse/SEARCH-1752">SEARCH-1752</a>
|
* @see <a href="https://issues.alfresco.com/jira/browse/SEARCH-1752">SEARCH-1752</a>
|
||||||
*/
|
*/
|
||||||
public abstract class NodeStatePublisher extends AbstractTracker
|
public abstract class CoreStatePublisher extends AbstractTracker
|
||||||
{
|
{
|
||||||
DocRouter docRouter;
|
DocRouter docRouter;
|
||||||
private final boolean isMaster;
|
private final boolean isMaster;
|
||||||
@@ -70,7 +71,7 @@ public abstract class NodeStatePublisher extends AbstractTracker
|
|||||||
/** The property to use for determining the shard. */
|
/** The property to use for determining the shard. */
|
||||||
protected Optional<QName> shardProperty = Optional.empty();
|
protected Optional<QName> shardProperty = Optional.empty();
|
||||||
|
|
||||||
NodeStatePublisher(
|
CoreStatePublisher(
|
||||||
boolean isMaster,
|
boolean isMaster,
|
||||||
Properties p,
|
Properties p,
|
||||||
SOLRAPIClient client,
|
SOLRAPIClient client,
|
||||||
@@ -88,12 +89,28 @@ public abstract class NodeStatePublisher extends AbstractTracker
|
|||||||
docRouter = DocRouterFactory.getRouter(p, ShardMethodEnum.getShardMethod(shardMethod));
|
docRouter = DocRouterFactory.getRouter(p, ShardMethodEnum.getShardMethod(shardMethod));
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeStatePublisher(Type type)
|
CoreStatePublisher(Type type)
|
||||||
{
|
{
|
||||||
super(type);
|
super(type);
|
||||||
this.isMaster = false;
|
this.isMaster = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns information about the {@link org.alfresco.solr.client.Node} associated with the given dbid.
|
||||||
|
*
|
||||||
|
* @param dbid the node identifier.
|
||||||
|
* @return the {@link org.alfresco.solr.client.Node} associated with the given dbid.
|
||||||
|
*/
|
||||||
|
public NodeReport checkNode(Long dbid)
|
||||||
|
{
|
||||||
|
NodeReport nodeReport = new NodeReport();
|
||||||
|
nodeReport.setDbid(dbid);
|
||||||
|
|
||||||
|
this.infoSrv.addCommonNodeReportInfo(nodeReport);
|
||||||
|
|
||||||
|
return nodeReport;
|
||||||
|
}
|
||||||
|
|
||||||
private void firstUpdateShardProperty()
|
private void firstUpdateShardProperty()
|
||||||
{
|
{
|
||||||
shardKey.ifPresent( shardKeyName -> {
|
shardKey.ifPresent( shardKeyName -> {
|
||||||
@@ -222,4 +239,14 @@ public abstract class NodeStatePublisher extends AbstractTracker
|
|||||||
{
|
{
|
||||||
return this.docRouter;
|
return this.docRouter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the hosting core is master or standalone.
|
||||||
|
*
|
||||||
|
* @return true if the hosting core is master or standalone.
|
||||||
|
*/
|
||||||
|
public boolean isOnMasterOrStandalone()
|
||||||
|
{
|
||||||
|
return isMaster;
|
||||||
|
}
|
||||||
}
|
}
|
@@ -49,7 +49,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
* This tracks two things: transactions and metadata nodes
|
* This tracks two things: transactions and metadata nodes
|
||||||
* @author Ahmed Owian
|
* @author Ahmed Owian
|
||||||
*/
|
*/
|
||||||
public class MetadataTracker extends NodeStatePublisher implements Tracker
|
public class MetadataTracker extends CoreStatePublisher implements Tracker
|
||||||
{
|
{
|
||||||
protected final static Logger log = LoggerFactory.getLogger(MetadataTracker.class);
|
protected final static Logger log = LoggerFactory.getLogger(MetadataTracker.class);
|
||||||
private static final int DEFAULT_TRANSACTION_DOCS_BATCH_SIZE = 100;
|
private static final int DEFAULT_TRANSACTION_DOCS_BATCH_SIZE = 100;
|
||||||
@@ -888,24 +888,18 @@ public class MetadataTracker extends NodeStatePublisher implements Tracker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public NodeReport checkNode(Long dbid)
|
public NodeReport checkNode(Long dbid)
|
||||||
{
|
{
|
||||||
NodeReport nodeReport = new NodeReport();
|
NodeReport nodeReport = super.checkNode(dbid);
|
||||||
nodeReport.setDbid(dbid);
|
|
||||||
|
|
||||||
// In DB
|
// In DB
|
||||||
|
|
||||||
GetNodesParameters parameters = new GetNodesParameters();
|
GetNodesParameters parameters = new GetNodesParameters();
|
||||||
parameters.setFromNodeId(dbid);
|
parameters.setFromNodeId(dbid);
|
||||||
parameters.setToNodeId(dbid);
|
parameters.setToNodeId(dbid);
|
||||||
List<Node> dbnodes;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
dbnodes = client.getNodes(parameters, 1);
|
List<Node> dbnodes = client.getNodes(parameters, 1);
|
||||||
if (dbnodes.size() == 1)
|
if (dbnodes.size() == 1)
|
||||||
{
|
{
|
||||||
Node dbnode = dbnodes.get(0);
|
Node dbnode = dbnodes.get(0);
|
||||||
@@ -915,41 +909,31 @@ public class MetadataTracker extends NodeStatePublisher implements Tracker
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
nodeReport.setDbNodeStatus(SolrApiNodeStatus.UNKNOWN);
|
nodeReport.setDbNodeStatus(SolrApiNodeStatus.UNKNOWN);
|
||||||
nodeReport.setDbTx(-1l);
|
nodeReport.setDbTx(-1L);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
nodeReport.setDbNodeStatus(SolrApiNodeStatus.UNKNOWN);
|
nodeReport.setDbNodeStatus(SolrApiNodeStatus.UNKNOWN);
|
||||||
nodeReport.setDbTx(-2l);
|
nodeReport.setDbTx(-2L);
|
||||||
}
|
}
|
||||||
catch (JSONException e)
|
catch (JSONException e)
|
||||||
{
|
{
|
||||||
nodeReport.setDbNodeStatus(SolrApiNodeStatus.UNKNOWN);
|
nodeReport.setDbNodeStatus(SolrApiNodeStatus.UNKNOWN);
|
||||||
nodeReport.setDbTx(-3l);
|
nodeReport.setDbTx(-3L);
|
||||||
}
|
}
|
||||||
catch (AuthenticationException e1)
|
catch (AuthenticationException e1)
|
||||||
{
|
{
|
||||||
nodeReport.setDbNodeStatus(SolrApiNodeStatus.UNKNOWN);
|
nodeReport.setDbNodeStatus(SolrApiNodeStatus.UNKNOWN);
|
||||||
nodeReport.setDbTx(-4l);
|
nodeReport.setDbTx(-4L);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.infoSrv.addCommonNodeReportInfo(nodeReport);
|
|
||||||
|
|
||||||
return nodeReport;
|
return nodeReport;
|
||||||
}
|
}
|
||||||
|
|
||||||
public NodeReport checkNode(Node node)
|
public NodeReport checkNode(Node node)
|
||||||
{
|
{
|
||||||
NodeReport nodeReport = new NodeReport();
|
return checkNode(node.getId());
|
||||||
nodeReport.setDbid(node.getId());
|
|
||||||
|
|
||||||
nodeReport.setDbNodeStatus(node.getStatus());
|
|
||||||
nodeReport.setDbTx(node.getTxnId());
|
|
||||||
|
|
||||||
this.infoSrv.addCommonNodeReportInfo(nodeReport);
|
|
||||||
|
|
||||||
return nodeReport;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Node> getFullNodesForDbTransaction(Long txid)
|
public List<Node> getFullNodesForDbTransaction(Long txid)
|
||||||
|
@@ -14,8 +14,8 @@ import java.util.Properties;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Despite belonging to the Tracker ecosystem, this component is actually a publisher, which periodically informs
|
* Despite belonging to the Tracker ecosystem, this component is actually a publisher, which periodically informs
|
||||||
* Alfresco about the state of the hosting slave node.
|
* Alfresco about the state of the hosting slave core.
|
||||||
* As the name suggests, this worker is scheduled only when the hosting node acts as a slave.
|
* As the name suggests, this worker is scheduled only when the owning core acts as a slave.
|
||||||
* It allows Solr's master/slave setup to be used with dynamic shard registration.
|
* It allows Solr's master/slave setup to be used with dynamic shard registration.
|
||||||
*
|
*
|
||||||
* In this scenario the slave is polling a "tracking" Solr node. The tracker below calls
|
* In this scenario the slave is polling a "tracking" Solr node. The tracker below calls
|
||||||
@@ -27,9 +27,9 @@ import java.util.Properties;
|
|||||||
* @author Andrea Gazzarini
|
* @author Andrea Gazzarini
|
||||||
* @since 1.5
|
* @since 1.5
|
||||||
*/
|
*/
|
||||||
public class SlaveNodeStatePublisher extends NodeStatePublisher
|
public class SlaveCoreStatePublisher extends CoreStatePublisher
|
||||||
{
|
{
|
||||||
public SlaveNodeStatePublisher(
|
public SlaveCoreStatePublisher(
|
||||||
boolean isMaster,
|
boolean isMaster,
|
||||||
Properties coreProperties,
|
Properties coreProperties,
|
||||||
SOLRAPIClient repositoryClient,
|
SOLRAPIClient repositoryClient,
|
||||||
@@ -61,6 +61,12 @@ public class SlaveNodeStatePublisher extends NodeStatePublisher
|
|||||||
// Do nothing here
|
// Do nothing here
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOnMasterOrStandalone()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasMaintenance()
|
public boolean hasMaintenance()
|
||||||
{
|
{
|
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2005-2019 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.alfresco.solr.utils;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
public abstract class Utils
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Returns the same input collection if that is not null, otherwise a new empty collection.
|
||||||
|
* Provides a safe way for iterating over a returned collection (which could be null).
|
||||||
|
*
|
||||||
|
* @param values the collection.
|
||||||
|
* @param <T> the collection type.
|
||||||
|
* @return the same input collection if that is not null, otherwise a new empty collection.
|
||||||
|
*/
|
||||||
|
public static <T> Collection<T> notNullOrEmpty(Collection<T> values)
|
||||||
|
{
|
||||||
|
return values != null ? values : Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the given input in an Integer, otherwise it returns null.
|
||||||
|
*
|
||||||
|
* @param value the numeric string.
|
||||||
|
* @return the corresponding Integer or null in case the input is NaN.
|
||||||
|
*/
|
||||||
|
public static Integer toIntOrNull(String value)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return Integer.valueOf(value);
|
||||||
|
}
|
||||||
|
catch(NumberFormatException nfe)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -20,15 +20,23 @@ package org.alfresco.solr;
|
|||||||
|
|
||||||
import static java.util.Arrays.asList;
|
import static java.util.Arrays.asList;
|
||||||
|
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
|
import static java.util.Collections.singletonList;
|
||||||
import static org.alfresco.solr.AlfrescoCoreAdminHandler.ALFRESCO_CORE_NAME;
|
import static org.alfresco.solr.AlfrescoCoreAdminHandler.ALFRESCO_CORE_NAME;
|
||||||
import static org.alfresco.solr.AlfrescoCoreAdminHandler.ARCHIVE_CORE_NAME;
|
import static org.alfresco.solr.AlfrescoCoreAdminHandler.ARCHIVE_CORE_NAME;
|
||||||
import static org.alfresco.solr.AlfrescoCoreAdminHandler.ARG_TXID;
|
import static org.alfresco.solr.AlfrescoCoreAdminHandler.ARG_TXID;
|
||||||
import static org.alfresco.solr.AlfrescoCoreAdminHandler.STORE_REF_MAP;
|
import static org.alfresco.solr.AlfrescoCoreAdminHandler.STORE_REF_MAP;
|
||||||
import static org.alfresco.solr.AlfrescoCoreAdminHandler.VERSION_CORE_NAME;
|
import static org.alfresco.solr.AlfrescoCoreAdminHandler.VERSION_CORE_NAME;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertSame;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.reset;
|
import static org.mockito.Mockito.reset;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
@@ -42,13 +50,18 @@ import java.util.stream.Collectors;
|
|||||||
import org.alfresco.service.cmr.repository.StoreRef;
|
import org.alfresco.service.cmr.repository.StoreRef;
|
||||||
import org.alfresco.solr.adapters.IOpenBitSet;
|
import org.alfresco.solr.adapters.IOpenBitSet;
|
||||||
import org.alfresco.solr.tracker.AclTracker;
|
import org.alfresco.solr.tracker.AclTracker;
|
||||||
|
import org.alfresco.solr.tracker.DocRouter;
|
||||||
import org.alfresco.solr.tracker.IndexHealthReport;
|
import org.alfresco.solr.tracker.IndexHealthReport;
|
||||||
import org.alfresco.solr.tracker.MetadataTracker;
|
import org.alfresco.solr.tracker.MetadataTracker;
|
||||||
|
import org.alfresco.solr.tracker.PropertyRouter;
|
||||||
|
import org.alfresco.solr.tracker.SlaveCoreStatePublisher;
|
||||||
import org.alfresco.solr.tracker.TrackerRegistry;
|
import org.alfresco.solr.tracker.TrackerRegistry;
|
||||||
import org.apache.solr.common.SolrException;
|
import org.apache.solr.common.SolrException;
|
||||||
import org.apache.solr.common.params.CoreAdminParams;
|
import org.apache.solr.common.params.CoreAdminParams;
|
||||||
|
import org.apache.solr.common.params.ModifiableSolrParams;
|
||||||
import org.apache.solr.common.params.SolrParams;
|
import org.apache.solr.common.params.SolrParams;
|
||||||
import org.apache.solr.common.util.NamedList;
|
import org.apache.solr.common.util.NamedList;
|
||||||
|
import org.apache.solr.core.SolrCore;
|
||||||
import org.apache.solr.request.SolrQueryRequest;
|
import org.apache.solr.request.SolrQueryRequest;
|
||||||
import org.apache.solr.response.SolrQueryResponse;
|
import org.apache.solr.response.SolrQueryResponse;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@@ -105,6 +118,169 @@ public class AlfrescoCoreAdminHandlerIT
|
|||||||
when(req.getParams()).thenReturn(params);
|
when(req.getParams()).thenReturn(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void extractShardsWithEmptyParameter_shouldReturnAnEmptyList()
|
||||||
|
{
|
||||||
|
assertTrue(alfrescoCoreAdminHandler.extractShards("", Integer.MAX_VALUE).isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void extractShardsWithNullParameter_shouldReturnAnEmptyList()
|
||||||
|
{
|
||||||
|
assertTrue(alfrescoCoreAdminHandler.extractShards(null, Integer.MAX_VALUE).isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void extractShardsWithOneInvalidShard_shouldReturnAnEmptyList()
|
||||||
|
{
|
||||||
|
assertTrue(alfrescoCoreAdminHandler.extractShards("This is an invalid shard id", Integer.MAX_VALUE).isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void extractShardsWithOneShards_shouldReturnSingletonList()
|
||||||
|
{
|
||||||
|
assertEquals(singletonList(1), alfrescoCoreAdminHandler.extractShards("1", Integer.MAX_VALUE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void extractShardsWithSeveralValidShards_shouldReturnAllOfThemInTheList()
|
||||||
|
{
|
||||||
|
assertEquals(asList(1,5,6,11,23), alfrescoCoreAdminHandler.extractShards("1,5,6,11,23", Integer.MAX_VALUE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void extractShardsWithSeveralValidShards_shouldReturnOnlyValidIdentifiers()
|
||||||
|
{
|
||||||
|
assertEquals(asList(1,5,6,11,23), alfrescoCoreAdminHandler.extractShards("1,5,A,6,xyz,11,BB,23,o01z", Integer.MAX_VALUE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void extractShardsWithSeveralValidShardsAndLimit_shouldConsiderOnlyShardsLesserThanLimit()
|
||||||
|
{
|
||||||
|
assertEquals(asList(1,5,6,11,12), alfrescoCoreAdminHandler.extractShards("1,5,6,11,23,25,99,223,12", 23));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void hasAlfrescoCoreWhenInputIsNull_shouldReturnFalse()
|
||||||
|
{
|
||||||
|
assertFalse(alfrescoCoreAdminHandler.hasAlfrescoCore(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void hasAlfrescoCoreWhenWeHaveNoCore_shouldReturnFalse()
|
||||||
|
{
|
||||||
|
assertFalse(alfrescoCoreAdminHandler.hasAlfrescoCore(emptyList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void hasAlfrescoCoreWhenDoesntHaveAnyTracker_shouldReturnFalse()
|
||||||
|
{
|
||||||
|
assertFalse(alfrescoCoreAdminHandler.hasAlfrescoCore(emptyList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void hasAlfrescoCoreWithRegisteredTrackers_shouldReturnTrue()
|
||||||
|
{
|
||||||
|
when(trackerRegistry.hasTrackersForCore("CoreD")).thenReturn(true);
|
||||||
|
assertTrue(alfrescoCoreAdminHandler.hasAlfrescoCore(asList(dummyCore("CoreA"), dummyCore("CoreB"), dummyCore("CoreC"), dummyCore("CoreD"))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void trackerRegistryHasNoCoreNames_itShouldReturnAnEmptyList()
|
||||||
|
{
|
||||||
|
assertTrue(alfrescoCoreAdminHandler.coreNames().isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void coreDetectedAsMasterOrStandalone()
|
||||||
|
{
|
||||||
|
MetadataTracker coreStatePublisher = mock(MetadataTracker.class);
|
||||||
|
|
||||||
|
when(trackerRegistry.getTrackerForCore(anyString(), eq(MetadataTracker.class)))
|
||||||
|
.thenReturn(coreStatePublisher);
|
||||||
|
|
||||||
|
assertTrue(alfrescoCoreAdminHandler.isMasterOrStandalone("ThisIsTheCoreName"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void coreDetectedAsSlave()
|
||||||
|
{
|
||||||
|
when(trackerRegistry.getTrackerForCore(anyString(), eq(MetadataTracker.class))).thenReturn(null);
|
||||||
|
assertFalse(alfrescoCoreAdminHandler.isMasterOrStandalone("ThisIsTheCoreName"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void coreIsMaster_thenCoreStatePublisherInstanceCorrespondsToMetadataTracker()
|
||||||
|
{
|
||||||
|
MetadataTracker coreStatePublisher = mock(MetadataTracker.class);
|
||||||
|
|
||||||
|
when(trackerRegistry.getTrackerForCore(anyString(), eq(MetadataTracker.class)))
|
||||||
|
.thenReturn(coreStatePublisher);
|
||||||
|
|
||||||
|
assertSame(coreStatePublisher, alfrescoCoreAdminHandler.coreStatePublisher("ThisIsTheCoreName"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void coreIsSlave_thenCoreStatePublisherInstanceCorrespondsToSlaveCoreStatePublisher()
|
||||||
|
{
|
||||||
|
SlaveCoreStatePublisher coreStatePublisher = mock(SlaveCoreStatePublisher.class);
|
||||||
|
|
||||||
|
when(trackerRegistry.getTrackerForCore(anyString(), eq(MetadataTracker.class))).thenReturn(null);
|
||||||
|
when(trackerRegistry.getTrackerForCore(anyString(), eq(SlaveCoreStatePublisher.class))).thenReturn(coreStatePublisher);
|
||||||
|
|
||||||
|
assertSame(coreStatePublisher, alfrescoCoreAdminHandler.coreStatePublisher("ThisIsTheCoreName"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void coreIsSlave_thenDocRouterIsNull()
|
||||||
|
{
|
||||||
|
String coreName = "aCore";
|
||||||
|
when(trackerRegistry.getTrackerForCore(eq(coreName), eq(MetadataTracker.class))).thenReturn(null);
|
||||||
|
assertNull(alfrescoCoreAdminHandler.getDocRouter("aCore"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void coreIsMaster_thenDocRouterIsProperlyReturned()
|
||||||
|
{
|
||||||
|
DocRouter expectedRouter = new PropertyRouter("someProperty_.{1,35}");
|
||||||
|
|
||||||
|
MetadataTracker coreStatePublisher = mock(MetadataTracker.class);
|
||||||
|
when(coreStatePublisher.getDocRouter()).thenReturn(expectedRouter);
|
||||||
|
when(trackerRegistry.getTrackerForCore(anyString(), eq(MetadataTracker.class))).thenReturn(coreStatePublisher);
|
||||||
|
|
||||||
|
assertSame(expectedRouter, alfrescoCoreAdminHandler.getDocRouter("aCore"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void targetCoreNameCanBeSpecifiedInSeveralWays()
|
||||||
|
{
|
||||||
|
String coreName = "ThisIsTheCoreName";
|
||||||
|
|
||||||
|
ModifiableSolrParams params = new ModifiableSolrParams();
|
||||||
|
|
||||||
|
assertNull(alfrescoCoreAdminHandler.coreName(params));
|
||||||
|
|
||||||
|
params.set(CoreAdminParams.CORE, coreName);
|
||||||
|
|
||||||
|
assertEquals(coreName, alfrescoCoreAdminHandler.coreName(params));
|
||||||
|
|
||||||
|
params.remove(CoreAdminParams.CORE);
|
||||||
|
assertNull(alfrescoCoreAdminHandler.coreName(params));
|
||||||
|
|
||||||
|
params.set("coreName", coreName);
|
||||||
|
|
||||||
|
assertEquals(coreName, alfrescoCoreAdminHandler.coreName(params));
|
||||||
|
assertEquals(coreName, alfrescoCoreAdminHandler.coreName(params));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private SolrCore dummyCore(String name)
|
||||||
|
{
|
||||||
|
SolrCore core = mock(SolrCore.class);
|
||||||
|
when(core.getName()).thenReturn(name);
|
||||||
|
return core;
|
||||||
|
}
|
||||||
|
|
||||||
/** Check that a transaction report can be generated. */
|
/** Check that a transaction report can be generated. */
|
||||||
@Test
|
@Test
|
||||||
public void handleCustomActionTXReportSuccess() throws Exception
|
public void handleCustomActionTXReportSuccess() throws Exception
|
||||||
@@ -143,8 +319,6 @@ public class AlfrescoCoreAdminHandlerIT
|
|||||||
public void handleCustomActionTXReportMissingTXId()
|
public void handleCustomActionTXReportMissingTXId()
|
||||||
{
|
{
|
||||||
when(params.get(CoreAdminParams.ACTION)).thenReturn(TXREPORT);
|
when(params.get(CoreAdminParams.ACTION)).thenReturn(TXREPORT);
|
||||||
when(params.get(ARG_TXID)).thenReturn(null);
|
|
||||||
|
|
||||||
alfrescoCoreAdminHandler.handleCustomAction(req, rsp);
|
alfrescoCoreAdminHandler.handleCustomAction(req, rsp);
|
||||||
|
|
||||||
verify(rsp, never()).add(anyString(), any());
|
verify(rsp, never()).add(anyString(), any());
|
||||||
@@ -156,11 +330,8 @@ public class AlfrescoCoreAdminHandlerIT
|
|||||||
{
|
{
|
||||||
when(params.get(CoreAdminParams.ACTION)).thenReturn(TXREPORT);
|
when(params.get(CoreAdminParams.ACTION)).thenReturn(TXREPORT);
|
||||||
when(params.get(CoreAdminParams.CORE)).thenReturn(null);
|
when(params.get(CoreAdminParams.CORE)).thenReturn(null);
|
||||||
when(params.get(ARG_TXID)).thenReturn(TX_ID);
|
|
||||||
|
|
||||||
alfrescoCoreAdminHandler.handleCustomAction(req, rsp);
|
alfrescoCoreAdminHandler.handleCustomAction(req, rsp);
|
||||||
|
|
||||||
verify(rsp, never()).add(anyString(), any());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Check that when an unknown action is provided we don't generate a report. */
|
/** Check that when an unknown action is provided we don't generate a report. */
|
||||||
@@ -212,10 +383,9 @@ public class AlfrescoCoreAdminHandlerIT
|
|||||||
public void coreNamesAreTrimmed_oneCoreNameAtTime() {
|
public void coreNamesAreTrimmed_oneCoreNameAtTime() {
|
||||||
AlfrescoCoreAdminHandler spy = spy(new AlfrescoCoreAdminHandler() {
|
AlfrescoCoreAdminHandler spy = spy(new AlfrescoCoreAdminHandler() {
|
||||||
@Override
|
@Override
|
||||||
protected boolean newCore(String coreName, int numShards, StoreRef storeRef, String templateName, int replicationFactor, int nodeInstance, int numNodes, String shardIds, Properties extraProperties, SolrQueryResponse rsp)
|
protected void newCore(String coreName, int numShards, StoreRef storeRef, String templateName, int replicationFactor, int nodeInstance, int numNodes, String shardIds, Properties extraProperties, SolrQueryResponse rsp)
|
||||||
{
|
{
|
||||||
// Do nothing here otherwise we cannot spy it
|
// Do nothing here otherwise we cannot spy it
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -238,10 +408,9 @@ public class AlfrescoCoreAdminHandlerIT
|
|||||||
public void validAndInvalidCoreNames() {
|
public void validAndInvalidCoreNames() {
|
||||||
AlfrescoCoreAdminHandler spy = spy(new AlfrescoCoreAdminHandler() {
|
AlfrescoCoreAdminHandler spy = spy(new AlfrescoCoreAdminHandler() {
|
||||||
@Override
|
@Override
|
||||||
protected boolean newCore(String coreName, int numShards, StoreRef storeRef, String templateName, int replicationFactor, int nodeInstance, int numNodes, String shardIds, Properties extraProperties, SolrQueryResponse rsp)
|
protected void newCore(String coreName, int numShards, StoreRef storeRef, String templateName, int replicationFactor, int nodeInstance, int numNodes, String shardIds, Properties extraProperties, SolrQueryResponse rsp)
|
||||||
{
|
{
|
||||||
// Do nothing here otherwise we cannot spy it
|
// Do nothing here otherwise we cannot spy it
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user