pulling from master

This commit is contained in:
Keerat
2019-11-13 13:28:44 +00:00
107 changed files with 3064 additions and 2329 deletions
@@ -54,7 +54,6 @@ ENV MASTER_HOST $MASTER_HOST
# Set Master / Slave configuration for this Node
RUN if [ "$ENABLE_MASTER" == "true" ] ; then \
sed -i '/^bash.*/i echo "\nenable.master=${ENABLE_MASTER}\nenable.slave=${ENABLE_SLAVE}" >> ${DIST_DIR}/solrhome/templates/rerank/conf/solrcore.properties\n' \
${DIST_DIR}/solr/bin/search_config_setup.sh; \
sed -i "/^bash.*/i sed -i '/^\\\\\s*<requestHandler name=\"\\\\/replication\".*/a \
<lst name=\"master\">\
@@ -64,7 +63,6 @@ RUN if [ "$ENABLE_MASTER" == "true" ] ; then \
</lst>' ${DIST_DIR}/solrhome/templates/rerank/conf/solrconfig.xml\n" ${DIST_DIR}/solr/bin/search_config_setup.sh; \
fi
RUN if [ "$ENABLE_SLAVE" == "true" ] ; then \
sed -i '/^bash.*/i echo "\nenable.master=${ENABLE_MASTER}\nenable.slave=${ENABLE_SLAVE}" >> ${DIST_DIR}/solrhome/templates/rerank/conf/solrcore.properties\n' \
${DIST_DIR}/solr/bin/search_config_setup.sh; \
sed -i "/^bash.*/i sed -i '/^\\\\\s*<requestHandler name=\"\\\\/replication\".*/a \
<lst name=\"slave\">\
@@ -131,4 +129,4 @@ fi
RUN mkdir ${DIST_DIR}/keystore \
&& chown -R solr:solr ${DIST_DIR}/keystore
VOLUME ["${DIST_DIR}/keystore"]
VOLUME ["${DIST_DIR}/keystore"]
+2 -4
View File
@@ -13,10 +13,8 @@
<properties>
<tas.rest.api.version>6.0.1.2</tas.rest.api.version>
<tas.cmis.api.version>6.0.0.4</tas.cmis.api.version>
<tas.utility.version>3.0.11</tas.utility.version>
<!-- GS V3.2-0-SNAPSHOT will have to be used for GS-IE automation tests due to the dependencies in TAS Rest API project
This version needs to be later updated when GS V3.2-0 is released -->
<rm.version>3.2.0-SNAPSHOT</rm.version>
<tas.utility.version>3.0.14</tas.utility.version>
<rm.version>3.2.0</rm.version>
<suiteXmlFile>src/test/resources/SearchSuite.xml</suiteXmlFile>
<test.exclude></test.exclude>
<test.include></test.include>
@@ -29,6 +29,7 @@ import org.alfresco.utility.model.UserModel;
import org.alfresco.utility.network.ServerHealth;
import org.apache.chemistry.opencmis.client.api.CmisObject;
import org.apache.chemistry.opencmis.client.api.Session;
import org.hamcrest.Matchers;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
@@ -39,6 +40,7 @@ import org.testng.annotations.BeforeSuite;
import lombok.Getter;
import static java.util.Optional.ofNullable;
import static lombok.AccessLevel.PROTECTED;
/**
@@ -85,6 +87,14 @@ public abstract class AbstractE2EFunctionalTest extends AbstractTestNGSpringCont
protected SiteModel testSite;
protected static String unique_searchString;
protected static final String SEARCH_LANGUAGE_CMIS = "cmis";
protected enum SearchLanguage {
CMIS,
AFTS
}
@BeforeSuite(alwaysRun = true)
public void beforeSuite() throws Exception
@@ -399,16 +409,45 @@ public abstract class AbstractE2EFunctionalTest extends AbstractTestNGSpringCont
* @param userQuery
* @return
*/
protected SearchResponse runSearchSpellcheckQuery(String query, String userQuery)
{
SearchRequest searchReq = new SearchRequest();
protected SearchResponse SearchSpellcheckQuery(UserModel user, String query, String userQuery)
{
UserModel searchUser = ofNullable(user).isPresent()? user: testUser;
SearchRequest searchReq = new SearchRequest();
RestRequestQueryModel queryReq = new RestRequestQueryModel();
queryReq.setQuery(query);
queryReq.setUserQuery(userQuery);
searchReq.setQuery(queryReq);
searchReq.setSpellcheck(new RestRequestSpellcheckModel());
SearchResponse response = query(searchReq);
searchReq.setSpellcheck(new org.alfresco.rest.model.RestRequestSpellcheckModel());
SearchResponse response = queryAsUser(searchUser, queryReq);
return response;
}
/**
* Helper method to test if the search query works and count matches where provided
* @param query: AFTS or cmis query string
* @param expectedCount: Only successful response is checked, when expectedCount is null (can not be exactly specified),
* @param setCmis: Query language is set to cmis when setCmis is true, AFTS when false
* @return SearchResponse
*/
protected SearchResponse testSearchQuery(String query, Integer expectedCount, SearchLanguage queryLanguage)
{
RestRequestQueryModel queryModel = new RestRequestQueryModel();
queryModel.setQuery(query);
if (ofNullable(queryLanguage).isPresent())
{
queryModel.setLanguage(queryLanguage.toString());
}
SearchResponse response = queryAsUser(testUser, queryModel);
restClient.assertStatusCodeIs(HttpStatus.OK);
if (ofNullable(expectedCount).isPresent())
{
restClient.onResponse().assertThat().body("list.pagination.count", Matchers.equalTo(expectedCount));
}
return response;
}
}
@@ -170,24 +170,24 @@ public class SearchSpellCheckTest extends AbstractSearchServicesE2ETest
waitForIndexing(file.getName(), true);
// Correct spelling with cm:name field
SearchResponse response = runSearchSpellcheckQuery("cm:name:learning", "learning");
SearchResponse response = SearchSpellcheckQuery(testUser, "cm:name:learning", "learning");
response.assertThat().entriesListIsNotEmpty();
response.getContext().assertThat().field("spellCheck").isNull();
// Correct spelling with no field
response = runSearchSpellcheckQuery("learning", "learning");
response = SearchSpellcheckQuery(testUser, "learning", "learning");
response.assertThat().entriesListIsNotEmpty();
response.getContext().assertThat().field("spellCheck").isNull();
// Correct spelling with a different field. Used cm:content field
response = runSearchSpellcheckQuery("cm:content:learning", "learning");
response = SearchSpellcheckQuery(testUser, "cm:content:learning", "learning");
response.assertThat().entriesListIsEmpty();
// Incorrect spelling with cm:name field
response = runSearchSpellcheckQuery("cm:name:lerning", "lerning");
response = SearchSpellcheckQuery(testUser, "cm:name:lerning", "lerning");
response.assertThat().entriesListIsNotEmpty();
response.getContext().assertThat().field("spellCheck").isNotEmpty();
@@ -195,7 +195,7 @@ public class SearchSpellCheckTest extends AbstractSearchServicesE2ETest
response.getContext().getSpellCheck().assertThat().field("type").is("searchInsteadFor");
// Incorrect spelling with no field
response = runSearchSpellcheckQuery("lerning", "lerning");
response = SearchSpellcheckQuery(testUser, "lerning", "lerning");
response.assertThat().entriesListIsNotEmpty();
response.getContext().assertThat().field("spellCheck").isNotEmpty();
@@ -203,7 +203,7 @@ public class SearchSpellCheckTest extends AbstractSearchServicesE2ETest
response.getContext().getSpellCheck().assertThat().field("type").is("searchInsteadFor");
// Incorrect spelling with a different field. Used cm:content field
response = runSearchSpellcheckQuery("cm:content:lerning", "lerning");
response = SearchSpellcheckQuery(testUser, "cm:content:lerning", "lerning");
response.assertThat().entriesListIsEmpty();
@@ -220,7 +220,7 @@ public class SearchSpellCheckTest extends AbstractSearchServicesE2ETest
waitForContentIndexing(file3.getContent(), true);
// Incorrect spelling with cm:name field
response = runSearchSpellcheckQuery("cm:name:lerning", "lerning");
response = SearchSpellcheckQuery(testUser, "cm:name:lerning", "lerning");
response.assertThat().entriesListIsNotEmpty();
response.getContext().assertThat().field("spellCheck").isNotEmpty();
@@ -228,7 +228,7 @@ public class SearchSpellCheckTest extends AbstractSearchServicesE2ETest
response.getContext().getSpellCheck().assertThat().field("type").is("searchInsteadFor");
// Incorrect spelling with no field
response = runSearchSpellcheckQuery("lerning", "lerning");
response = SearchSpellcheckQuery(testUser, "lerning", "lerning");
response.assertThat().entriesListIsNotEmpty();
response.getContext().assertThat().field("spellCheck").isNotEmpty();
@@ -236,7 +236,7 @@ public class SearchSpellCheckTest extends AbstractSearchServicesE2ETest
response.getContext().getSpellCheck().assertThat().field("type").is("searchInsteadFor");
// Incorrect spelling with cm:content field
response = runSearchSpellcheckQuery("cm:content:lerning", "lerning");
response = SearchSpellcheckQuery(testUser, "cm:content:lerning", "lerning");
response.assertThat().entriesListIsNotEmpty();
response.getContext().assertThat().field("spellCheck").isNotEmpty();
@@ -244,7 +244,7 @@ public class SearchSpellCheckTest extends AbstractSearchServicesE2ETest
response.getContext().getSpellCheck().assertThat().field("type").is("searchInsteadFor");
// Correct spelling with cm:name field
response = runSearchSpellcheckQuery("cm:name:learning", "learning");
response = SearchSpellcheckQuery(testUser, "cm:name:learning", "learning");
response.assertThat().entriesListIsNotEmpty();
response.getContext().assertThat().field("spellCheck").isNotEmpty();
@@ -252,7 +252,7 @@ public class SearchSpellCheckTest extends AbstractSearchServicesE2ETest
response.getContext().getSpellCheck().assertThat().field("type").is("didYouMean");
// Correct spelling with no field
response = runSearchSpellcheckQuery("learning", "learning");
response = SearchSpellcheckQuery(testUser, "learning", "learning");
response.assertThat().entriesListIsNotEmpty();
response.getContext().assertThat().field("spellCheck").isNotEmpty();
@@ -260,7 +260,7 @@ public class SearchSpellCheckTest extends AbstractSearchServicesE2ETest
response.getContext().getSpellCheck().assertThat().field("type").is("didYouMean");
// Correct spelling with cm:content field
response = runSearchSpellcheckQuery("cm:content:learning", "learning");
response = SearchSpellcheckQuery(testUser, "cm:content:learning", "learning");
response.assertThat().entriesListIsNotEmpty();
response.getContext().assertThat().field("spellCheck").isNotEmpty();
@@ -288,13 +288,13 @@ public class SearchSpellCheckTest extends AbstractSearchServicesE2ETest
waitForContentIndexing(file2.getContent(), true);
// Search with field not filed in either files
SearchResponse response = runSearchSpellcheckQuery("cm:description:eclipse", "eclipse");
SearchResponse response = SearchSpellcheckQuery(testUser, "cm:description:eclipse", "eclipse");
response.assertThat().entriesListIsEmpty();
response.getContext().assertThat().field("spellCheck").isNull();
// Incorrect spelling with the field on a file as well
response = runSearchSpellcheckQuery("cm:name:eclipse", "eclipse");
response = SearchSpellcheckQuery(testUser, "cm:name:eclipse", "eclipse");
response.assertThat().entriesListIsNotEmpty();
response.getContext().assertThat().field("spellCheck").isNotEmpty();
@@ -302,7 +302,7 @@ public class SearchSpellCheckTest extends AbstractSearchServicesE2ETest
response.getContext().getSpellCheck().assertThat().field("type").is("searchInsteadFor");
// Incorrect spelling with no field for file1
response = runSearchSpellcheckQuery("eclipse", "eclipse");
response = SearchSpellcheckQuery(testUser, "eclipse", "eclipse");
response.assertThat().entriesListIsNotEmpty();
response.getContext().assertThat().field("spellCheck").isNotEmpty();
@@ -310,7 +310,7 @@ public class SearchSpellCheckTest extends AbstractSearchServicesE2ETest
response.getContext().getSpellCheck().assertThat().field("type").is("searchInsteadFor");
// Incorrect spelling with no field for file2
response = runSearchSpellcheckQuery("eclipses", "eclipses");
response = SearchSpellcheckQuery(testUser, "eclipses", "eclipses");
response.assertThat().entriesListIsNotEmpty();
response.getContext().assertThat().field("spellCheck").isNotEmpty();
@@ -318,7 +318,7 @@ public class SearchSpellCheckTest extends AbstractSearchServicesE2ETest
response.getContext().getSpellCheck().assertThat().field("type").is("searchInsteadFor");
// Search for the field only filed on file2 and not file1
response = runSearchSpellcheckQuery("cm:title:eclipses", "eclipses");
response = SearchSpellcheckQuery(testUser, "cm:title:eclipses", "eclipses");
response.assertThat().entriesListIsNotEmpty();
response.getContext().assertThat().field("spellCheck").isNotEmpty();
@@ -326,13 +326,13 @@ public class SearchSpellCheckTest extends AbstractSearchServicesE2ETest
response.getContext().getSpellCheck().assertThat().field("type").is("searchInsteadFor");
// Query using 3 edits (more than spellcheck works for [maxEdits<=2])
response = runSearchSpellcheckQuery("elapssed", "elapssed");
response = SearchSpellcheckQuery(testUser, "elapssed", "elapssed");
response.assertThat().entriesListIsEmpty();
response.getContext().assertThat().field("spellCheck").isNull();
// Query with edit on first letter (does not work with spellcheck [minPrefix=1])
response = runSearchSpellcheckQuery("iklipse ", "iklipse ");
response = SearchSpellcheckQuery(testUser, "iklipse ", "iklipse ");
response.assertThat().entriesListIsEmpty();
response.getContext().assertThat().field("spellCheck").isNull();
@@ -354,7 +354,7 @@ public class SearchSpellCheckTest extends AbstractSearchServicesE2ETest
waitForContentIndexing(file.getContent(), true);
// Incorrect spelling with no field
SearchResponse response = runSearchSpellcheckQuery("b00k", "b00k");
SearchResponse response = SearchSpellcheckQuery(testUser, "b00k", "b00k");
response.assertThat().entriesListIsNotEmpty();
response.getContext().assertThat().field("spellCheck").isNotEmpty();
@@ -362,7 +362,7 @@ public class SearchSpellCheckTest extends AbstractSearchServicesE2ETest
response.getContext().getSpellCheck().assertThat().field("type").is("searchInsteadFor");
// Incorrect spelling with the cm:name field
response = runSearchSpellcheckQuery("cm:name:b00k", "b00k");
response = SearchSpellcheckQuery(testUser, "cm:name:b00k", "b00k");
response.assertThat().entriesListIsNotEmpty();
response.getContext().assertThat().field("spellCheck").isNotEmpty();
@@ -370,7 +370,7 @@ public class SearchSpellCheckTest extends AbstractSearchServicesE2ETest
response.getContext().getSpellCheck().assertThat().field("type").is("searchInsteadFor");
// Incorrect spelling with the cm:title field
response = runSearchSpellcheckQuery("cm:title:b00k", "b00k");
response = SearchSpellcheckQuery(testUser, "cm:title:b00k", "b00k");
response.assertThat().entriesListIsNotEmpty();
response.getContext().assertThat().field("spellCheck").isNotEmpty();
@@ -378,7 +378,7 @@ public class SearchSpellCheckTest extends AbstractSearchServicesE2ETest
response.getContext().getSpellCheck().assertThat().field("type").is("searchInsteadFor");
// Incorrect spelling with the cm:description field
response = runSearchSpellcheckQuery("cm:description:b00k", "b00k");
response = SearchSpellcheckQuery(testUser, "cm:description:b00k", "b00k");
response.assertThat().entriesListIsNotEmpty();
response.getContext().assertThat().field("spellCheck").isNotEmpty();
@@ -386,7 +386,7 @@ public class SearchSpellCheckTest extends AbstractSearchServicesE2ETest
response.getContext().getSpellCheck().assertThat().field("type").is("searchInsteadFor");
// Incorrect spelling with the cm:description field
response = runSearchSpellcheckQuery("cm:content:b00k", "b00k");
response = SearchSpellcheckQuery(testUser, "cm:content:b00k", "b00k");
response.assertThat().entriesListIsNotEmpty();
response.getContext().assertThat().field("spellCheck").isNotEmpty();
@@ -395,7 +395,7 @@ public class SearchSpellCheckTest extends AbstractSearchServicesE2ETest
// Incorrect spelling with the cm:author field (not a field in shared.properties
// for spellcheck)
response = runSearchSpellcheckQuery("cm:author:b00k", "b00k");
response = SearchSpellcheckQuery(testUser, "cm:author:b00k", "b00k");
response.assertThat().entriesListIsEmpty();
response.getContext().assertThat().field("spellCheck").isNull();
+14 -1
View File
@@ -29,7 +29,7 @@
<properties>
<java.version>11</java.version>
<solr.base.version>6.6.5</solr.base.version>
<solr.version>${solr.base.version}-patched</solr.version>
<solr.version>${solr.base.version}-patched.1</solr.version>
<!-- The location to download the solr zip file from. -->
<!-- <solr.zip>https://archive.apache.org/dist/lucene/solr/${solr.version}/solr-${solr.version}.zip</solr.zip> -->
<!-- Solr startup scripts do not work with any Java version higher than 9 so the scripts have been patched -->
@@ -54,6 +54,19 @@
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.22.2</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
@@ -150,8 +150,6 @@ The following table illustrates the configuration properties used by the Tracker
|alfresco.stores|workspace://SpacesStore|The reference to a node store| | |Y|Y| | |
|batch.count|5000|UpSert batch size (e.g. metadata docs, acls)| | |Y|Y| | |
|alfresco.maxLiveSearchers|2|Max allowed number of active searchers|Y| |Y|Y| | |
|enable.slave|false|Indicates if the hosting instance is a slave| | |Y|Y| | |
|enable.master|true|Indicates if the hosting instance is a master| | |Y|Y| | |
|shard.count|1|The total number of shards that compose the Solr infrastructure|| |Y|Y| | |
|shard.instance|0|The unique shard identifier assigned to this instance|| |Y|Y| | |
|shard.method|"DB_ID"|Data (Documents, ACLs) Routing criteria among shards| | |Y|Y| | |
+2 -2
View File
@@ -120,7 +120,7 @@
<dependency>
<groupId>com.carrotsearch.randomizedtesting</groupId>
<artifactId>randomizedtesting-runner</artifactId>
<version>2.7.3</version>
<version>2.7.4</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -292,7 +292,7 @@
</goals>
<configuration>
<excludes>
<exclude>**/AnnotationWriter.*</exclude>
<exclude>**/libs/*</exclude>
</excludes>
<!-- Sets the path to the file which contains the execution data. -->
<dataFile>${project.build.directory}/coverage-reports/jacoco-ut.exec</dataFile>
@@ -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);
}
}
@@ -40,6 +40,8 @@ import org.apache.solr.handler.component.ResponseBuilder;
import org.apache.solr.handler.component.SearchComponent;
import org.apache.solr.handler.component.ShardRequest;
import org.apache.solr.request.SolrQueryRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
@@ -49,6 +51,8 @@ import org.apache.solr.request.SolrQueryRequest;
*/
public class RewriteFacetParametersComponent extends SearchComponent
{
private static final Logger log = LoggerFactory.getLogger(RewriteFacetParametersComponent.class);
/* (non-Javadoc)
* @see org.apache.solr.handler.component.SearchComponent#prepare(org.apache.solr.handler.component.ResponseBuilder)
*/
@@ -439,7 +443,13 @@ public class RewriteFacetParametersComponent extends SearchComponent
Map<String, String> fieldMappings, SolrQueryRequest req)
{
String shardPurpose = req.getParams().get(ShardParams.SHARDS_PURPOSE);
boolean isRefinementRequest = (shardPurpose!=null)?(shardPurpose.equals(String.valueOf(ShardRequest.PURPOSE_REFINE_FACETS))) || (shardPurpose.equals(String.valueOf(ShardRequest.PURPOSE_REFINE_PIVOT_FACETS))):false;
boolean isRefinementRequest = false;
//Fix for https://issues.alfresco.com/jira/browse/MNT-21015
if (shardPurpose != null) {
int shardPurposeCode = Integer.parseInt(shardPurpose);
log.debug("ShardPurpose: " + shardPurpose);
isRefinementRequest = ((shardPurposeCode & ShardRequest.PURPOSE_REFINE_FACETS) != 0) || ((shardPurposeCode & ShardRequest.PURPOSE_REFINE_PIVOT_FACETS) != 0);
}
String[] facetFieldsOrig = params.getParams(paramName);
List<String> facetFieldList = new ArrayList<>();
if(facetFieldsOrig != null)
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2005-2016 Alfresco Software Limited.
* Copyright (C) 2005-2019 Alfresco Software Limited.
*
* This file is part of Alfresco
*
@@ -16,31 +16,423 @@
* 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.lifecycle;
import static java.util.Arrays.asList;
import static java.util.Optional.ofNullable;
import org.alfresco.opencmis.dictionary.CMISStrictDictionaryService;
import org.alfresco.solr.AlfrescoCoreAdminHandler;
import org.alfresco.solr.AlfrescoSolrDataModel;
import org.alfresco.solr.SolrInformationServer;
import org.alfresco.solr.SolrKeyResourceLoader;
import org.alfresco.solr.client.SOLRAPIClient;
import org.alfresco.solr.client.SOLRAPIClientFactory;
import org.alfresco.solr.content.SolrContentStore;
import org.alfresco.solr.tracker.AclTracker;
import org.alfresco.solr.tracker.CascadeTracker;
import org.alfresco.solr.tracker.CommitTracker;
import org.alfresco.solr.tracker.ContentTracker;
import org.alfresco.solr.tracker.MetadataTracker;
import org.alfresco.solr.tracker.ModelTracker;
import org.alfresco.solr.tracker.SlaveCoreStatePublisher;
import org.alfresco.solr.tracker.SolrTrackerScheduler;
import org.alfresco.solr.tracker.Tracker;
import org.alfresco.solr.tracker.TrackerRegistry;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.StrUtils;
import org.apache.solr.core.AbstractSolrEventListener;
import org.apache.solr.core.CloseHook;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.core.CoreDescriptorDecorator;
import org.apache.solr.core.PluginInfo;
import org.apache.solr.core.SolrCore;
import org.apache.solr.core.SolrResourceLoader;
import org.apache.solr.handler.ReplicationHandler;
import org.apache.solr.request.SolrRequestHandler;
import org.apache.solr.search.SolrIndexSearcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import java.util.function.Function;
import java.util.function.Predicate;
/**
* Listens for the first searcher to be created for a core and registers the trackers
* Listeners for *FIRST SEARCHER* events in order to prepare and register the SolrContentStore and the Tracking Subsystem.
*
* @author Gethin James
* @author Andrea Gazzarini
*/
public class SolrCoreLoadListener extends AbstractSolrEventListener {
public class SolrCoreLoadListener extends AbstractSolrEventListener
{
private static final Logger LOGGER = LoggerFactory.getLogger(SolrCoreLoadListener.class);
public SolrCoreLoadListener(SolrCore core) {
/**
* Builds a new listener instance with the given {@link SolrCore} (event source).
*
* @param core the {@link SolrCore} instance representing the event source of this listener.
*/
public SolrCoreLoadListener(SolrCore core)
{
super(core);
}
@Override
public void newSearcher(SolrIndexSearcher newSearcher, SolrIndexSearcher currentSearcher) {
CoreContainer coreContainer = getCore().getCoreContainer();
AlfrescoCoreAdminHandler coreAdminHandler = (AlfrescoCoreAdminHandler) coreContainer.getMultiCoreHandler();
public void newSearcher(SolrIndexSearcher newSearcher, SolrIndexSearcher currentSearcher)
{
if (getCore().isReloaded())
{
LOGGER.info("Solr Core {}, instance {} has been reloaded. " +
"The previous tracking subsystem will be stopped and another set of trackers will be registered on this new instance.",
getCore().getName(),
getCore().hashCode());
}
else
{
LOGGER.info("Solr Core {}, instance {}, has been registered for the first time.",
getCore().getName(),
getCore().hashCode());
}
SolrCoreLoadRegistration.registerForCore(coreAdminHandler, coreContainer, getCore(), getCore().getName());
CoreContainer coreContainer = getCore().getCoreContainer();
AlfrescoCoreAdminHandler admin = (AlfrescoCoreAdminHandler) coreContainer.getMultiCoreHandler();
SolrCore core = getCore();
TrackerRegistry trackerRegistry = admin.getTrackerRegistry();
Properties coreProperties = new CoreDescriptorDecorator(core.getCoreDescriptor()).getProperties();
SolrResourceLoader loader = core.getLatestSchema().getResourceLoader();
SolrKeyResourceLoader keyResourceLoader = new SolrKeyResourceLoader(loader);
SOLRAPIClientFactory clientFactory = new SOLRAPIClientFactory();
SOLRAPIClient repositoryClient =
clientFactory.getSOLRAPIClient(coreProperties, keyResourceLoader,
AlfrescoSolrDataModel.getInstance().getDictionaryService(CMISStrictDictionaryService.DEFAULT),
AlfrescoSolrDataModel.getInstance().getNamespaceDAO());
SolrContentStore contentStore = new SolrContentStore(coreContainer.getSolrHome());
SolrInformationServer informationServer = new SolrInformationServer(admin, core, repositoryClient, contentStore);
coreProperties.putAll(informationServer.getProps());
admin.getInformationServers().put(core.getName(), informationServer);
final SolrTrackerScheduler scheduler = admin.getScheduler();
// Prevents other threads from registering the ModelTracker at the same time
// Create model tracker and load all the persisted models
synchronized(SolrCoreLoadListener.class)
{
createModelTracker(core.getName(),
trackerRegistry,
coreProperties,
coreContainer.getSolrHome(),
repositoryClient,
informationServer,
scheduler);
}
/*
* The shutdown hook needs to be registered regardless we are slave or masters.
* This because if we are master all trackers will be scheduled, if we are slave the node state publisher
* will be scheduled.
*
* As consequence of that, regardless the node role, we will always have something to shutdown in the tracker
* registry.
*/
final List<Tracker> trackers = new ArrayList<>();
core.addCloseHook(new CloseHook()
{
@Override
public void preClose(SolrCore core)
{
LOGGER.info("Solr Core instance {} with name {} is going to be closed. Tracking Subsystem shutdown callback procedure has been started.", core.hashCode(), core.getName());
// IMPORTANT: the closure needs to be created with the trackers created in this method
shutdownTrackers(core, trackers, scheduler, false);
}
@Override
public void postClose(SolrCore core)
{
LOGGER.info("Solr Core instance {} with name {} has been closed. Tracking Subsystem shutdown callback procedure has been completed.", core.hashCode(), core.getName());
}
});
boolean trackersHaveBeenEnabled = Boolean.parseBoolean(coreProperties.getProperty("enable.alfresco.tracking", "true"));
boolean owningCoreIsSlave = isSlaveModeEnabledFor(core);
if (trackerRegistry.hasTrackersForCore(core.getName()))
{
LOGGER.info("Trackers (it could be only the node state publisher in case this node is a slave) for " + core.getName() + " are already registered, shutting them down.");
Collection<Tracker> alreadyRegisteredTrackers = trackerRegistry.getTrackersForCore(core.getName());
trackerRegistry.removeTrackersForCore(core.getName());
shutdownTrackers(core, alreadyRegisteredTrackers, scheduler, core.isReloaded());
admin.getInformationServers().remove(core.getName());
}
// Re-put the information server in the map because a Core reload (see above) could have removed the reference.
admin.getInformationServers().put(core.getName(), informationServer);
// Guard conditions: if trackers must be disabled then immediately return, we've done here.
// Case #1: trackers have been explicitly disabled.
if (!trackersHaveBeenEnabled)
{
LOGGER.info("SearchServices Core Trackers have been explicitly disabled on core \"{}\" through \"enable.alfresco.tracking\" configuration property.", core.getName());
SlaveCoreStatePublisher statePublisher = new SlaveCoreStatePublisher(false, coreProperties, repositoryClient, core.getName(), informationServer);
trackerRegistry.register(core.getName(), statePublisher);
scheduler.schedule(statePublisher, core.getName(), coreProperties);
trackers.add(statePublisher);
LOGGER.info("SearchServices Slave Node Provider have been created and scheduled for core \"{}\".", core.getName());
return;
}
// Case #2: we are on a slave node.
if (owningCoreIsSlave)
{
LOGGER.info("SearchServices Core Trackers have been disabled on core \"{}\" because it is a slave core.", core.getName());
SlaveCoreStatePublisher statePublisher = new SlaveCoreStatePublisher(false, coreProperties, repositoryClient, core.getName(), informationServer);
trackerRegistry.register(core.getName(), statePublisher);
scheduler.schedule(statePublisher, core.getName(), coreProperties);
trackers.add(statePublisher);
LOGGER.info("SearchServices Slave Node Provider have been created and scheduled for Core instance {} with name {}.", core.hashCode(), core.getName());
return;
}
LOGGER.info("SearchServices Tracking Subsystem starts on Solr Core instance {} with name {}", core.hashCode(), core.getName());
trackers.addAll(createAndScheduleCoreTrackers(core, trackerRegistry, coreProperties, scheduler, repositoryClient, informationServer));
CommitTracker commitTracker = new CommitTracker(coreProperties, repositoryClient, core.getName(), informationServer, trackers);
trackerRegistry.register(core.getName(), commitTracker);
scheduler.schedule(commitTracker, core.getName(), coreProperties);
LOGGER.info("Tracker {}, instance {}, belonging to Core {}, instance {} has been registered and scheduled.",
commitTracker.getClass().getSimpleName(),
commitTracker.hashCode(),
core.getName(),
core.hashCode());
//Add the commitTracker to the list of scheduled trackers that can be shutdown
trackers.add(commitTracker);
}
}
List<Tracker> createAndScheduleCoreTrackers(SolrCore core,
TrackerRegistry trackerRegistry,
Properties props,
SolrTrackerScheduler scheduler,
SOLRAPIClient repositoryClient,
SolrInformationServer srv)
{
AclTracker aclTracker =
registerAndSchedule(
new AclTracker(props, repositoryClient, core.getName(), srv),
core,
props,
trackerRegistry,
scheduler);
ContentTracker contentTracker =
registerAndSchedule(
new ContentTracker(props, repositoryClient, core.getName(), srv),
core,
props,
trackerRegistry,
scheduler);
MetadataTracker metadataTracker =
registerAndSchedule(
new MetadataTracker(true, props, repositoryClient, core.getName(), srv),
core,
props,
trackerRegistry,
scheduler);
CascadeTracker cascadeTracker =
registerAndSchedule(
new CascadeTracker(props, repositoryClient, core.getName(), srv),
core,
props,
trackerRegistry,
scheduler);
//The CommitTracker will acquire these locks in order
//The ContentTracker will likely have the longest runs so put it first to ensure the MetadataTracker is not paused while
//waiting for the ContentTracker to release it's lock.
//The aclTracker will likely have the shortest runs so put it last.
return asList(cascadeTracker, contentTracker, metadataTracker, aclTracker);
}
/**
* Accepts a {@link Tracker} instance, registers and schedules it.
*
* @param tracker the tracker that will be scheduled and registered.
* @param core the owning core.
* @param properties configuration properties.
* @param registry the tracker registry instance.
* @param scheduler the tracker schedule instance.
* @param <T> the tracker instance.
* @return the registered and scheduled tracker instance.
*/
private <T extends Tracker> T registerAndSchedule(T tracker, SolrCore core, Properties properties, TrackerRegistry registry, SolrTrackerScheduler scheduler)
{
registry.register(core.getName(), tracker);
scheduler.schedule(tracker, core.getName(), properties);
LOGGER.info("Tracker {}, instance {}, belonging to Core {}, instance {} has been registered and scheduled.",
tracker.getClass().getSimpleName(),
tracker.hashCode(),
core.getName(),
core.hashCode());
return tracker;
}
private void createModelTracker(String coreName,
TrackerRegistry trackerRegistry,
Properties props,
String solrHome,
SOLRAPIClient repositoryClient,
SolrInformationServer srv,
SolrTrackerScheduler scheduler)
{
ModelTracker mTracker = trackerRegistry.getModelTracker();
if (mTracker == null)
{
LOGGER.debug("Creating a new Model Tracker instance.");
mTracker = new ModelTracker(solrHome, props, repositoryClient, coreName, srv);
trackerRegistry.setModelTracker(mTracker);
LOGGER.info("Model Tracker: ensuring first model sync.");
mTracker.ensureFirstModelSync();
scheduler.schedule(mTracker, coreName, props);
LOGGER.info("Model Tracker has been correctly initialised, registered and scheduled.");
}
}
/**
* Shuts down the trackers for a core.
*
* The trackers are only deleted from the scheduler if they are the exact same instance of the Tracker class
* passed into this method.
* For example, you could have 2 cores of the same name and have the trackers registered with the scheduler BUT
* the scheduler only keys by core name. The Collection<Tracker>s passed into this method are only removed
* from the scheduler if the instances are == (equal). See scheduler.deleteJobForTrackerInstance()
*
* Trackers are not removed from the registry because the registry only keys by core name; its possible to
* have multiple cores of the same name running. Left over trackers in the registry are cleaned up by the CoreContainer
* shutdown, that happens in the the AlfrescoCoreAdminHandler.shutdown().
*
* The coreHasBeenReloaded flag is used just for logging out meaningful messages about the owning core instance.
* If we are in a RELOAD scenario (coreHasBeenReloaded = true) we no longer have the reference of the closed core
* so we print only its name. Instead in case we are here because a core has been closed, we can print out the core
* reference in order to add meaningful information in the log.
*
* @param core The owning core name.
* @param coreTrackers A collection of trackers
* @param scheduler The scheduler
* @param coreHasBeenReloaded a flag indicating if we are on a Core RELOAD scenario.
*/
void shutdownTrackers(SolrCore core, Collection<Tracker> coreTrackers, SolrTrackerScheduler scheduler, boolean coreHasBeenReloaded)
{
coreTrackers.forEach(tracker -> shutdownTracker(core, tracker, scheduler, coreHasBeenReloaded));
}
/**
* Shutdown procedure for a single tracker.
* The coreHasBeenReloaded flag is used just for logging out meaningful messages about the owning core instance.
* If we are in a RELOAD scenario (coreHasBeenReloaded = true) we no longer have the reference of the closed core
* so we print only its name. Instead in case we are here because a core has been closed, we can print out the core
* reference in order to add meaningful information in the log.
*
* @param core the owning {@link SolrCore}
* @param tracker the {@link Tracker} instance we want to stop.
* @param scheduler the scheduler.
* @param coreHasBeenReloaded a flag indicating if we are on a Core RELOAD scenario.
*/
private void shutdownTracker(SolrCore core, Tracker tracker, SolrTrackerScheduler scheduler, boolean coreHasBeenReloaded)
{
// In case of reload the input core is not the owner: the owner is instead the previous (closed) core and we don't have its reference here.
String coreReference = core.getName() + (coreHasBeenReloaded ? "" : ", instance " + core.hashCode());
if (tracker.isAlreadyInShutDownMode())
{
LOGGER.info("Tracker {}, instance {} belonging to core {}, is already in shutdown mode.",
tracker.getClass().getSimpleName(),
tracker.hashCode(),
coreReference);
return;
}
LOGGER.info("Tracker {}, instance {} belonging to core {} shutdown procedure initiated.",
tracker.getClass().getSimpleName(),
tracker.hashCode(),
coreReference);
try
{
tracker.setShutdown(true);
if (!scheduler.isShutdown())
{
scheduler.deleteJobForTrackerInstance(core.getName(), tracker);
}
tracker.shutdown();
LOGGER.info("Tracker {}, instance {}, belonging to core {} shutdown procedure correctly terminated.",
tracker.getClass().getSimpleName(),
tracker.hashCode(),
coreReference);
}
catch (Exception exception)
{
LOGGER.error("Tracker {}, instance {} belonging to core {}, shutdown procedure failed. " +
"See the stacktrace below for further details.",
tracker.getClass().getSimpleName(),
tracker.hashCode(),
coreReference,
exception);
}
}
/**
* Checks if the configuration declares this node as a slave.
*
* @param core the hosting {@link SolrCore} instance.
* @return true if the content store must be set in read only mode, false otherwise.
*/
boolean isSlaveModeEnabledFor(SolrCore core)
{
Predicate<PluginInfo> onlyReplicationHandler =
plugin -> "/replication".equals(plugin.name)
|| plugin.className.endsWith(ReplicationHandler.class.getSimpleName());
Function<NamedList, Boolean> isSlaveModeEnabled =
params -> ofNullable(params)
.map(configuration -> {
Object enable = configuration.get("enable");
return enable == null ||
(enable instanceof String ? StrUtils.parseBool((String)enable) : Boolean.TRUE.equals(enable));})
.orElse(false);
return core.getSolrConfig().getPluginInfos(SolrRequestHandler.class.getName())
.stream()
.filter(PluginInfo::isEnabled)
.filter(onlyReplicationHandler)
.findFirst()
.map(plugin -> plugin.initArgs)
.map(params -> params.get("slave"))
.map(NamedList.class::cast)
.map(isSlaveModeEnabled)
.orElse(false);
}
}
@@ -1,258 +0,0 @@
/*
* Copyright (C) 2005-2016 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.lifecycle;
import java.lang.invoke.MethodHandles;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import org.alfresco.opencmis.dictionary.CMISStrictDictionaryService;
import org.alfresco.solr.AlfrescoCoreAdminHandler;
import org.alfresco.solr.AlfrescoSolrDataModel;
import org.alfresco.solr.SolrInformationServer;
import org.alfresco.solr.SolrKeyResourceLoader;
import org.alfresco.solr.client.SOLRAPIClient;
import org.alfresco.solr.client.SOLRAPIClientFactory;
import org.alfresco.solr.content.SolrContentStore;
import org.alfresco.solr.tracker.AclTracker;
import org.alfresco.solr.tracker.CascadeTracker;
import org.alfresco.solr.tracker.CommitTracker;
import org.alfresco.solr.tracker.ContentTracker;
import org.alfresco.solr.tracker.MetadataTracker;
import org.alfresco.solr.tracker.ModelTracker;
import org.alfresco.solr.tracker.SolrTrackerScheduler;
import org.alfresco.solr.tracker.Tracker;
import org.alfresco.solr.tracker.TrackerRegistry;
import org.apache.solr.core.CloseHook;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.core.CoreDescriptorDecorator;
import org.apache.solr.core.SolrCore;
import org.apache.solr.core.SolrResourceLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Deals with core registration when the core is loaded.
*
* @author Gethin James
*/
public class SolrCoreLoadRegistration {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
/**
* Registers with the admin handler the information server and the trackers.
*/
public static void registerForCore(AlfrescoCoreAdminHandler adminHandler, CoreContainer coreContainer, SolrCore core,
String coreName)
{
TrackerRegistry trackerRegistry = adminHandler.getTrackerRegistry();
Properties props = new CoreDescriptorDecorator(core.getCoreDescriptor()).getProperties();
//Prepare cores
SolrResourceLoader loader = core.getLatestSchema().getResourceLoader();
SolrKeyResourceLoader keyResourceLoader = new SolrKeyResourceLoader(loader);
SOLRAPIClientFactory clientFactory = new SOLRAPIClientFactory();
SOLRAPIClient repositoryClient = clientFactory.getSOLRAPIClient(props, keyResourceLoader,
AlfrescoSolrDataModel.getInstance().getDictionaryService(CMISStrictDictionaryService.DEFAULT),
AlfrescoSolrDataModel.getInstance().getNamespaceDAO());
//Start content store
SolrContentStore contentStore = new SolrContentStore(coreContainer.getSolrHome());
SolrInformationServer srv = new SolrInformationServer(adminHandler, core, repositoryClient, contentStore);
props.putAll(srv.getProps());
adminHandler.getInformationServers().put(coreName, srv);
SolrTrackerScheduler scheduler = adminHandler.getScheduler();
// Prevents other threads from registering the ModelTracker at the same time
// Create model tracker and load all the persisted models
createModelTracker(coreName,
trackerRegistry,
props,
coreContainer.getSolrHome(),
repositoryClient,
srv,
scheduler);
log.info("Starting to track " + coreName);
if (Boolean.parseBoolean(props.getProperty("enable.alfresco.tracking", "false")))
{
if (trackerRegistry.hasTrackersForCore(coreName))
{
log.info("Trackers for " + coreName+ " is already registered, shutting them down.");
shutdownTrackers(coreName, trackerRegistry.getTrackersForCore(coreName),scheduler);
trackerRegistry.removeTrackersForCore(coreName);
adminHandler.getInformationServers().remove(coreName);
}
List<Tracker> trackers = createCoreTrackers(coreName, trackerRegistry, props, scheduler, repositoryClient, srv);
CommitTracker commitTracker = new CommitTracker(props, repositoryClient, coreName, srv, trackers);
trackerRegistry.register(coreName, commitTracker);
scheduler.schedule(commitTracker, coreName, props);
log.info("The Trackers are now scheduled to run");
trackers.add(commitTracker); //Add the commitTracker to the list of scheduled trackers that can be shutdown
core.addCloseHook(new CloseHook()
{
@Override
public void preClose(SolrCore core)
{
log.info("Shutting down " + core.getName());
SolrCoreLoadRegistration.shutdownTrackers(core.getName(), trackers, scheduler);
}
@Override
public void postClose(SolrCore core)
{
// Nothing to be done here
}
});
}
}
/**
* Creates the trackers
*
* @param coreName
* @param trackerRegistry
* @param props
* @param scheduler
* @param repositoryClient
* @param srv
* @return A list of trackers
*/
private static List<Tracker> createCoreTrackers(String coreName,
TrackerRegistry trackerRegistry,
Properties props,
SolrTrackerScheduler scheduler,
SOLRAPIClient repositoryClient,
SolrInformationServer srv) {
List<Tracker> trackers = new ArrayList<Tracker>();
AclTracker aclTracker = new AclTracker(props, repositoryClient, coreName, srv);
trackerRegistry.register(coreName, aclTracker);
scheduler.schedule(aclTracker, coreName, props);
ContentTracker contentTrkr = new ContentTracker(props, repositoryClient, coreName, srv);
trackerRegistry.register(coreName, contentTrkr);
scheduler.schedule(contentTrkr, coreName, props);
MetadataTracker metaTrkr = new MetadataTracker(props, repositoryClient, coreName, srv);
trackerRegistry.register(coreName, metaTrkr);
scheduler.schedule(metaTrkr, coreName, props);
CascadeTracker cascadeTrkr = new CascadeTracker(props, repositoryClient, coreName, srv);
trackerRegistry.register(coreName, cascadeTrkr);
scheduler.schedule(cascadeTrkr, coreName, props);
//The CommitTracker will acquire these locks in order
//The ContentTracker will likely have the longest runs so put it first to ensure the MetadataTracker is not paused while
//waiting for the ContentTracker to release it's lock.
//The aclTracker will likely have the shortest runs so put it last.
trackers.add(cascadeTrkr);
trackers.add(contentTrkr);
trackers.add(metaTrkr);
trackers.add(aclTracker);
return trackers;
}
/**
* Create model tracker and load persisted models.
*
* @param coreName
* @param trackerRegistry
* @param props
* @param solrHome
* @param repositoryClient
* @param srv
* @param scheduler
* @return true if model tracker has been created, false if it already exists.
*/
private synchronized static void createModelTracker(String coreName,
TrackerRegistry trackerRegistry,
Properties props,
String solrHome,
SOLRAPIClient repositoryClient,
SolrInformationServer srv,
SolrTrackerScheduler scheduler)
{
ModelTracker mTracker = trackerRegistry.getModelTracker();
if (mTracker == null)
{
log.debug("Creating ModelTracker");
mTracker = new ModelTracker(solrHome, props, repositoryClient,
coreName, srv);
trackerRegistry.setModelTracker(mTracker);
log.info("Ensuring first model sync.");
mTracker.ensureFirstModelSync();
log.info("Done ensuring first model sync.");
//Scheduling the ModelTracker.
scheduler.schedule(mTracker, coreName, props);
}
}
/**
* Shuts down the trackers for a core.
*
* The trackers are only deleted from the scheduler if they are the exact same instance of the Tracker class
* passed into this method.
* For example, you could have 2 cores of the same name and have the trackers registered with the scheduler BUT
* the scheduler only keys by core name. The Collection<Tracker>s passed into this method are only removed
* from the scheduler if the instances are == (equal). See scheduler.deleteJobForTrackerInstance()
*
* Trackers are not removed from the registry because the registry only keys by core name; its possible to
* have multiple cores of the same name running. Left over trackers in the registry are cleaned up by the CoreContainer
* shutdown, that happens in the the AlfrescoCoreAdminHandler.shutdown().
*
* @param coreName The name of the core
* @param coreTrackers A collection of trackers
* @param scheduler The scheduler
*/
public static void shutdownTrackers(String coreName, Collection<Tracker> coreTrackers, SolrTrackerScheduler scheduler)
{
try
{
log.info("Shutting down " + coreName + " with " + coreTrackers.size() + " trackers.");
// Sets the shutdown flag on the trackers to stop them from doing any more work
coreTrackers.forEach(tracker -> tracker.setShutdown(true));
if (!scheduler.isShutdown())
{
coreTrackers.forEach(tracker -> scheduler.deleteJobForTrackerInstance(coreName,tracker) );
}
coreTrackers.forEach(tracker -> tracker.shutdown());
}
catch (Exception e)
{
log.error("Failed to shutdown trackers for core "+coreName, e);
}
}
}
@@ -18,6 +18,7 @@
*/
package org.alfresco.solr.tracker;
import java.lang.invoke.MethodHandles;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.util.Properties;
@@ -31,7 +32,6 @@ import org.alfresco.solr.client.SOLRAPIClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Abstract base class that provides common {@link Tracker} behaviour.
*
@@ -39,20 +39,18 @@ import org.slf4j.LoggerFactory;
*/
public abstract class AbstractTracker implements Tracker
{
public static final long TIME_STEP_32_DAYS_IN_MS = 1000 * 60 * 60 * 24 * 32L;
public static final long TIME_STEP_1_HR_IN_MS = 60 * 60 * 1000L;
public static final String SHARD_METHOD_ACLID = "ACL_ID";
public static final String SHARD_METHOD_DBID = "DB_ID";
protected final static Logger log = LoggerFactory.getLogger(AbstractTracker.class);
static final long TIME_STEP_32_DAYS_IN_MS = 1000 * 60 * 60 * 24 * 32L;
static final long TIME_STEP_1_HR_IN_MS = 60 * 60 * 1000L;
static final String SHARD_METHOD_DBID = "DB_ID";
protected final static Logger LOGGER = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
protected Properties props;
protected SOLRAPIClient client;
protected InformationServer infoSrv;
InformationServer infoSrv;
protected String coreName;
protected StoreRef storeRef;
protected long batchCount;
protected boolean isSlave = false;
protected boolean isMaster = true;
protected String alfrescoVersion;
protected TrackerStats trackerStats;
protected boolean runPostModelLoadInit = true;
@@ -71,14 +69,10 @@ public abstract class AbstractTracker implements Tracker
protected volatile boolean rollback;
protected final Type type;
/*
* A thread handler can be used by subclasses, but they have to intentionally instantiate it.
*/
protected ThreadHandler threadHandler;
ThreadHandler threadHandler;
/**
* Default constructor, strictly for testing.
@@ -98,8 +92,6 @@ public abstract class AbstractTracker implements Tracker
storeRef = new StoreRef(p.getProperty("alfresco.stores", "workspace://SpacesStore"));
batchCount = Integer.parseInt(p.getProperty("alfresco.batch.count", "5000"));
maxLiveSearchers = Integer.parseInt(p.getProperty("alfresco.maxLiveSearchers", "2"));
isSlave = Boolean.parseBoolean(p.getProperty("enable.slave", "false"));
isMaster = Boolean.parseBoolean(p.getProperty("enable.master", "true"));
shardCount = Integer.parseInt(p.getProperty("shard.count", "1"));
shardInstance = Integer.parseInt(p.getProperty("shard.instance", "0"));
@@ -115,19 +107,19 @@ public abstract class AbstractTracker implements Tracker
this.type = type;
log.info("Solr built for Alfresco version: " + alfrescoVersion);
LOGGER.info("Solr built for Alfresco version: {}", alfrescoVersion);
}
/**
* Subclasses must implement behaviour that completes the following steps, in order:
*
* <ol>
* <li>Purge</li>
* <li>Reindex</li>
* <li>Index</li>
* <li>Track repository</li>
* </ol>
* @throws Throwable
*/
protected abstract void doTrack() throws Throwable;
@@ -146,7 +138,7 @@ public abstract class AbstractTracker implements Tracker
}
catch(Exception e)
{
// Ignore
}
@@ -158,12 +150,7 @@ public abstract class AbstractTracker implements Tracker
getTrackerState();
if(state == null) {
return true;
} else {
return false;
}
return state == null;
}
/**
@@ -173,8 +160,9 @@ public abstract class AbstractTracker implements Tracker
@Override
public void track()
{
if(runLock.availablePermits() == 0) {
log.info("... " + this.getClass().getSimpleName() + " for core [" + coreName + "] is already in use "+ this.getClass());
if(runLock.availablePermits() == 0)
{
LOGGER.info("... {} for core [{}] is already in use {}", this.getClass().getSimpleName(), coreName, getClass());
return;
}
@@ -184,15 +172,14 @@ public abstract class AbstractTracker implements Tracker
* The runLock ensures that for each tracker type (metadata, content, commit, cascade) only one tracker will
* be running at a time.
*/
runLock.acquire();
if(state==null && Boolean.parseBoolean(System.getProperty("alfresco.test", "false")))
if (state==null && Boolean.parseBoolean(System.getProperty("alfresco.test", "false")))
{
assert(assertTrackerStateRemainsNull());
}
log.info("... Running " + this.getClass().getSimpleName() + " for core [" + coreName + "].");
LOGGER.info("... Running {} for core [{}]", this.getClass().getSimpleName(), coreName);
if(this.state == null)
{
@@ -200,8 +187,8 @@ public abstract class AbstractTracker implements Tracker
* Set the global state for the tracker here.
*/
this.state = getTrackerState();
log.debug("##### Setting tracker global state.");
log.debug("State set: " + this.state.toString());
LOGGER.debug("##### Setting tracker global state.");
LOGGER.debug("State set: {}", this.state.toString());
this.state.setRunning(true);
}
else
@@ -219,38 +206,39 @@ public abstract class AbstractTracker implements Tracker
catch(IndexTrackingShutdownException t)
{
setRollback(true);
log.info("Stopping index tracking for " + getClass().getSimpleName() + " - " + coreName);
LOGGER.info("Stopping index tracking for {} - {}", getClass().getSimpleName(), coreName);
}
catch(Throwable t)
{
setRollback(true);
if (t instanceof SocketTimeoutException || t instanceof ConnectException)
{
if (log.isDebugEnabled())
if (LOGGER.isDebugEnabled())
{
// DEBUG, so give the whole stack trace
log.warn("Tracking communication timed out for " + getClass().getSimpleName() + " - " + coreName, t);
LOGGER.warn("Tracking communication timed out for {} - {}", getClass().getSimpleName(), coreName, t);
}
else
{
// We don't need the stack trace. It timed out.
log.warn("Tracking communication timed out for " + getClass().getSimpleName() + " - " + coreName);
LOGGER.warn("Tracking communication timed out for for {} - {}", getClass().getSimpleName(), coreName);
}
}
else
{
log.error("Tracking failed for " + getClass().getSimpleName() + " - " + coreName, t);
LOGGER.error("Tracking failed for for {} - {}", getClass().getSimpleName(), coreName, t);
}
}
}
catch (InterruptedException e)
{
log.error("Semaphore interrupted for " + getClass().getSimpleName() + " - " + coreName, e);
LOGGER.error("Semaphore interrupted for for {} - {}", getClass().getSimpleName(), coreName, e);
}
finally
{
infoSrv.unregisterTrackerThread();
if(state != null) {
if(state != null)
{
//During a rollback state is set to null.
state.setRunning(false);
state.setCheck(false);
@@ -259,15 +247,18 @@ public abstract class AbstractTracker implements Tracker
}
}
public boolean getRollback() {
public boolean getRollback()
{
return this.rollback;
}
public void setRollback(boolean rollback) {
public void setRollback(boolean rollback)
{
this.rollback = rollback;
}
private void continueState() {
private void continueState()
{
infoSrv.continueState(state);
state.incrementTrackerCycles();
}
@@ -289,8 +280,6 @@ public abstract class AbstractTracker implements Tracker
return this.infoSrv.getTrackerInitialState();
}
}
/**
* Allows time for the scheduled asynchronous tasks to complete
@@ -309,6 +298,7 @@ public abstract class AbstractTracker implements Tracker
}
catch (InterruptedException e)
{
// Nothing to be done here
}
}
currentRunnable = this.threadHandler.peekHeadReindexWorker();
@@ -327,15 +317,22 @@ public abstract class AbstractTracker implements Tracker
throw new IndexTrackingShutdownException();
}
}
@Override
public boolean isAlreadyInShutDownMode()
{
return shutdown;
}
@Override
public void setShutdown(boolean shutdown)
{
this.shutdown = shutdown;
}
@Override
public void shutdown()
{
log.warn("Core "+ coreName+" shutdown called on tracker. " + getClass().getSimpleName() + " " + hashCode());
setShutdown(true);
if(this.threadHandler != null)
{
@@ -343,15 +340,16 @@ public abstract class AbstractTracker implements Tracker
}
}
public Semaphore getWriteLock() {
public Semaphore getWriteLock()
{
return this.writeLock;
}
public Semaphore getRunLock() {
public Semaphore getRunLock()
{
return this.runLock;
}
/**
* @return Alfresco version Solr was built for
*/
@@ -370,6 +368,4 @@ public abstract class AbstractTracker implements Tracker
{
return type;
}
}
}
@@ -288,11 +288,6 @@ public class AclTracker extends AbstractTracker
protected void trackRepository() throws IOException, AuthenticationException, JSONException
{
checkShutdown();
if(!isMaster && isSlave)
{
return;
}
TrackerState state = super.getTrackerState();
@@ -50,14 +50,14 @@ public class CascadeTracker extends AbstractTracker implements Tracker
public CascadeTracker(Properties p, SOLRAPIClient client, String coreName,
InformationServer informationServer)
{
super(p, client, coreName, informationServer, Tracker.Type.Cascade);
super(p, client, coreName, informationServer, Tracker.Type.CASCADE);
threadHandler = new ThreadHandler(p, coreName, "CascadeTracker");
}
CascadeTracker()
{
super(Tracker.Type.Cascade);
super(Tracker.Type.CASCADE);
}
@Override
@@ -51,7 +51,7 @@ public class CommitTracker extends AbstractTracker
**/
CommitTracker()
{
super(Tracker.Type.Commit);
super(Tracker.Type.COMMIT);
}
public CommitTracker(Properties p,
@@ -60,7 +60,7 @@ public class CommitTracker extends AbstractTracker
InformationServer informationServer,
List<Tracker> trackers)
{
super(p, client, coreName, informationServer, Tracker.Type.Commit);
super(p, client, coreName, informationServer, Tracker.Type.COMMIT);
//Set the trackers
for(Tracker tracker : trackers) {
@@ -45,7 +45,7 @@ public class ContentTracker extends AbstractTracker implements Tracker
public ContentTracker(Properties p, SOLRAPIClient client, String coreName,
InformationServer informationServer)
{
super(p, client, coreName, informationServer, Tracker.Type.Content);
super(p, client, coreName, informationServer, Tracker.Type.CONTENT);
contentReadBatchSize = Integer.parseInt(p.getProperty("alfresco.contentReadBatchSize", "100"));
contentUpdateBatchSize = Integer.parseInt(p.getProperty("alfresco.contentUpdateBatchSize", "1000"));
threadHandler = new ThreadHandler(p, coreName, "ContentTracker");
@@ -53,7 +53,7 @@ public class ContentTracker extends AbstractTracker implements Tracker
ContentTracker()
{
super(Tracker.Type.Content);
super(Tracker.Type.CONTENT);
}
@Override
@@ -0,0 +1,252 @@
/*
* #%L
* Alfresco Solr Client
* %%
* 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/>.
* #L%
*/
package org.alfresco.solr.tracker;
import static java.util.Optional.of;
import static java.util.Optional.ofNullable;
import static org.alfresco.solr.tracker.DocRouterFactory.SHARD_KEY_KEY;
import org.alfresco.opencmis.dictionary.CMISStrictDictionaryService;
import org.alfresco.repo.dictionary.NamespaceDAO;
import org.alfresco.repo.index.shard.ShardMethodEnum;
import org.alfresco.repo.index.shard.ShardState;
import org.alfresco.repo.index.shard.ShardStateBuilder;
import org.alfresco.repo.search.impl.QueryParserUtils;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.namespace.QName;
import org.alfresco.solr.AlfrescoCoreAdminHandler;
import org.alfresco.solr.AlfrescoSolrDataModel;
import org.alfresco.solr.InformationServer;
import org.alfresco.solr.NodeReport;
import org.alfresco.solr.TrackerState;
import org.alfresco.solr.client.SOLRAPIClient;
import org.apache.commons.lang3.StringUtils;
import java.util.HashMap;
import java.util.Optional;
import java.util.Properties;
/**
* Superclass for all components which are able to inform Alfresco about the hosting node state.
* This has been introduced in SEARCH-1752 for splitting the dual responsibility of the {@link MetadataTracker}.
* As consequence of that, this class contains all the members needed for obtaining a valid
* {@link org.alfresco.repo.index.shard.ShardState} that can be periodically communicated to Alfresco.
*
* @author Andrea Gazzarini
* @since 1.5
* @see <a href="https://issues.alfresco.com/jira/browse/SEARCH-1752">SEARCH-1752</a>
*/
public abstract class CoreStatePublisher extends AbstractTracker
{
DocRouter docRouter;
private final boolean isMaster;
/** The string representation of the shard key. */
private Optional<String> shardKey;
/** The property to use for determining the shard. */
protected Optional<QName> shardProperty = Optional.empty();
CoreStatePublisher(
boolean isMaster,
Properties p,
SOLRAPIClient client,
String coreName,
InformationServer informationServer,
Type type)
{
super(p, client, coreName, informationServer, type);
this.isMaster = isMaster;
shardMethod = p.getProperty("shard.method", SHARD_METHOD_DBID);
shardKey = ofNullable(p.getProperty(SHARD_KEY_KEY));
firstUpdateShardProperty();
docRouter = DocRouterFactory.getRouter(p, ShardMethodEnum.getShardMethod(shardMethod));
}
CoreStatePublisher(Type type)
{
super(type);
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()
{
shardKey.ifPresent( shardKeyName -> {
updateShardProperty();
if (shardProperty.isEmpty())
{
LOGGER.warn("Sharding property {} was set to {}, but no such property was found.", SHARD_KEY_KEY, shardKeyName);
}
});
}
/**
* Set the shard property using the shard key.
*/
void updateShardProperty()
{
shardKey.ifPresent(shardKeyName -> {
Optional<QName> updatedShardProperty = getShardProperty(shardKeyName);
if (!shardProperty.equals(updatedShardProperty))
{
if (updatedShardProperty.isEmpty())
{
LOGGER.warn("The model defining {} property has been disabled", shardKeyName);
}
else
{
LOGGER.info("New {} property found for {} ", SHARD_KEY_KEY, shardKeyName);
}
}
shardProperty = updatedShardProperty;
});
}
/**
* Given the field name, returns the name of the property definition.
* If the property definition is not found, Empty optional is returned.
*
* @param field the field name.
* @return the name of the associated property definition if present, Optional.Empty() otherwise
*/
static Optional<QName> getShardProperty(String field)
{
if (StringUtils.isBlank(field))
{
throw new IllegalArgumentException("Sharding property " + SHARD_KEY_KEY + " has not been set.");
}
AlfrescoSolrDataModel dataModel = AlfrescoSolrDataModel.getInstance();
NamespaceDAO namespaceDAO = dataModel.getNamespaceDAO();
DictionaryService dictionaryService = dataModel.getDictionaryService(CMISStrictDictionaryService.DEFAULT);
PropertyDefinition propertyDef = QueryParserUtils.matchPropertyDefinition("http://www.alfresco.org/model/content/1.0",
namespaceDAO,
dictionaryService,
field);
return ofNullable(propertyDef).map(PropertyDefinition::getName);
}
/**
* The {@link ShardState}, as the name suggests, encapsulates/stores the state of the shard which hosts this
* {@link MetadataTracker} instance.
*
* The {@link ShardState} is primarily used in two places:
*
* <ul>
* <li>Transaction tracking: (see {@link MetadataTracker#trackTransactions()}): for pulling/tracking transactions from Alfresco</li>
* <li>
* DynamicSharding: when the {@link MetadataTracker} is running on a slave instance it doesn't actually act
* as a tracker, it calls Alfresco to register the state of the node (the shard) without pulling any transactions.
* As consequence of that, Alfresco will be aware about the shard which will be included in subsequent queries.
* </li>
* </ul>
*
* @return the {@link ShardState} instance which stores the current state of the hosting shard.
*/
ShardState getShardState()
{
TrackerState transactionsTrackerState = getTrackerState();
TrackerState changeSetsTrackerState =
of(infoSrv.getAdminHandler())
.map(AlfrescoCoreAdminHandler::getTrackerRegistry)
.map(registry -> registry.getTrackerForCore(coreName, AclTracker.class))
.map(Tracker::getTrackerState)
.orElse(transactionsTrackerState);
HashMap<String, String> propertyBag = new HashMap<>();
propertyBag.put("coreName", coreName);
HashMap<String, String> extendedPropertyBag = new HashMap<>(propertyBag);
updateShardProperty();
shardProperty.ifPresent(p -> extendedPropertyBag.putAll(docRouter.getProperties(p)));
return ShardStateBuilder.shardState()
.withMaster(isMaster)
.withLastUpdated(System.currentTimeMillis())
.withLastIndexedChangeSetCommitTime(changeSetsTrackerState.getLastIndexedChangeSetCommitTime())
.withLastIndexedChangeSetId(changeSetsTrackerState.getLastIndexedChangeSetId())
.withLastIndexedTxCommitTime(transactionsTrackerState.getLastIndexedTxCommitTime())
.withLastIndexedTxId(transactionsTrackerState.getLastIndexedTxId())
.withPropertyBag(extendedPropertyBag)
.withShardInstance()
.withBaseUrl(infoSrv.getBaseUrl())
.withPort(infoSrv.getPort())
.withHostName(infoSrv.getHostName())
.withShard()
.withInstance(shardInstance)
.withFloc()
.withNumberOfShards(shardCount)
.withAddedStoreRef(storeRef)
.withTemplate(shardTemplate)
.withHasContent(transformContent)
.withShardMethod(ShardMethodEnum.getShardMethod(shardMethod))
.withPropertyBag(propertyBag)
.endFloc()
.endShard()
.endShardInstance()
.build();
}
/**
* Returns the {@link DocRouter} instance in use on this node.
*
* @return the {@link DocRouter} instance in use on this node.
*/
public DocRouter getDocRouter()
{
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;
}
}
@@ -20,27 +20,15 @@ package org.alfresco.solr.tracker;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Optional;
import java.util.Properties;
import java.util.concurrent.ConcurrentLinkedQueue;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.httpclient.AuthenticationException;
import org.alfresco.opencmis.dictionary.CMISStrictDictionaryService;
import org.alfresco.repo.dictionary.NamespaceDAO;
import org.alfresco.repo.index.shard.ShardMethodEnum;
import org.alfresco.repo.index.shard.ShardState;
import org.alfresco.repo.index.shard.ShardStateBuilder;
import org.alfresco.repo.search.impl.QueryParserUtils;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.namespace.QName;
import org.alfresco.solr.AlfrescoCoreAdminHandler;
import org.alfresco.solr.AlfrescoSolrDataModel;
import org.alfresco.solr.BoundedDeque;
import org.alfresco.solr.InformationServer;
import org.alfresco.solr.NodeReport;
@@ -53,95 +41,41 @@ import org.alfresco.solr.client.SOLRAPIClient;
import org.alfresco.solr.client.Transaction;
import org.alfresco.solr.client.Transactions;
import org.apache.commons.codec.EncoderException;
import org.apache.commons.lang3.StringUtils;
import org.json.JSONException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static java.util.Optional.of;
import static java.util.Optional.ofNullable;
import static org.alfresco.solr.tracker.DocRouterFactory.SHARD_KEY_KEY;
/*
* This tracks two things: transactions and metadata nodes
* @author Ahmed Owian
*/
public class MetadataTracker extends AbstractTracker implements Tracker
public class MetadataTracker extends CoreStatePublisher implements Tracker
{
protected final static Logger log = LoggerFactory.getLogger(MetadataTracker.class);
private static final int DEFAULT_TRANSACTION_DOCS_BATCH_SIZE = 100;
private static final int DEFAULT_NODE_BATCH_SIZE = 10;
private int transactionDocsBatchSize = DEFAULT_TRANSACTION_DOCS_BATCH_SIZE;
private int nodeBatchSize = DEFAULT_NODE_BATCH_SIZE;
private ConcurrentLinkedQueue<Long> transactionsToReindex = new ConcurrentLinkedQueue<Long>();
private ConcurrentLinkedQueue<Long> transactionsToIndex = new ConcurrentLinkedQueue<Long>();
private ConcurrentLinkedQueue<Long> transactionsToPurge = new ConcurrentLinkedQueue<Long>();
private ConcurrentLinkedQueue<Long> nodesToReindex = new ConcurrentLinkedQueue<Long>();
private ConcurrentLinkedQueue<Long> nodesToIndex = new ConcurrentLinkedQueue<Long>();
private ConcurrentLinkedQueue<Long> nodesToPurge = new ConcurrentLinkedQueue<Long>();
private ConcurrentLinkedQueue<String> queriesToReindex = new ConcurrentLinkedQueue<String>();
private DocRouter docRouter;
/** The string representation of the shard key. */
private Optional<String> shardKey;
/** The property to use for determining the shard. */
private Optional<QName> shardProperty = Optional.empty();
private ConcurrentLinkedQueue<Long> transactionsToReindex = new ConcurrentLinkedQueue<>();
private ConcurrentLinkedQueue<Long> transactionsToIndex = new ConcurrentLinkedQueue<>();
private ConcurrentLinkedQueue<Long> transactionsToPurge = new ConcurrentLinkedQueue<>();
private ConcurrentLinkedQueue<Long> nodesToReindex = new ConcurrentLinkedQueue<>();
private ConcurrentLinkedQueue<Long> nodesToIndex = new ConcurrentLinkedQueue<>();
private ConcurrentLinkedQueue<Long> nodesToPurge = new ConcurrentLinkedQueue<>();
private ConcurrentLinkedQueue<String> queriesToReindex = new ConcurrentLinkedQueue<>();
public MetadataTracker(Properties p, SOLRAPIClient client, String coreName,
public MetadataTracker(final boolean isMaster, Properties p, SOLRAPIClient client, String coreName,
InformationServer informationServer)
{
super(p, client, coreName, informationServer, Tracker.Type.MetaData);
super(isMaster, p, client, coreName, informationServer, Tracker.Type.METADATA);
transactionDocsBatchSize = Integer.parseInt(p.getProperty("alfresco.transactionDocsBatchSize", "100"));
shardMethod = p.getProperty("shard.method", SHARD_METHOD_DBID);
shardKey = ofNullable(p.getProperty(SHARD_KEY_KEY));
firstUpdateShardProperty();
docRouter = DocRouterFactory.getRouter(p, ShardMethodEnum.getShardMethod(shardMethod));
nodeBatchSize = Integer.parseInt(p.getProperty("alfresco.nodeBatchSize", "10"));
threadHandler = new ThreadHandler(p, coreName, "MetadataTracker");
}
/**
* Set the shard property using the shard key.
*/
private void updateShardProperty()
{
shardKey.ifPresent(shardKeyName -> {
Optional<QName> updatedShardProperty = getShardProperty(shardKeyName);
if (!shardProperty.equals(updatedShardProperty))
{
if (updatedShardProperty.isEmpty())
{
log.warn("The model defining " + shardKeyName + " property has been disabled");
}
else
{
log.info("New " + SHARD_KEY_KEY + " property found for " + shardKeyName);
}
}
shardProperty = updatedShardProperty;
});
}
private void firstUpdateShardProperty()
{
shardKey.ifPresent( shardKeyName -> {
updateShardProperty();
if (shardProperty.isEmpty())
{
log.warn("Sharding property " + SHARD_KEY_KEY + " was set to " + shardKeyName + ", but no such property was found.");
}
});
}
MetadataTracker()
{
super(Tracker.Type.MetaData);
}
public DocRouter getDocRouter() {
return this.docRouter;
super(Tracker.Type.METADATA);
}
@Override
@@ -160,7 +94,8 @@ public class MetadataTracker extends AbstractTracker implements Tracker
}
}
public void maintenance() throws Exception {
public void maintenance() throws Exception
{
purgeTransactions();
purgeNodes();
reindexTransactions();
@@ -170,7 +105,8 @@ public class MetadataTracker extends AbstractTracker implements Tracker
indexNodes();
}
public boolean hasMaintenance() throws Exception {
public boolean hasMaintenance()
{
return transactionsToReindex.size() > 0 ||
transactionsToIndex.size() > 0 ||
transactionsToPurge.size() > 0 ||
@@ -180,30 +116,11 @@ public class MetadataTracker extends AbstractTracker implements Tracker
queriesToReindex.size() > 0;
}
private void trackRepository() throws IOException, AuthenticationException, JSONException, EncoderException
{
log.debug("####### MetadataTracker trackRepository Start #######");
checkShutdown();
if(!isMaster && isSlave)
{
// Dynamic registration
/*
* This section 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 code below calls
* the repo to register the state of the node without pulling any real transactions from the repo.
*
* This allows the repo to register the replica so that it will be included in queries. But the slave Solr node
* will pull its data from a "tracking" Solr node using Solr's master/slave replication, rather then tracking the repository.
*
*/
ShardState shardstate = getShardState();
client.getTransactions(0L, null, 0L, null, 0, shardstate);
return;
}
// Check we are tracking the correct repository
TrackerState state = super.getTrackerState();
log.debug("####### MetadataTracker check CYCLE #######");
@@ -233,67 +150,6 @@ public class MetadataTracker extends AbstractTracker implements Tracker
trackTransactions();
}
/**
* The {@link ShardState}, as the name suggests, encapsulates/stores the state of the shard which hosts this
* {@link MetadataTracker} instance.
*
* The {@link ShardState} is primarily used in two places:
*
* <ul>
* <li>Transaction tracking: (see {@link #trackTransactions()}): for pulling/tracking transactions from Alfresco</li>
* <li>
* DynamicSharding: when the {@link MetadataTracker} is running on a slave instance it doesn't actually act
* as a tracker, it calls Alfresco to register the state of the node (the shard) without pulling any transactions.
* As consequence of that, Alfresco will be aware about the shard which will be included in subsequent queries.
* </li>
* </ul>
*
* @return the {@link ShardState} instance which stores the current state of the hosting shard.
*/
ShardState getShardState()
{
TrackerState transactionsTrackerState = super.getTrackerState();
TrackerState changeSetsTrackerState =
of(infoSrv.getAdminHandler())
.map(AlfrescoCoreAdminHandler::getTrackerRegistry)
.map(registry -> registry.getTrackerForCore(coreName, AclTracker.class))
.map(Tracker::getTrackerState)
.orElse(transactionsTrackerState);
HashMap<String, String> propertyBag = new HashMap<>();
propertyBag.put("coreName", coreName);
HashMap<String, String> extendedPropertyBag = new HashMap<>(propertyBag);
updateShardProperty();
shardProperty.ifPresent(p -> extendedPropertyBag.putAll(docRouter.getProperties(p)));
return ShardStateBuilder.shardState()
.withMaster(isMaster)
.withLastUpdated(System.currentTimeMillis())
.withLastIndexedChangeSetCommitTime(changeSetsTrackerState.getLastIndexedChangeSetCommitTime())
.withLastIndexedChangeSetId(changeSetsTrackerState.getLastIndexedChangeSetId())
.withLastIndexedTxCommitTime(transactionsTrackerState.getLastIndexedTxCommitTime())
.withLastIndexedTxId(transactionsTrackerState.getLastIndexedTxId())
.withPropertyBag(extendedPropertyBag)
.withShardInstance()
.withBaseUrl(infoSrv.getBaseUrl())
.withPort(infoSrv.getPort())
.withHostName(infoSrv.getHostName())
.withShard()
.withInstance(shardInstance)
.withFloc()
.withNumberOfShards(shardCount)
.withAddedStoreRef(storeRef)
.withTemplate(shardTemplate)
.withHasContent(transformContent)
.withShardMethod(ShardMethodEnum.getShardMethod(shardMethod))
.withPropertyBag(propertyBag)
.endFloc()
.endShard()
.endShardInstance()
.build();
}
/**
* Checks the first and last TX time
* @param state the state of this tracker
@@ -1032,24 +888,18 @@ public class MetadataTracker extends AbstractTracker implements Tracker
}
}
@Override
public NodeReport checkNode(Long dbid)
{
NodeReport nodeReport = new NodeReport();
nodeReport.setDbid(dbid);
NodeReport nodeReport = super.checkNode(dbid);
// In DB
GetNodesParameters parameters = new GetNodesParameters();
parameters.setFromNodeId(dbid);
parameters.setToNodeId(dbid);
List<Node> dbnodes;
try
{
dbnodes = client.getNodes(parameters, 1);
List<Node> dbnodes = client.getNodes(parameters, 1);
if (dbnodes.size() == 1)
{
Node dbnode = dbnodes.get(0);
@@ -1059,41 +909,31 @@ public class MetadataTracker extends AbstractTracker implements Tracker
else
{
nodeReport.setDbNodeStatus(SolrApiNodeStatus.UNKNOWN);
nodeReport.setDbTx(-1l);
nodeReport.setDbTx(-1L);
}
}
catch (IOException e)
{
nodeReport.setDbNodeStatus(SolrApiNodeStatus.UNKNOWN);
nodeReport.setDbTx(-2l);
nodeReport.setDbTx(-2L);
}
catch (JSONException e)
{
nodeReport.setDbNodeStatus(SolrApiNodeStatus.UNKNOWN);
nodeReport.setDbTx(-3l);
nodeReport.setDbTx(-3L);
}
catch (AuthenticationException e1)
{
nodeReport.setDbNodeStatus(SolrApiNodeStatus.UNKNOWN);
nodeReport.setDbTx(-4l);
nodeReport.setDbTx(-4L);
}
this.infoSrv.addCommonNodeReportInfo(nodeReport);
return nodeReport;
}
public NodeReport checkNode(Node node)
{
NodeReport nodeReport = new NodeReport();
nodeReport.setDbid(node.getId());
nodeReport.setDbNodeStatus(node.getStatus());
nodeReport.setDbTx(node.getTxnId());
this.infoSrv.addCommonNodeReportInfo(nodeReport);
return nodeReport;
return checkNode(node.getId());
}
public List<Node> getFullNodesForDbTransaction(Long txid)
@@ -1230,34 +1070,4 @@ public class MetadataTracker extends AbstractTracker implements Tracker
{
this.queriesToReindex.offer(query);
}
/**
* Given the field name, returns the name of the property definition.
* If the property definition is not found, Empty optional is returned.
*
* @param field
*
* @return the name of the associated property definition if present, Optional.Empty() otherwise
*
*/
public static Optional<QName> getShardProperty(String field)
{
if (StringUtils.isBlank(field))
{
throw new IllegalArgumentException("Sharding property " + SHARD_KEY_KEY + " has not been set.");
}
AlfrescoSolrDataModel dataModel = AlfrescoSolrDataModel.getInstance();
NamespaceDAO namespaceDAO = dataModel.getNamespaceDAO();
DictionaryService dictionaryService = dataModel.getDictionaryService(CMISStrictDictionaryService.DEFAULT);
PropertyDefinition propertyDef = QueryParserUtils.matchPropertyDefinition("http://www.alfresco.org/model/content/1.0",
namespaceDAO,
dictionaryService,
field);
if (propertyDef == null)
{
return Optional.empty();
}
return of(propertyDef.getName());
}
}
@@ -103,10 +103,10 @@ public class ModelTracker extends AbstractTracker implements Tracker
public ModelTracker(String solrHome, Properties p, SOLRAPIClient client, String coreName,
InformationServer informationServer)
{
super(p, client, coreName, informationServer, Tracker.Type.Model);
super(p, client, coreName, informationServer, Tracker.Type.MODEL);
String normalSolrHome = SolrResourceLoader.normalizeDir(solrHome);
alfrescoModelDir = new File(ConfigUtil.locateProperty("solr.model.dir", normalSolrHome+"alfrescoModels"));
log.info("Alfresco Model dir " + alfrescoModelDir);
LOGGER.info("Alfresco Model dir " + alfrescoModelDir);
if (!alfrescoModelDir.exists())
{
alfrescoModelDir.mkdir();
@@ -115,12 +115,16 @@ public class ModelTracker extends AbstractTracker implements Tracker
loadPersistedModels();
}
public boolean hasMaintenance() {
@Override
public boolean hasMaintenance()
{
return false;
}
public void maintenance() {
@Override
public void maintenance()
{
// Nothing to be done here
}
/**
@@ -183,7 +187,7 @@ public class ModelTracker extends AbstractTracker implements Tracker
*/
ModelTracker()
{
super(Tracker.Type.Model);
super(Tracker.Type.MODEL);
}
@Override
@@ -193,7 +197,7 @@ public class ModelTracker extends AbstractTracker implements Tracker
int registeredSearcherCount = this.infoSrv.getRegisteredSearcherCount();
if (registeredSearcherCount >= getMaxLiveSearchers())
{
log.info(".... skipping tracking registered searcher count = " + registeredSearcherCount);
LOGGER.info(".... skipping tracking registered searcher count = " + registeredSearcherCount);
return;
}
@@ -203,7 +207,7 @@ public class ModelTracker extends AbstractTracker implements Tracker
public void trackModels(boolean onlyFirstTime) throws AuthenticationException, IOException, JSONException
{
boolean requiresWriteLock = false;
boolean requiresWriteLock;
modelLock.readLock().lock();
try
{
@@ -264,17 +268,13 @@ public class ModelTracker extends AbstractTracker implements Tracker
}
catch (Throwable t)
{
log.error("Model tracking failed for core: "+ coreName, t);
LOGGER.error("Model tracking failed for core: "+ coreName, t);
}
}
/**
* Tracks models. Reflects changes and updates on disk copy
*
* @throws AuthenticationException
* @throws IOException
* @throws JSONException
*/
private void trackModelsImpl() throws AuthenticationException, IOException, JSONException
{
@@ -480,16 +480,10 @@ public class ModelTracker extends AbstractTracker implements Tracker
}
return expandedQName;
}
/**
* @param alfrescoModelDir
* @param modelName
*/
private void removeMatchingModels(File alfrescoModelDir, QName modelName)
{
final String prefix = modelName.toPrefixString(this.infoSrv.getNamespaceDAO()).replace(":", ".") + ".";
final String postFix = ".xml";
@@ -540,7 +534,7 @@ public class ModelTracker extends AbstractTracker implements Tracker
{
loadedModels.add(modelName);
}
log.info("Loading model " + model.getName());
LOGGER.info("Loading model " + model.getName());
}
}
@@ -0,0 +1,88 @@
package org.alfresco.solr.tracker;
import static org.alfresco.solr.tracker.Tracker.Type.NODE_STATE_PUBLISHER;
import org.alfresco.httpclient.AuthenticationException;
import org.alfresco.repo.index.shard.ShardState;
import org.alfresco.solr.SolrInformationServer;
import org.alfresco.solr.TrackerState;
import org.alfresco.solr.client.SOLRAPIClient;
import org.apache.commons.codec.EncoderException;
import java.io.IOException;
import java.util.Properties;
/**
* Despite belonging to the Tracker ecosystem, this component is actually a publisher, which periodically informs
* Alfresco about the state of the hosting slave core.
* 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.
*
* In this scenario the slave is polling a "tracking" Solr node. The tracker below calls
* the repo to register the state of the node without pulling any real transactions from the repo.
*
* This allows the repo to register the replica so that it will be included in queries. But the slave Solr node
* will pull its data from a "tracking" Solr node using Solr's master/slave replication, rather then tracking the repository.
*
* @author Andrea Gazzarini
* @since 1.5
*/
public class SlaveCoreStatePublisher extends CoreStatePublisher
{
public SlaveCoreStatePublisher(
boolean isMaster,
Properties coreProperties,
SOLRAPIClient repositoryClient,
String name,
SolrInformationServer informationServer)
{
super(isMaster, coreProperties, repositoryClient, name, informationServer, NODE_STATE_PUBLISHER);
}
@Override
protected void doTrack()
{
try
{
ShardState shardstate = getShardState();
client.getTransactions(0L, null, 0L, null, 0, shardstate);
}
catch (EncoderException | IOException | AuthenticationException exception )
{
LOGGER.error("Unable to publish this node state. " +
"A failure condition has been met during the outbound subscription message encoding process. " +
"See the stacktrace below for further details.", exception);
}
}
@Override
public void maintenance()
{
// Do nothing here
}
@Override
public boolean isOnMasterOrStandalone()
{
return false;
}
@Override
public boolean hasMaintenance()
{
return false;
}
/**
* When running in a slave mode, we need to recreate the tracker state every time.
* This because in that context we don't have any tracker updating the state (e.g. lastIndexedChangeSetCommitTime,
* lastIndexedChangeSetId)
*
* @return a new, fresh and up to date instance of {@link TrackerState}.
*/
@Override
public TrackerState getTrackerState()
{
return infoSrv.getTrackerInitialState();
}
}
@@ -76,18 +76,20 @@ public class SolrTrackerScheduler
{
log.error("Failed to schedule " + jobType + " Job.", e);
}
private String getCron(Properties props, String cronType)
{
String cron = props.getProperty(cronType);
return cron == null ? props.getProperty("alfresco.cron",DEFAULT_CRON) : cron;
return cron == null ? props.getProperty("alfresco.cron", DEFAULT_CRON) : cron;
}
/**
* Schedules individual trackers based on the solrcore properties.
*
* @author Michael Suzuki
* @param tracker
* @param coreName
* @param props
* @param tracker the tracker to bo scheduled.
* @param coreName the owning core name.
* @param props the core properties.
*/
public void schedule(Tracker tracker, String coreName, Properties props)
{
@@ -98,27 +100,30 @@ public class SolrTrackerScheduler
Trigger trigger;
try
{
String cron = null;
String cron;
switch (tracker.getType())
{
case ACL:
cron = getCron(props,"alfresco.acl.tracker.cron");
break;
case Model:
case MODEL:
cron = getCron(props,"alfresco.model.tracker.cron");
break;
case Content:
case CONTENT:
cron = getCron(props,"alfresco.content.tracker.cron");
break;
case MetaData:
case METADATA:
cron = getCron(props,"alfresco.metadata.tracker.cron");
break;
case Cascade:
case CASCADE:
cron = getCron(props,"alfresco.cascade.tracker.cron");
break;
case Commit:
case COMMIT:
cron = getCron(props,"alfresco.commit.tracker.cron");
break;
case NODE_STATE_PUBLISHER:
cron = getCron(props,"alfresco.nodestate.tracker.cron");
break;
default:
cron = props.getProperty("alfresco.cron",DEFAULT_CRON);
break;
@@ -161,7 +166,7 @@ public class SolrTrackerScheduler
* identical to the instance that is passed in. If they are identical then the job is deleted.
* Otherwise, another core (of the same name) scheduled this job, so its left alone.
*
* @param coreName
* @param coreName the core name.
* @param tracker Specific instance of a tracker
*/
public void deleteJobForTrackerInstance(String coreName, Tracker tracker)
@@ -36,7 +36,9 @@ public interface Tracker
String getAlfrescoVersion();
void setShutdown(boolean shutdown);
boolean isAlreadyInShutDownMode();
void shutdown();
boolean getRollback();
@@ -51,12 +53,14 @@ public interface Tracker
Type getType();
enum Type{
Model,
Content,
enum Type
{
MODEL,
CONTENT,
ACL,
Cascade,
Commit,
MetaData
CASCADE,
COMMIT,
METADATA,
NODE_STATE_PUBLISHER
}
}
@@ -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;
}
}
}
@@ -87,7 +87,7 @@ import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_VERSI
* @author Michael Suzuki
*/
@ThreadLeakLingering(linger = 5000)
public abstract class AbstractAlfrescoDistributedTest extends SolrTestInitializer
public abstract class AbstractAlfrescoDistributedIT extends SolrITInitializer
{
protected static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@@ -760,8 +760,6 @@ public abstract class AbstractAlfrescoDistributedTest extends SolrTestInitialize
params.remove("distrib");
setDistributedParams(params);
QueryResponse rsp = queryRandomShard(json, params);
System.out.println("Cluster Response:"+rsp);
System.out.println("Control Response:"+controlRsp);
solrComparator.compareResponses(rsp, controlRsp);
return rsp;
}
@@ -27,7 +27,6 @@ import org.alfresco.solr.client.NodeMetaData;
import org.alfresco.solr.client.SOLRAPIQueueClient;
import org.alfresco.solr.client.Transaction;
import org.alfresco.solr.tracker.Tracker;
import org.alfresco.util.SearchLanguageConversion;
import org.apache.chemistry.opencmis.commons.impl.json.JSONArray;
import org.apache.chemistry.opencmis.commons.impl.json.JSONObject;
import org.apache.chemistry.opencmis.commons.impl.json.JSONValue;
@@ -84,17 +83,17 @@ import static org.junit.Assert.assertEquals;
/**
* Base class that provides the solr test harness.
* This is used to manage the embedded solr used for unit and integration testing.
* This is used to manage the embedded solr used for integration testing.
* The abstract also provides helper method that interacts with the
* embedded solr.
*
* @author Michael Suzuki
*
*/
public abstract class AbstractAlfrescoSolrTests implements SolrTestFiles, AlfrescoSolrConstants
public abstract class AbstractAlfrescoSolrIT implements SolrTestFiles, AlfrescoSolrConstants
{
static AlfrescoCoreAdminHandler admin;
private static Log LOG = LogFactory.getLog(AbstractAlfrescoSolrTests.class);
private static Log LOG = LogFactory.getLog(AbstractAlfrescoSolrIT.class);
private static boolean CORE_NOT_YET_CREATED = true;
/**
@@ -43,7 +43,7 @@ import static org.alfresco.solr.AlfrescoSolrUtils.*;
*/
@SolrTestCaseJ4.SuppressSSL
@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"})
public class AdminHandlerDistributedTest extends AbstractAlfrescoDistributedTest
public class AdminHandlerDistributedIT extends AbstractAlfrescoDistributedIT
{
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
final String JETTY_SERVER_ID = this.getClass().getSimpleName();
@@ -52,7 +52,7 @@ public class AdminHandlerDistributedTest extends AbstractAlfrescoDistributedTest
@BeforeClass
private static void initData() throws Throwable
{
initSolrServers(2, "AdminHandlerDistributedTest", null);
initSolrServers(2, "AdminHandlerDistributedIT", null);
}
@AfterClass
@@ -11,7 +11,8 @@ import org.junit.Test;
@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"})
@SolrTestCaseJ4.SuppressSSL
public class AdminHandlerTest extends AbstractAlfrescoSolrTests {
public class AdminHandlerIT extends AbstractAlfrescoSolrIT
{
static CoreAdminHandler admin;
@@ -20,15 +20,23 @@ package org.alfresco.solr;
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.ARCHIVE_CORE_NAME;
import static org.alfresco.solr.AlfrescoCoreAdminHandler.ARG_TXID;
import static org.alfresco.solr.AlfrescoCoreAdminHandler.STORE_REF_MAP;
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.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
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.solr.adapters.IOpenBitSet;
import org.alfresco.solr.tracker.AclTracker;
import org.alfresco.solr.tracker.DocRouter;
import org.alfresco.solr.tracker.IndexHealthReport;
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.apache.solr.common.SolrException;
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.util.NamedList;
import org.apache.solr.core.SolrCore;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.SolrQueryResponse;
import org.junit.Before;
@@ -60,7 +73,7 @@ import org.mockito.junit.MockitoJUnitRunner;
/** Unit tests for {@link org.alfresco.solr.AlfrescoCoreAdminHandler}. */
@RunWith(MockitoJUnitRunner.class)
public class AlfrescoCoreAdminHandlerTest
public class AlfrescoCoreAdminHandlerIT
{
/** The string representing a transaction report. */
private static final String TXREPORT = "TXREPORT";
@@ -105,6 +118,169 @@ public class AlfrescoCoreAdminHandlerTest
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. */
@Test
public void handleCustomActionTXReportSuccess() throws Exception
@@ -143,8 +319,6 @@ public class AlfrescoCoreAdminHandlerTest
public void handleCustomActionTXReportMissingTXId()
{
when(params.get(CoreAdminParams.ACTION)).thenReturn(TXREPORT);
when(params.get(ARG_TXID)).thenReturn(null);
alfrescoCoreAdminHandler.handleCustomAction(req, rsp);
verify(rsp, never()).add(anyString(), any());
@@ -156,11 +330,8 @@ public class AlfrescoCoreAdminHandlerTest
{
when(params.get(CoreAdminParams.ACTION)).thenReturn(TXREPORT);
when(params.get(CoreAdminParams.CORE)).thenReturn(null);
when(params.get(ARG_TXID)).thenReturn(TX_ID);
alfrescoCoreAdminHandler.handleCustomAction(req, rsp);
verify(rsp, never()).add(anyString(), any());
}
/** Check that when an unknown action is provided we don't generate a report. */
@@ -212,10 +383,9 @@ public class AlfrescoCoreAdminHandlerTest
public void coreNamesAreTrimmed_oneCoreNameAtTime() {
AlfrescoCoreAdminHandler spy = spy(new AlfrescoCoreAdminHandler() {
@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
return true;
}
});
@@ -238,10 +408,9 @@ public class AlfrescoCoreAdminHandlerTest
public void validAndInvalidCoreNames() {
AlfrescoCoreAdminHandler spy = spy(new AlfrescoCoreAdminHandler() {
@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
return true;
}
});
@@ -37,8 +37,9 @@ import org.quartz.SchedulerException;
@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"})
@SolrTestCaseJ4.SuppressSSL
public class AlfrescoSolrReloadTest extends AbstractAlfrescoSolrTests {
private static Log logger = LogFactory.getLog(org.alfresco.solr.tracker.AlfrescoSolrTrackerTest.class);
public class AlfrescoSolrReloadIT extends AbstractAlfrescoSolrIT
{
private static Log logger = LogFactory.getLog(org.alfresco.solr.tracker.AlfrescoSolrTrackerIT.class);
@BeforeClass
public static void beforeClass() throws Exception {
@@ -77,7 +77,7 @@ import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.namespace.QName;
import org.alfresco.solr.AbstractAlfrescoSolrTests.SolrServletRequest;
import org.alfresco.solr.AbstractAlfrescoSolrIT.SolrServletRequest;
import org.alfresco.solr.client.Acl;
import org.alfresco.solr.client.AclChangeSet;
import org.alfresco.solr.client.AclReaders;
@@ -30,7 +30,7 @@ import org.junit.BeforeClass;
import org.junit.Test;
@SolrTestCaseJ4.SuppressSSL
public class AlfrescoTrackerRegistrationTest extends AbstractAlfrescoSolrTests
public class AlfrescoTrackerRegistrationIT extends AbstractAlfrescoSolrIT
{
@BeforeClass
public static void beforeClass() throws Exception {
@@ -51,7 +51,7 @@ import static org.alfresco.solr.AlfrescoSolrUtils.getCore;
*/
@SolrTestCaseJ4.SuppressSSL
@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"})
public class CoresCreateUpdateDistributedTest extends AbstractAlfrescoDistributedTest
public class CoresCreateUpdateDistributedIT extends AbstractAlfrescoDistributedIT
{
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
final static String JETTY_SERVER_ID = "CoresCreateUpdateDistributedTest";
@@ -40,7 +40,7 @@ import static org.alfresco.solr.AlfrescoSolrUtils.getCore;
*/
@SolrTestCaseJ4.SuppressSSL
@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"})
public class CoresCreateViaPropertyTest extends AbstractAlfrescoDistributedTest
public class CoresCreateViaPropertyIT extends AbstractAlfrescoDistributedIT
{
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
final static String JETTY_SERVER_ID = "CoresCreateViaPropertyTest";
@@ -72,79 +72,4 @@ public class SolrDataModelTest
Long actualId = AlfrescoSolrDataModel.parseTransactionId(id);
assertEquals(expectedId, actualId);
}
@Test
public void smokeTestCMISModel()
{
AlfrescoSolrDataModel dataModel = new AlfrescoSolrDataModel();
// load test model containing content properties multiple
ClassLoader cl = SolrDataModelTest.class.getClassLoader();
InputStream modelStream = cl.getResourceAsStream("alfresco/model/dictionaryModel.xml");
assertNotNull(modelStream);
M2Model model = M2Model.createModel(modelStream);
dataModel.putModel(model);
modelStream = cl.getResourceAsStream("alfresco/model/cmisModel.xml");
assertNotNull(modelStream);
model = M2Model.createModel(modelStream);
dataModel.putModel(model);
assertEquals(2, dataModel.getAlfrescoModels().size());
assertEquals(1, dataModel.getIndexedFieldNamesForProperty(OBJECT_ID).getFields().size());
assertEquals(4, dataModel.getIndexedFieldNamesForProperty(NAME).getFields().size());
assertEquals(1, dataModel.getIndexedFieldNamesForProperty(CREATION_DATE).getFields().size());
assertEquals(0, dataModel.getIndexedFieldNamesForProperty(IS_IMMUTABLE).getFields().size());
assertEquals(0, dataModel.getIndexedFieldNamesForProperty(IS_PRIVATE_WOKING_COPY).getFields().size());
assertEquals(1, dataModel.getIndexedFieldNamesForProperty(CONTENT_STREAM_LENGTH).getFields().size());
assertEquals(1, dataModel .getQueryableFields(OBJECT_ID, null, FieldUse.FACET).getFields().size());
assertEquals(1, dataModel .getQueryableFields(OBJECT_ID, null, FieldUse.COMPLETION).getFields().size());
assertEquals(1, dataModel .getQueryableFields(OBJECT_ID, null, FieldUse.FTS).getFields().size());
assertEquals(1, dataModel .getQueryableFields(OBJECT_ID, null, FieldUse.ID).getFields().size());
assertEquals(1, dataModel .getQueryableFields(OBJECT_ID, null, FieldUse.MULTI_FACET).getFields().size());
assertEquals(1, dataModel .getQueryableFields(OBJECT_ID, null, FieldUse.SORT).getFields().size());
assertEquals(1, dataModel .getQueryableFields(OBJECT_ID, null, FieldUse.STATS).getFields().size());
assertEquals(1, dataModel .getQueryableFields(OBJECT_ID, null, FieldUse.SUGGESTION).getFields().size());
assertEquals(1, dataModel .getQueryableFields(NAME, null, FieldUse.FACET).getFields().size());
assertEquals(1, dataModel .getQueryableFields(NAME, null, FieldUse.COMPLETION).getFields().size());
assertEquals(1, dataModel .getQueryableFields(NAME, null, FieldUse.FTS).getFields().size());
assertEquals(2, dataModel .getQueryableFields(NAME, null, FieldUse.ID).getFields().size());
assertEquals(1, dataModel .getQueryableFields(NAME, null, FieldUse.MULTI_FACET).getFields().size());
assertEquals(1, dataModel .getQueryableFields(NAME, null, FieldUse.SORT).getFields().size());
assertEquals(1, dataModel .getQueryableFields(NAME, null, FieldUse.STATS).getFields().size());
assertEquals(1, dataModel .getQueryableFields(NAME, null, FieldUse.SUGGESTION).getFields().size());
assertEquals(1, dataModel .getQueryableFields(CREATION_DATE, null, FieldUse.FACET).getFields().size());
assertEquals(1, dataModel .getQueryableFields(CREATION_DATE, null, FieldUse.COMPLETION).getFields().size());
assertEquals(1, dataModel .getQueryableFields(CREATION_DATE, null, FieldUse.FTS).getFields().size());
assertEquals(1, dataModel .getQueryableFields(CREATION_DATE, null, FieldUse.ID).getFields().size());
assertEquals(1, dataModel .getQueryableFields(CREATION_DATE, null, FieldUse.MULTI_FACET).getFields().size());
assertEquals(1, dataModel .getQueryableFields(CREATION_DATE, null, FieldUse.SORT).getFields().size());
assertEquals(1, dataModel .getQueryableFields(CREATION_DATE, null, FieldUse.STATS).getFields().size());
assertEquals(1, dataModel .getQueryableFields(CREATION_DATE, null, FieldUse.SUGGESTION).getFields().size());
assertEquals(1, dataModel .getQueryableFields(IS_PRIVATE_WOKING_COPY, null, FieldUse.FACET).getFields().size());
assertEquals(1, dataModel .getQueryableFields(IS_PRIVATE_WOKING_COPY, null, FieldUse.COMPLETION).getFields().size());
assertEquals(1, dataModel .getQueryableFields(IS_PRIVATE_WOKING_COPY, null, FieldUse.FTS).getFields().size());
assertEquals(1, dataModel .getQueryableFields(IS_PRIVATE_WOKING_COPY, null, FieldUse.ID).getFields().size());
assertEquals(1, dataModel .getQueryableFields(IS_PRIVATE_WOKING_COPY, null, FieldUse.MULTI_FACET).getFields().size());
assertEquals(1, dataModel .getQueryableFields(IS_PRIVATE_WOKING_COPY, null, FieldUse.SORT).getFields().size());
assertEquals(1, dataModel .getQueryableFields(IS_PRIVATE_WOKING_COPY, null, FieldUse.STATS).getFields().size());
assertEquals(1, dataModel .getQueryableFields(IS_PRIVATE_WOKING_COPY, null, FieldUse.SUGGESTION).getFields().size());
assertEquals(1, dataModel .getQueryableFields(CONTENT_STREAM_LENGTH, null, FieldUse.FACET).getFields().size());
assertEquals(1, dataModel .getQueryableFields(CONTENT_STREAM_LENGTH, null, FieldUse.COMPLETION).getFields().size());
assertEquals(1, dataModel .getQueryableFields(CONTENT_STREAM_LENGTH, null, FieldUse.FTS).getFields().size());
assertEquals(1, dataModel .getQueryableFields(CONTENT_STREAM_LENGTH, null, FieldUse.ID).getFields().size());
assertEquals(1, dataModel .getQueryableFields(CONTENT_STREAM_LENGTH, null, FieldUse.MULTI_FACET).getFields().size());
assertEquals(1, dataModel .getQueryableFields(CONTENT_STREAM_LENGTH, null, FieldUse.SORT).getFields().size());
assertEquals(1, dataModel .getQueryableFields(CONTENT_STREAM_LENGTH, null, FieldUse.STATS).getFields().size());
assertEquals(1, dataModel .getQueryableFields(CONTENT_STREAM_LENGTH, null, FieldUse.SUGGESTION).getFields().size());
}
}
@@ -69,7 +69,7 @@ import static org.alfresco.solr.AlfrescoSolrUtils.createCoreUsingTemplate;
* @author Michael Suzuki
*/
@ThreadLeakLingering(linger = 5000)
public abstract class SolrTestInitializer extends SolrTestCaseJ4
public abstract class SolrITInitializer extends SolrTestCaseJ4
{
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@@ -40,7 +40,7 @@ import static org.alfresco.solr.AlfrescoSolrUtils.*;
*/
@SolrTestCaseJ4.SuppressSSL
@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"})
public class TemplatesDistributedTest extends AbstractAlfrescoDistributedTest
public class TemplatesDistributedIT extends AbstractAlfrescoDistributedIT
{
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
final static String JETTY_SERVER_ID = "TemplatesDistributedTest";
@@ -18,7 +18,7 @@
*/
package org.alfresco.solr.highlight;
import org.alfresco.solr.AbstractAlfrescoDistributedTest;
import org.alfresco.solr.AbstractAlfrescoDistributedIT;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.util.LuceneTestCase;
@@ -35,9 +35,9 @@ import org.junit.Test;
*/
@SolrTestCaseJ4.SuppressSSL
@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"})
public class AlfrescoHighligherDistributedTest extends AbstractAlfrescoDistributedTest
public class AlfrescoHighligherDistributedIT extends AbstractAlfrescoDistributedIT
{
private static Log logger = LogFactory.getLog(AlfrescoHighligherDistributedTest.class);
private static Log logger = LogFactory.getLog(AlfrescoHighligherDistributedIT.class);
@BeforeClass
private static void initData() throws Throwable
@@ -22,13 +22,9 @@ package org.alfresco.solr.highlight;
import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.search.adaptor.lucene.QueryConstants;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
import org.alfresco.solr.AbstractAlfrescoSolrTests;
import org.alfresco.solr.AlfrescoCoreAdminHandler;
import org.alfresco.solr.AbstractAlfrescoSolrIT;
import org.alfresco.solr.client.*;
import org.alfresco.solr.dataload.TestDataProvider;
import org.alfresco.util.Pair;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.index.Term;
@@ -37,39 +33,27 @@ import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.LegacyNumericRangeQuery;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.params.HighlightParams;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.response.BasicResultContext;
import org.apache.solr.response.SolrQueryResponse;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Random;
import static com.google.common.collect.ImmutableMap.of;
import static java.util.Arrays.asList;
import static java.util.stream.IntStream.range;
import static junit.framework.TestCase.assertTrue;
import static org.alfresco.model.ContentModel.PROP_CREATOR;
import static org.alfresco.model.ContentModel.PROP_RATING_SCHEME;
import static org.alfresco.model.ContentModel.TYPE_CONTENT;
import static org.alfresco.solr.AlfrescoSolrUtils.*;
import static org.apache.solr.SolrJettyTestBase.jetty;
import static org.junit.Assert.assertNotNull;
@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"})
public class AlfrescoHighlighterTest extends AbstractAlfrescoSolrTests
public class AlfrescoHighlighterIT extends AbstractAlfrescoSolrIT
{
private static Log logger = LogFactory.getLog(AlfrescoHighlighterTest.class);
private static Log logger = LogFactory.getLog(AlfrescoHighlighterIT.class);
private static long MAX_WAIT_TIME = 80000;
@BeforeClass
@@ -1,176 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.alfresco.solr.highlight;
import org.alfresco.solr.AbstractAlfrescoSolrTests;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.handler.component.AlfrescoSolrHighlighter;
import org.apache.solr.handler.component.HighlightComponent;
import org.apache.solr.highlight.PostingsSolrHighlighter;
import org.apache.solr.highlight.SolrHighlighter;
import org.apache.solr.schema.IndexSchema;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static junit.framework.TestCase.*;
@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"})
public class TestPostingsSolrHighlighter extends AbstractAlfrescoSolrTests
{
@BeforeClass
public static void beforeClass() throws Exception
{
initAlfrescoCore("schema.xml");
// test our config is sane, just to be sure:
// postingshighlighter should be used
SolrHighlighter highlighter = HighlightComponent.getHighlighter(getCore());
assertTrue("wrong highlighter: " + highlighter.getClass(), highlighter instanceof AlfrescoSolrHighlighter);
// 'text' and 'text3' should have offsets, 'text2' should not
IndexSchema schema = getCore().getLatestSchema();
assertTrue(schema.getField("text").storeOffsetsWithPositions());
assertTrue(schema.getField("text3").storeOffsetsWithPositions());
assertFalse(schema.getField("text2").storeOffsetsWithPositions());
}
@Before
public void setUp() throws Exception
{
// if you override setUp or tearDown, you better call
// the super classes version
clearIndex();
assertU(adoc("text", "document one", "text2", "document one", "text3", "crappy document", "id", "101"));
assertU(adoc("text", "second document", "text2", "second document", "text3", "crappier document", "id", "102"));
assertU(commit());
}
@Test
public void testSimple() {
assertQ("simplest test",
req("q", "text:document", "sort", "id asc", "hl", "true"),
"count(//lst[@name='highlighting']/*)=2",
"//lst[@name='highlighting']/lst[@name='101']/arr[@name='text']/str='<em>document</em> one'",
"//lst[@name='highlighting']/lst[@name='102']/arr[@name='text']/str='second <em>document</em>'");
}
public void testPagination() {
assertQ("pagination test",
req("q", "text:document", "sort", "id asc", "hl", "true", "rows", "1", "start", "1"),
"count(//lst[@name='highlighting']/*)=1",
"//lst[@name='highlighting']/lst[@name='102']/arr[@name='text']/str='second <em>document</em>'");
}
public void testEmptySnippet() {
assertQ("null snippet test",
req("q", "text:one OR *:*", "sort", "id asc", "hl", "true"),
"count(//lst[@name='highlighting']/*)=2",
"//lst[@name='highlighting']/lst[@name='101']/arr[@name='text']/str='document <em>one</em>'",
"count(//lst[@name='highlighting']/lst[@name='102']/arr[@name='text']/*)=0");
}
public void testDefaultSummary() {
assertQ("null snippet test",
req("q", "text:one OR *:*", "sort", "id asc", "hl", "true", "hl.defaultSummary", "true"),
"count(//lst[@name='highlighting']/*)=2",
"//lst[@name='highlighting']/lst[@name='101']/arr[@name='text']/str='document <em>one</em>'",
"//lst[@name='highlighting']/lst[@name='102']/arr[@name='text']/str='second document'");
}
public void testDifferentField() {
assertQ("highlighting text3",
req("q", "text3:document", "sort", "id asc", "hl", "true", "hl.fl", "text3"),
"count(//lst[@name='highlighting']/*)=2",
"//lst[@name='highlighting']/lst[@name='101']/arr[@name='text3']/str='crappy <em>document</em>'",
"//lst[@name='highlighting']/lst[@name='102']/arr[@name='text3']/str='crappier <em>document</em>'");
}
public void testTwoFields() {
assertQ("highlighting text and text3",
req("q", "text:document text3:document", "sort", "id asc", "hl", "true", "hl.fl", "text,text3"),
"count(//lst[@name='highlighting']/*)=2",
"//lst[@name='highlighting']/lst[@name='101']/arr[@name='text']/str='<em>document</em> one'",
"//lst[@name='highlighting']/lst[@name='101']/arr[@name='text3']/str='crappy <em>document</em>'",
"//lst[@name='highlighting']/lst[@name='102']/arr[@name='text']/str='second <em>document</em>'",
"//lst[@name='highlighting']/lst[@name='102']/arr[@name='text3']/str='crappier <em>document</em>'");
}
/**
public void testMisconfiguredField() {
ignoreException("was indexed without offsets");
try {
assertQ("should fail, has no offsets",
req("q", "text2:document", "sort", "id asc", "hl", "true", "hl.fl", "text2"));
fail();
} catch (Exception expected) {
// expected
}
resetExceptionIgnores();
}
**/
public void testTags() {
assertQ("different pre/post tags",
req("q", "text:document", "sort", "id asc", "hl", "true", "hl.tag.pre", "[", "hl.tag.post", "]"),
"count(//lst[@name='highlighting']/*)=2",
"//lst[@name='highlighting']/lst[@name='101']/arr[@name='text']/str='[document] one'",
"//lst[@name='highlighting']/lst[@name='102']/arr[@name='text']/str='second [document]'");
}
public void testTagsPerField() {
assertQ("highlighting text and text3",
req("q", "text:document text3:document", "sort", "id asc", "hl", "true", "hl.fl", "text,text3", "f.text3.hl.tag.pre", "[", "f.text3.hl.tag.post", "]"),
"count(//lst[@name='highlighting']/*)=2",
"//lst[@name='highlighting']/lst[@name='101']/arr[@name='text']/str='<em>document</em> one'",
"//lst[@name='highlighting']/lst[@name='101']/arr[@name='text3']/str='crappy [document]'",
"//lst[@name='highlighting']/lst[@name='102']/arr[@name='text']/str='second <em>document</em>'",
"//lst[@name='highlighting']/lst[@name='102']/arr[@name='text3']/str='crappier [document]'");
}
public void testBreakIterator() {
assertQ("different breakiterator",
req("q", "text:document", "sort", "id asc", "hl", "true", "hl.bs.type", "WORD"),
"count(//lst[@name='highlighting']/*)=2",
"//lst[@name='highlighting']/lst[@name='101']/arr[@name='text']/str='<em>document</em>'",
"//lst[@name='highlighting']/lst[@name='102']/arr[@name='text']/str='<em>document</em>'");
}
public void testBreakIterator2() {
assertU(adoc("text", "Document one has a first sentence. Document two has a second sentence.", "id", "103"));
assertU(commit());
assertQ("different breakiterator",
req("q", "text:document", "sort", "id asc", "hl", "true", "hl.bs.type", "WHOLE"),
"//lst[@name='highlighting']/lst[@name='103']/arr[@name='text']/str='<em>Document</em> one has a first sentence. <em>Document</em> two has a second sentence.'");
}
public void testEncoder() {
assertU(adoc("text", "Document one has a first <i>sentence</i>.", "id", "103"));
assertU(commit());
assertQ("html escaped",
req("q", "text:document", "sort", "id asc", "hl", "true", "hl.encoder", "html"),
"//lst[@name='highlighting']/lst[@name='103']/arr[@name='text']/str='<em>Document</em>&#32;one&#32;has&#32;a&#32;first&#32;&lt;i&gt;sentence&lt;&#x2F;i&gt;&#46;'");
}
public void testWildcard() {
assertQ("simplest test",
req("q", "text:doc*ment", "sort", "id asc", "hl", "true", "hl.highlightMultiTerm", "true"),
"count(//lst[@name='highlighting']/*)=2",
"//lst[@name='highlighting']/lst[@name='101']/arr[@name='text']/str='<em>document</em> one'",
"//lst[@name='highlighting']/lst[@name='102']/arr[@name='text']/str='second <em>document</em>'");
}
}
@@ -0,0 +1,170 @@
/*
* Copyright (C) 2005-2013 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.lifecycle;
import org.alfresco.solr.SolrInformationServer;
import org.alfresco.solr.client.SOLRAPIClient;
import org.alfresco.solr.tracker.AclTracker;
import org.alfresco.solr.tracker.CascadeTracker;
import org.alfresco.solr.tracker.ContentTracker;
import org.alfresco.solr.tracker.MetadataTracker;
import org.alfresco.solr.tracker.SolrTrackerScheduler;
import org.alfresco.solr.tracker.Tracker;
import org.alfresco.solr.tracker.TrackerRegistry;
import org.apache.solr.core.SolrConfig;
import org.apache.solr.core.SolrCore;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.xml.sax.InputSource;
import java.util.List;
import java.util.Properties;
import static java.util.Arrays.asList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* Unit tests for the {@link SolrCoreLoadListener}.
*
* @author Andrea Gazzarini
* @since 1.5
*/
@RunWith(MockitoJUnitRunner.class)
public class SolrCoreLoadListenerTest
{
private SolrCoreLoadListener listener;
@Mock
private SolrCore core;
@Mock
private SolrTrackerScheduler scheduler;
@Mock
private SOLRAPIClient api;
@Mock
private SolrInformationServer informationServer;
@Mock
private TrackerRegistry registry;
private Properties coreProperties;
private String coreName = "XYZ";
@Before
public void setUp()
{
listener = new SolrCoreLoadListener(core);
when(core.getName()).thenReturn(coreName);
coreProperties = new Properties();
}
@Test
public void coreTrackersRegistrationAndScheduling()
{
List<Tracker> coreTrackers = listener.createAndScheduleCoreTrackers(core, registry, coreProperties, scheduler, api, informationServer);
verify(registry).register(eq(coreName), any(AclTracker.class));
verify(registry).register(eq(coreName), any(ContentTracker.class));
verify(registry).register(eq(coreName), any(MetadataTracker.class));
verify(registry).register(eq(coreName), any(CascadeTracker.class));
verify(scheduler).schedule(any(AclTracker.class), eq(coreName), same(coreProperties));
verify(scheduler).schedule(any(ContentTracker.class), eq(coreName), same(coreProperties));
verify(scheduler).schedule(any(MetadataTracker.class), eq(coreName), same(coreProperties));
verify(scheduler).schedule(any(CascadeTracker.class), eq(coreName), same(coreProperties));
assertEquals(4, coreTrackers.size());
}
@Test
public void trackersShutDownProcedure()
{
List<Tracker> coreTrackers =
asList(mock(AclTracker.class), mock(ContentTracker.class), mock(MetadataTracker.class), mock(CascadeTracker.class));
listener.shutdownTrackers(core, coreTrackers, scheduler, false);
coreTrackers.forEach(tracker -> verify(tracker).setShutdown(true));
coreTrackers.forEach(tracker -> verify(scheduler).deleteJobForTrackerInstance(core.getName(), tracker));
coreTrackers.forEach(tracker -> verify(tracker).shutdown());
}
@Test
public void noReplicationHandlerDefined_thenContentStoreIsInReadWriteMode() throws Exception
{
prepare("solrconfig_no_replication_handler_defined.xml");
assertFalse("If no replication handler is defined, then we expect to run a RW content store.", listener.isSlaveModeEnabledFor(core));
}
@Test
public void emptyReplicationHandlerDefined_thenContentStoreIsInReadWriteMode() throws Exception
{
prepare("solrconfig_empty_replication_handler.xml");
assertFalse("If an empty replication handler is defined, then we expect to run a RW content store.", listener.isSlaveModeEnabledFor(core));
}
@Test
public void slaveReplicationHandlerDefinedButDisabled_thenContentStoreIsInReadWriteMode() throws Exception
{
prepare("solrconfig_slave_disabled_replication_handler.xml");
assertFalse("If a slave replication handler is defined but disabled, then we expect to run a RW content store.", listener.isSlaveModeEnabledFor(core));
}
@Test
public void masterReplicationHandlerDefined_thenContentStoreIsInReadWriteMode() throws Exception
{
prepare("solrconfig_master_replication_handler.xml");
assertFalse("If a master replication handler is defined but disabled, then we expect to run a RW content store.", listener.isSlaveModeEnabledFor(core));
}
@Test
public void masterReplicationHandlerDefinedButDisabled_thenContentStoreIsInReadWriteMode() throws Exception
{
prepare("solrconfig_master_disabled_replication_handler.xml");
assertFalse("If a master replication handler is defined but disabled, then we expect to run a RW content store.", listener.isSlaveModeEnabledFor(core));
}
@Test
public void slaveReplicationHandlerDefined_thenContentStoreIsInReadOnlyMode() throws Exception
{
prepare("solrconfig_slave_replication_handler.xml");
assertTrue("If a slave replication handler is defined, then we expect to run a RO content store.", listener.isSlaveModeEnabledFor(core));
}
private void prepare(String configName) throws Exception
{
SolrConfig solrConfig = new SolrConfig(configName, new InputSource(getClass().getResourceAsStream("/test-files/" + configName)));
when(core.getSolrConfig()).thenReturn(solrConfig);
}
}
@@ -22,7 +22,7 @@ package org.alfresco.solr.query;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import org.alfresco.solr.AbstractAlfrescoSolrTests;
import org.alfresco.solr.AbstractAlfrescoSolrIT;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.util.NamedList;
@@ -38,7 +38,7 @@ import org.junit.Test;
@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"})
public class AlfrescoReRankQParserPluginTest extends AbstractAlfrescoSolrTests
public class AlfrescoReRankQParserPluginIT extends AbstractAlfrescoSolrIT
{
@BeforeClass
public static void beforeClass() throws Exception
@@ -21,7 +21,7 @@ package org.alfresco.solr.query;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.search.adaptor.lucene.QueryConstants;
import org.alfresco.solr.AbstractAlfrescoSolrTests;
import org.alfresco.solr.AbstractAlfrescoSolrIT;
import org.alfresco.solr.client.Acl;
import org.alfresco.solr.client.AclChangeSet;
import org.alfresco.solr.client.AclReaders;
@@ -51,7 +51,7 @@ import static java.util.Collections.singletonList;
import static java.util.stream.IntStream.range;
import static org.alfresco.solr.AlfrescoSolrUtils.*;
public class AlfrescoSolrFingerprintTest extends AbstractAlfrescoSolrTests
public class AlfrescoSolrFingerprintIT extends AbstractAlfrescoSolrIT
{
private static long MAX_WAIT_TIME = 80000;
@@ -19,31 +19,17 @@
package org.alfresco.solr.query;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import org.alfresco.solr.AbstractAlfrescoSolrTests;
import org.alfresco.solr.AbstractAlfrescoSolrIT;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.RefCount;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.ResultContext;
import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.search.DocIterator;
import org.apache.solr.search.DocList;
import org.apache.solr.search.SolrIndexSearcher;
import org.apache.solr.util.RefCounted;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"})
public class AlfrescoSolrSpellcheckerTest extends AbstractAlfrescoSolrTests
public class AlfrescoSolrSpellcheckerIT extends AbstractAlfrescoSolrIT
{
@BeforeClass
public static void beforeClass() throws Exception
@@ -34,7 +34,7 @@ import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.solr.AbstractAlfrescoSolrTests;
import org.alfresco.solr.AbstractAlfrescoSolrIT;
import org.alfresco.solr.client.ContentPropertyValue;
import org.alfresco.solr.client.MLTextPropertyValue;
import org.alfresco.solr.client.PropertyValue;
@@ -46,7 +46,7 @@ import org.junit.BeforeClass;
* @author Michael Suzuki
*
*/
public class AuthDataLoad extends AbstractAlfrescoSolrTests
public class AuthDataLoad extends AbstractAlfrescoSolrIT
{
static int count = 100;
static long maxReader = 1000;
@@ -39,7 +39,7 @@ import org.junit.Test;
* @author Michael Suzuki
*
*/
public class AuthQueryTest extends AuthDataLoad
public class AuthQueryIT extends AuthDataLoad
{
@Test
public void checkAuth()
@@ -109,7 +109,6 @@ public class AuthQueryTest extends AuthDataLoad
searchParameters.setQuery(queryString);
Query query = dataModel.getFTSQuery(new Pair<SearchParameters, Boolean>(searchParameters, Boolean.FALSE),
solrQueryRequest, FTSQueryParser.RerankPhase.SINGLE_PASS);
System.out.println("##################### Query:"+query);
TopDocs docs = solrIndexSearcher.search(query, count * 2 + 10);
Assert.assertEquals(count, docs.totalHits);
@@ -18,7 +18,7 @@
*/
package org.alfresco.solr.query;
import org.alfresco.solr.AbstractAlfrescoDistributedTest;
import org.alfresco.solr.AbstractAlfrescoDistributedIT;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.client.solrj.response.FacetField;
@@ -37,12 +37,12 @@ import static org.hamcrest.core.Is.is;
@SolrTestCaseJ4.SuppressSSL @LuceneTestCase.SuppressCodecs({ "Appending", "Lucene3x", "Lucene40", "Lucene41",
"Lucene42", "Lucene43", "Lucene44", "Lucene45", "Lucene46", "Lucene47", "Lucene48",
"Lucene49" }) public class DistributedAlfrescoSolrFacetingTest extends AbstractAlfrescoDistributedTest
"Lucene49" }) public class DistributedAlfrescoSolrFacetingIT extends AbstractAlfrescoDistributedIT
{
@BeforeClass
private static void initData() throws Throwable
{
initSolrServers(2, "DistributedAlfrescoSolrFacetingTest", null);
initSolrServers(2, "DistributedAlfrescoSolrFacetingIT", null);
indexSampleDocumentsForFacetingMincount();
}
@@ -34,7 +34,7 @@ import java.util.Random;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.search.adaptor.lucene.QueryConstants;
import org.alfresco.solr.AbstractAlfrescoDistributedTest;
import org.alfresco.solr.AbstractAlfrescoDistributedIT;
import org.alfresco.solr.client.Acl;
import org.alfresco.solr.client.AclChangeSet;
import org.alfresco.solr.client.AclReaders;
@@ -61,7 +61,7 @@ import org.junit.Test;
*/
@SolrTestCaseJ4.SuppressSSL
@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"})
public class DistributedAlfrescoSolrFingerPrintTest extends AbstractAlfrescoDistributedTest
public class DistributedAlfrescoSolrFingerPrintIT extends AbstractAlfrescoDistributedIT
{
private static long MAX_WAIT_TIME = 80000;
@@ -18,7 +18,7 @@
*/
package org.alfresco.solr.query;
import org.alfresco.solr.AbstractAlfrescoDistributedTest;
import org.alfresco.solr.AbstractAlfrescoDistributedIT;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.client.solrj.response.QueryResponse;
@@ -32,7 +32,7 @@ import org.junit.Test;
*/
@SolrTestCaseJ4.SuppressSSL
@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"})
public class DistributedAlfrescoSolrSpellcheckerTest extends AbstractAlfrescoDistributedTest
public class DistributedAlfrescoSolrSpellcheckerIT extends AbstractAlfrescoDistributedIT
{
@BeforeClass
private static void initData() throws Throwable
@@ -20,19 +20,18 @@
package org.alfresco.solr.query;
import org.alfresco.repo.search.adaptor.lucene.QueryConstants;
import org.alfresco.solr.AbstractAlfrescoSolrTests;
import org.alfresco.solr.AbstractAlfrescoSolrIT;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runners.Parameterized.Parameters;
@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"})
@SolrTestCaseJ4.SuppressSSL
public class SolrAuthTest extends AbstractAlfrescoSolrTests
public class SolrAuthIT extends AbstractAlfrescoSolrIT
{
@BeforeClass
@@ -18,9 +18,7 @@
*/
package org.alfresco.solr.query;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.search.GeneralHighlightParameters;
import org.alfresco.solr.AbstractAlfrescoSolrTests;
import org.alfresco.solr.AbstractAlfrescoSolrIT;
import org.junit.Before;
import org.junit.Test;
@@ -32,7 +30,7 @@ import org.junit.Test;
* @author Michael Suzuki
*
*/
public class UntokenisedFieldTest extends AbstractAlfrescoSolrTests
public class UntokenisedFieldIT extends AbstractAlfrescoSolrIT
{
String nodeRef = "workspace://SpacesStore/00000000-0000-1-4731-76966678";
String nodeRefS = "noderef@s_@mytest" ;
@@ -18,25 +18,16 @@
*/
package org.alfresco.solr.query.afts.qparser;
import static java.util.Arrays.asList;
import static java.util.stream.IntStream.range;
import org.alfresco.solr.AbstractAlfrescoSolrTests;
import org.alfresco.solr.AbstractAlfrescoSolrIT;
import org.junit.BeforeClass;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Supertype layer for all AFTS QParser tests.
*
* @author Andrea Gazzarini
*/
public abstract class AbstractQParserPluginTest extends AbstractAlfrescoSolrTests
public abstract class AbstractQParserPluginIT extends AbstractAlfrescoSolrIT
{
@BeforeClass
public static void spinUpSolr() throws Exception
@@ -24,7 +24,7 @@ import org.alfresco.util.ISO9075;
import org.junit.BeforeClass;
import org.junit.Test;
public class FieldNameEscapingTest extends AbstractQParserPluginTest implements QueryConstants
public class FieldNameEscapingIT extends AbstractQParserPluginIT implements QueryConstants
{
private static TestDataProvider DATASETS_PROVIDER;
@@ -43,7 +43,7 @@ import org.junit.BeforeClass;
import org.junit.Test;
@SolrTestCaseJ4.SuppressSSL
public class QParserPluginTest extends AbstractQParserPluginTest implements QueryConstants
public class QParserPluginIT extends AbstractQParserPluginIT implements QueryConstants
{
/** The UTC time zone. */
private static final TimeZone UTC = TimeZone.getTimeZone("UTC");
@@ -49,7 +49,7 @@ import static com.google.common.collect.ImmutableMap.of;
* This test set checks that in all these query types the default fields are involved in the search.
*
*/
public class AFTSDefaultTextQueryTest extends AbstractRequestHandlerTest
public class AFTSDefaultTextQueryIT extends AbstractRequestHandlerIT
{
@BeforeClass
@@ -39,7 +39,7 @@ import org.junit.Test;
*
* @author msuzuki
*/
public class AFTSDisjunctionTest extends AbstractRequestHandlerTest
public class AFTSDisjunctionIT extends AbstractRequestHandlerIT
{
@BeforeClass
public static void beforeClass() throws Exception
@@ -43,7 +43,7 @@ import java.util.Map;
* @author eporciani
* @author agazzarini
*/
public class AFTSIdentifierFieldsTest extends AbstractRequestHandlerTest
public class AFTSIdentifierFieldsIT extends AbstractRequestHandlerIT
{
@BeforeClass
public static void beforeClass() throws Exception
@@ -41,7 +41,7 @@ import java.util.Map;
*
* @author elia
*/
public class AFTSRangeQueryTest extends AbstractRequestHandlerTest
public class AFTSRangeQueryIT extends AbstractRequestHandlerIT
{
@BeforeClass
public static void beforeClass() throws Exception
@@ -20,7 +20,7 @@ import java.util.Locale;
@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"})
@SolrTestCaseJ4.SuppressSSL
public class AFTSRequestHandlerTest extends AbstractRequestHandlerTest implements QueryConstants
public class AFTSRequestHandlerIT extends AbstractRequestHandlerIT implements QueryConstants
{
private static TestDataProvider DATASETS_PROVIDER;
@@ -1,6 +1,6 @@
package org.alfresco.solr.query.afts.requestHandler;
import org.alfresco.solr.AbstractAlfrescoSolrTests;
import org.alfresco.solr.AbstractAlfrescoSolrIT;
import org.junit.BeforeClass;
import java.util.ArrayList;
@@ -12,7 +12,7 @@ import java.util.stream.Stream;
import static java.util.Arrays.asList;
import static java.util.stream.IntStream.range;
public abstract class AbstractRequestHandlerTest extends AbstractAlfrescoSolrTests
public abstract class AbstractRequestHandlerIT extends AbstractAlfrescoSolrIT
{
@BeforeClass
public static void spinUpSolr() throws Exception
@@ -9,7 +9,7 @@ import org.junit.Test;
*
* @author Andrea Gazzarini
*/
public class MNTTest extends AbstractRequestHandlerTest
public class MNTIT extends AbstractRequestHandlerIT
{
@BeforeClass
public static void loadData() throws Exception
@@ -27,7 +27,7 @@ import org.junit.Test;
@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"})
@SolrTestCaseJ4.SuppressSSL
public class AlfrescoCMISQParserPluginTest extends LoadCMISData implements QueryConstants
public class AlfrescoCMISQParserPluginIT extends LoadCMISData implements QueryConstants
{
@Test
public void cmisBasic() throws Exception
@@ -31,7 +31,7 @@ import org.junit.Test;
* @author Michael Suzuki
*
*/
public class CmisTest extends LoadCMISData
public class CmisIT extends LoadCMISData
{
@Before
public void setup() throws Exception
@@ -37,7 +37,7 @@ import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.solr.AbstractAlfrescoSolrTests;
import org.alfresco.solr.AbstractAlfrescoSolrIT;
import org.alfresco.solr.AlfrescoSolrDataModel;
import org.alfresco.solr.client.ContentPropertyValue;
import org.alfresco.solr.client.MLTextPropertyValue;
@@ -51,7 +51,7 @@ import org.junit.BeforeClass;
* @author Michael Suzuki
*
*/
public class LoadCMISData extends AbstractAlfrescoSolrTests
public class LoadCMISData extends AbstractAlfrescoSolrIT
{
protected static NodeRef testCMISContent00NodeRef;
protected static NodeRef testCMISRootNodeRef;
@@ -39,7 +39,7 @@ import java.util.Map;
import java.util.Properties;
@RunWith(MockitoJUnitRunner.class)
public class AclModCountRouterTest
public class AclModCountRouterIT
{
private DocRouter router;
@@ -36,7 +36,7 @@ import org.alfresco.model.ContentModel;
import org.alfresco.repo.search.adaptor.lucene.QueryConstants;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.solr.AbstractAlfrescoSolrTests;
import org.alfresco.solr.AbstractAlfrescoSolrIT;
import org.alfresco.solr.client.Acl;
import org.alfresco.solr.client.AclChangeSet;
import org.alfresco.solr.client.AclReaders;
@@ -62,9 +62,9 @@ import org.junit.Test;
@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"})
@SolrTestCaseJ4.SuppressSSL
public class AlfrescoSolrTrackerExceptionTest extends AbstractAlfrescoSolrTests
public class AlfrescoSolrTrackerExceptionIT extends AbstractAlfrescoSolrIT
{
private static Log logger = LogFactory.getLog(AlfrescoSolrTrackerTest.class);
private static Log logger = LogFactory.getLog(AlfrescoSolrTrackerExceptionIT.class);
private static long MAX_WAIT_TIME = 80000;
@BeforeClass
public static void beforeClass() throws Exception
@@ -37,7 +37,7 @@ import org.alfresco.model.ContentModel;
import org.alfresco.repo.search.adaptor.lucene.QueryConstants;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.solr.AbstractAlfrescoSolrTests;
import org.alfresco.solr.AbstractAlfrescoSolrIT;
import org.alfresco.solr.client.Acl;
import org.alfresco.solr.client.AclChangeSet;
import org.alfresco.solr.client.AclReaders;
@@ -64,9 +64,9 @@ import org.junit.Test;
@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"})
@SolrTestCaseJ4.SuppressSSL
public class AlfrescoSolrTrackerTest extends AbstractAlfrescoSolrTests
public class AlfrescoSolrTrackerIT extends AbstractAlfrescoSolrIT
{
private static Log logger = LogFactory.getLog(AlfrescoSolrTrackerTest.class);
private static Log logger = LogFactory.getLog(AlfrescoSolrTrackerIT.class);
private static long MAX_WAIT_TIME = 80000;
@BeforeClass
public static void beforeClass() throws Exception
@@ -32,7 +32,7 @@ import java.util.Collection;
import org.alfresco.repo.search.adaptor.lucene.QueryConstants;
import org.alfresco.solr.AbstractAlfrescoSolrTests;
import org.alfresco.solr.AbstractAlfrescoSolrIT;
import org.alfresco.solr.AlfrescoCoreAdminHandler;
import org.alfresco.solr.client.Acl;
@@ -58,9 +58,9 @@ import org.junit.Test;
@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"})
@SolrTestCaseJ4.SuppressSSL
public class AlfrescoSolrTrackerRollbackTest extends AbstractAlfrescoSolrTests
public class AlfrescoSolrTrackerRollbackIT extends AbstractAlfrescoSolrIT
{
private static Log logger = LogFactory.getLog(AlfrescoSolrTrackerTest.class);
private static Log logger = LogFactory.getLog(AlfrescoSolrTrackerIT.class);
private static long MAX_WAIT_TIME = 80000;
@BeforeClass
public static void beforeClass() throws Exception
@@ -36,7 +36,7 @@ import static org.junit.Assert.assertNotEquals;
import org.alfresco.repo.index.shard.ShardState;
import org.alfresco.repo.search.adaptor.lucene.QueryConstants;
import org.alfresco.solr.AbstractAlfrescoSolrTests;
import org.alfresco.solr.AbstractAlfrescoSolrIT;
import org.alfresco.solr.AlfrescoCoreAdminHandler;
import org.alfresco.solr.client.Acl;
import org.alfresco.solr.client.AclChangeSet;
@@ -70,7 +70,7 @@ import java.util.stream.Collectors;
*
* @author agazzarini
*/
public class AlfrescoSolrTrackerStateTest extends AbstractAlfrescoSolrTests
public class AlfrescoSolrTrackerStateIT extends AbstractAlfrescoSolrIT
{
@BeforeClass
public static void beforeClass() throws Exception
@@ -35,7 +35,7 @@ import org.alfresco.model.ContentModel;
import org.alfresco.repo.search.adaptor.lucene.QueryConstants;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.solr.AbstractAlfrescoSolrTests;
import org.alfresco.solr.AbstractAlfrescoSolrIT;
import org.alfresco.solr.client.*;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.*;
@@ -52,7 +52,7 @@ import java.util.List;
@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"})
@SolrTestCaseJ4.SuppressSSL
public class CascadeTrackerTest extends AbstractAlfrescoSolrTests
public class CascadeTrackerIT extends AbstractAlfrescoSolrIT
{
private static long MAX_WAIT_TIME = 80000;
@@ -38,7 +38,7 @@ import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class ContentTrackerTest
public class ContentTrackerIT
{
private ContentTracker contentTracker;
@@ -137,7 +137,7 @@ public class ContentTrackerTest
@Test
public void typeCheck()
{
Assert.assertTrue(contentTracker.getType().equals(Tracker.Type.Content));
Assert.assertTrue(contentTracker.getType().equals(Tracker.Type.CONTENT));
}
}
@@ -46,7 +46,7 @@ import java.util.Properties;
import java.util.Random;
@RunWith(MockitoJUnitRunner.class)
public class DateMonthRouterTest
public class DateMonthRouterIT
{
private Random randomizer = new Random();
@@ -19,7 +19,7 @@
package org.alfresco.solr.tracker;
import org.alfresco.repo.index.shard.ShardMethodEnum;
import org.alfresco.solr.AbstractAlfrescoDistributedTest;
import org.alfresco.solr.AbstractAlfrescoDistributedIT;
import org.alfresco.solr.SolrInformationServer;
import org.alfresco.solr.client.Acl;
import org.alfresco.solr.client.AclChangeSet;
@@ -57,7 +57,7 @@ import static org.alfresco.solr.AlfrescoSolrUtils.list;
*/
@SolrTestCaseJ4.SuppressSSL
@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"})
public class DistributedAclIdAlfrescoSolrTrackerTest extends AbstractAlfrescoDistributedTest
public class DistributedAclIdAlfrescoSolrTrackerIT extends AbstractAlfrescoDistributedIT
{
@BeforeClass
@@ -19,7 +19,7 @@
package org.alfresco.solr.tracker;
import org.alfresco.repo.search.adaptor.lucene.QueryConstants;
import org.alfresco.solr.AbstractAlfrescoDistributedTest;
import org.alfresco.solr.AbstractAlfrescoDistributedIT;
import org.alfresco.solr.client.Acl;
import org.alfresco.solr.client.AclChangeSet;
import org.alfresco.solr.client.Node;
@@ -50,7 +50,7 @@ import static org.alfresco.solr.AlfrescoSolrUtils.getTransaction;
*/
@SolrTestCaseJ4.SuppressSSL
@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"})
public class DistributedAlfrescoSolrJsonTest extends AbstractAlfrescoDistributedTest
public class DistributedAlfrescoSolrJsonIT extends AbstractAlfrescoDistributedIT
{
@BeforeClass
private static void initData() throws Throwable
@@ -19,7 +19,7 @@
package org.alfresco.solr.tracker;
import org.alfresco.repo.search.adaptor.lucene.QueryConstants;
import org.alfresco.solr.AbstractAlfrescoDistributedTest;
import org.alfresco.solr.AbstractAlfrescoDistributedIT;
import org.alfresco.solr.client.Acl;
import org.alfresco.solr.client.AclChangeSet;
import org.alfresco.solr.client.AclReaders;
@@ -56,7 +56,7 @@ import static org.alfresco.solr.AlfrescoSolrUtils.list;
*/
@SolrTestCaseJ4.SuppressSSL
@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"})
public class DistributedAlfrescoSolrTrackerTest extends AbstractAlfrescoDistributedTest
public class DistributedAlfrescoSolrTrackerIT extends AbstractAlfrescoDistributedIT
{
@BeforeClass
@@ -19,7 +19,7 @@
package org.alfresco.solr.tracker;
import org.alfresco.repo.search.adaptor.lucene.QueryConstants;
import org.alfresco.solr.AbstractAlfrescoDistributedTest;
import org.alfresco.solr.AbstractAlfrescoDistributedIT;
import org.alfresco.solr.client.Acl;
import org.alfresco.solr.client.AclChangeSet;
import org.alfresco.solr.client.AclReaders;
@@ -54,7 +54,7 @@ import static org.alfresco.solr.AlfrescoSolrUtils.indexAclChangeSet;
*/
@SolrTestCaseJ4.SuppressSSL
@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"})
public class DistributedAlfrescoSolrTrackerRaceTest extends AbstractAlfrescoDistributedTest
public class DistributedAlfrescoSolrTrackerRaceIT extends AbstractAlfrescoDistributedIT
{
@BeforeClass
@@ -33,7 +33,7 @@ import static org.alfresco.solr.AlfrescoSolrUtils.indexAclChangeSet;
import org.alfresco.repo.index.shard.ShardState;
import org.alfresco.repo.search.adaptor.lucene.QueryConstants;
import org.alfresco.solr.AbstractAlfrescoDistributedTest;
import org.alfresco.solr.AbstractAlfrescoDistributedIT;
import org.alfresco.solr.AlfrescoCoreAdminHandler;
import org.alfresco.solr.client.Acl;
import org.alfresco.solr.client.AclChangeSet;
@@ -68,7 +68,7 @@ import java.util.stream.Collectors;
* @author agazzarini
*/
@SolrTestCaseJ4.SuppressSSL
public class DistributedAlfrescoSolrTrackerStateTest extends AbstractAlfrescoDistributedTest
public class DistributedAlfrescoSolrTrackerStateIT extends AbstractAlfrescoDistributedIT
{
@BeforeClass
private static void initData() throws Throwable
@@ -30,7 +30,7 @@ import static org.alfresco.solr.AlfrescoSolrUtils.indexAclChangeSet;
import static org.carrot2.shaded.guava.common.collect.ImmutableList.of;
import org.alfresco.model.ContentModel;
import org.alfresco.solr.AbstractAlfrescoDistributedTest;
import org.alfresco.solr.AbstractAlfrescoDistributedIT;
import org.alfresco.solr.client.Acl;
import org.alfresco.solr.client.AclChangeSet;
import org.alfresco.solr.client.AclReaders;
@@ -55,7 +55,7 @@ import java.util.Properties;
*/
@SolrTestCaseJ4.SuppressSSL
@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"})
public class DistributedCascadeTrackerTest extends AbstractAlfrescoDistributedTest
public class DistributedCascadeTrackerIT extends AbstractAlfrescoDistributedIT
{
private Node parentFolder;
private NodeMetaData parentFolderMetadata;
@@ -21,7 +21,7 @@ package org.alfresco.solr.tracker;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.namespace.QName;
import org.alfresco.solr.AbstractAlfrescoDistributedTest;
import org.alfresco.solr.AbstractAlfrescoDistributedIT;
import org.alfresco.solr.AlfrescoSolrDataModel;
import org.alfresco.solr.client.Acl;
import org.alfresco.solr.client.AclChangeSet;
@@ -63,7 +63,7 @@ import static org.alfresco.solr.AlfrescoSolrUtils.indexAclChangeSet;
*/
@SolrTestCaseJ4.SuppressSSL
@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"})
public abstract class DistributedDateAbstractSolrTrackerTest extends AbstractAlfrescoDistributedTest
public abstract class DistributedDateAbstractSolrTrackerIT extends AbstractAlfrescoDistributedIT
{
@Test
public void testDateMonth() throws Exception
@@ -33,7 +33,7 @@ import org.alfresco.model.ContentModel;
import org.alfresco.repo.index.shard.ShardMethodEnum;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.namespace.QName;
import org.alfresco.solr.AbstractAlfrescoDistributedTest;
import org.alfresco.solr.AbstractAlfrescoDistributedIT;
import org.alfresco.solr.AlfrescoSolrDataModel;
import org.alfresco.solr.SolrInformationServer;
import org.alfresco.solr.client.Acl;
@@ -63,13 +63,13 @@ import java.util.Properties;
import java.util.TimeZone;
@SolrTestCaseJ4.SuppressSSL
public class DistributedDateMonthAlfrescoSolrTrackerTest extends AbstractAlfrescoDistributedTest
public class DistributedDateMonthAlfrescoSolrTrackerIT extends AbstractAlfrescoDistributedIT
{
@BeforeClass
@SuppressWarnings("unused")
public static void initData() throws Throwable
{
initSolrServers(5, DistributedDateMonthAlfrescoSolrTrackerTest.class.getSimpleName(), getShardMethod());
initSolrServers(5, DistributedDateMonthAlfrescoSolrTrackerIT.class.getSimpleName(), getShardMethod());
}
@AfterClass
@@ -33,7 +33,7 @@ import java.util.Properties;
@SolrTestCaseJ4.SuppressSSL
@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"})
public class DistributedDateQuarterAlfrescoSolrTrackerTest extends DistributedDateAbstractSolrTrackerTest
public class DistributedDateQuarterAlfrescoSolrTrackerIT extends DistributedDateAbstractSolrTrackerIT
{
@BeforeClass
@@ -33,12 +33,12 @@ import java.util.Properties;
@SolrTestCaseJ4.SuppressSSL
@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"})
public class DistributedDateSplitYearAlfrescoSolrTrackerTest extends DistributedDateAbstractSolrTrackerTest
public class DistributedDateSplitYearAlfrescoSolrTrackerIT extends DistributedDateAbstractSolrTrackerIT
{
@BeforeClass
private static void initData() throws Throwable
{
initSolrServers(3, "DistributedDateSplitYearAlfrescoSolrTrackerTest", getShardMethod());
initSolrServers(3, "DistributedDateSplitYearAlfrescoSolrTrackerIT", getShardMethod());
}
@AfterClass
@@ -18,7 +18,7 @@
*/
package org.alfresco.solr.tracker;
import org.alfresco.solr.AbstractAlfrescoDistributedTest;
import org.alfresco.solr.AbstractAlfrescoDistributedIT;
import org.alfresco.solr.SolrInformationServer;
import org.alfresco.solr.client.Acl;
import org.alfresco.solr.client.AclChangeSet;
@@ -53,12 +53,12 @@ import static org.alfresco.solr.AlfrescoSolrUtils.list;
*/
@SolrTestCaseJ4.SuppressSSL
@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"})
public class DistributedDbidRangeAlfrescoSolrTrackerTest extends AbstractAlfrescoDistributedTest
public class DistributedDbidRangeAlfrescoSolrTrackerIT extends AbstractAlfrescoDistributedIT
{
@BeforeClass
private static void initData() throws Throwable
{
initSolrServers(2, "DistributedDbidRangeAlfrescoSolrTrackerTest", getShardMethod());
initSolrServers(2, "DistributedDbidRangeAlfrescoSolrTrackerIT", getShardMethod());
}
@AfterClass
@@ -18,7 +18,7 @@
*/
package org.alfresco.solr.tracker;
import org.alfresco.solr.AbstractAlfrescoDistributedTest;
import org.alfresco.solr.AbstractAlfrescoDistributedIT;
import org.alfresco.solr.SolrInformationServer;
import org.alfresco.solr.client.Acl;
import org.alfresco.solr.client.AclChangeSet;
@@ -56,12 +56,12 @@ import static org.alfresco.solr.AlfrescoSolrUtils.list;
*/
@SolrTestCaseJ4.SuppressSSL
@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"})
public class DistributedExpandDbidRangeAlfrescoSolrTrackerTest extends AbstractAlfrescoDistributedTest
public class DistributedExpandDbidRangeAlfrescoSolrTrackerIT extends AbstractAlfrescoDistributedIT
{
@BeforeClass
private static void initData() throws Throwable
{
initSolrServers(2, "DistributedExpandDbidRangeAlfrescoSolrTrackerTest", getShardMethod());
initSolrServers(2, "DistributedExpandDbidRangeAlfrescoSolrTrackerIT", getShardMethod());
}
@AfterClass
@@ -21,7 +21,7 @@ package org.alfresco.solr.tracker;
import java.util.Properties;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.index.shard.ShardMethodEnum;
import org.alfresco.solr.AbstractAlfrescoDistributedTest;
import org.alfresco.solr.AbstractAlfrescoDistributedIT;
import org.alfresco.solr.client.Acl;
import org.alfresco.solr.client.AclChangeSet;
import org.alfresco.solr.client.AclReaders;
@@ -53,7 +53,7 @@ import static org.carrot2.shaded.guava.common.collect.ImmutableList.of;
@SolrTestCaseJ4.SuppressSSL
@SolrTestCaseJ4.SuppressObjectReleaseTracker (bugUrl = "RAMDirectory")
@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"})
public class DistributedExplicitShardIdWithStaticPropertyRouterTest extends AbstractAlfrescoDistributedTest
public class DistributedExplicitShardIdWithStaticPropertyRouterIT extends AbstractAlfrescoDistributedIT
{
private static long MAX_WAIT_TIME = 80000;
private final int timeout = 100000;
@@ -20,7 +20,7 @@ package org.alfresco.solr.tracker;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.index.shard.ShardMethodEnum;
import org.alfresco.solr.AbstractAlfrescoDistributedTest;
import org.alfresco.solr.AbstractAlfrescoDistributedIT;
import org.alfresco.solr.SolrInformationServer;
import org.alfresco.solr.client.Acl;
import org.alfresco.solr.client.AclChangeSet;
@@ -62,12 +62,12 @@ import static org.alfresco.solr.tracker.DocRouterFactory.SHARD_KEY_KEY;
@SolrTestCaseJ4.SuppressSSL
@SolrTestCaseJ4.SuppressObjectReleaseTracker (bugUrl = "RAMDirectory")
@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"})
public class DistributedExplicitShardRoutingTrackerTest extends AbstractAlfrescoDistributedTest
public class DistributedExplicitShardRoutingTrackerIT extends AbstractAlfrescoDistributedIT
{
@BeforeClass
private static void initData() throws Throwable
{
initSolrServers(3, "DistributedExplicitShardRoutingTrackerTest", getProperties());
initSolrServers(3, "DistributedExplicitShardRoutingTrackerIT", getProperties());
}
@AfterClass
@@ -41,7 +41,7 @@ import com.carrotsearch.randomizedtesting.RandomizedContext;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.index.shard.ShardMethodEnum;
import org.alfresco.solr.AbstractAlfrescoDistributedTest;
import org.alfresco.solr.AbstractAlfrescoDistributedIT;
import org.alfresco.solr.SolrInformationServer;
import org.alfresco.solr.client.Acl;
import org.alfresco.solr.client.AclChangeSet;
@@ -66,7 +66,7 @@ import org.junit.Test;
@SolrTestCaseJ4.SuppressSSL
@SolrTestCaseJ4.SuppressObjectReleaseTracker (bugUrl = "RAMDirectory")
@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"})
public class DistributedPropertyBasedAlfrescoSolrTrackerTest extends AbstractAlfrescoDistributedTest
public class DistributedPropertyBasedAlfrescoSolrTrackerIT extends AbstractAlfrescoDistributedIT
{
private static final String[] DOMAINS = {"alfresco.com", "king.com", "gmail.com", "yahoo.com", "cookie.es"};
private static final Map<String,Integer> domainsCount = new HashMap<>();
@@ -78,7 +78,7 @@ public class DistributedPropertyBasedAlfrescoSolrTrackerTest extends AbstractAlf
{
domainsCount.put(domain,0);
}
initSolrServers(4, "DistributedPropertyBasedAlfrescoSolrTrackerTest", getProperties());
initSolrServers(4, "DistributedPropertyBasedAlfrescoSolrTrackerIT", getProperties());
}
@AfterClass
@@ -41,7 +41,7 @@ import java.util.Map;
import java.util.Properties;
@RunWith(MockitoJUnitRunner.class)
public class ExplicitIDRouterTest
public class ExplicitIDRouterIT
{
private DocRouter router;
@@ -42,7 +42,7 @@ import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class ExplicitIDWithLRISRouterTest
public class ExplicitIDWithLRISRouterIT
{
private DocRouter router;
@@ -47,7 +47,7 @@ import org.junit.runner.RunWith;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class MetadataTrackerTest
@@ -58,20 +58,23 @@ public class MetadataTrackerTest
@Mock
private SOLRAPIClient repositoryClient;
private String coreName = "theCoreName";
@Mock
private InformationServer srv;
@Spy
private Properties props;
@Mock
private TrackerStats trackerStats;
@Before
public void setUp() throws Exception
public void setUp()
{
doReturn("workspace://SpacesStore").when(props).getProperty("alfresco.stores");
when(srv.getTrackerStats()).thenReturn(trackerStats);
this.metadataTracker = spy(new MetadataTracker(props, repositoryClient, coreName, srv));
String coreName = "theCoreName";
this.metadataTracker = spy(new MetadataTracker(true, props, repositoryClient, coreName, srv));
ModelTracker modelTracker = mock(ModelTracker.class);
when(modelTracker.hasModels()).thenReturn(true);
@@ -197,6 +200,4 @@ public class MetadataTrackerTest
assertSame(nodes4Tx, nodes);
}
}
@@ -56,7 +56,7 @@ import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class ModelTrackerTest
public class ModelTrackerIT
{
private ModelTracker modelTracker;
@@ -102,8 +102,6 @@ public class ModelTrackerTest
when(props.getProperty("alfresco.stores", "workspace://SpacesStore")).thenReturn("workspace://SpacesStore");
when(props.getProperty("alfresco.batch.count", "5000")).thenReturn("5000");
when(props.getProperty("alfresco.maxLiveSearchers", "2")).thenReturn("2");
when(props.getProperty("enable.slave", "false")).thenReturn("false");
when(props.getProperty("enable.master", "true")).thenReturn("true");
when(props.getProperty("shard.count", "1")).thenReturn("1");
when(props.getProperty("shard.instance", "0")).thenReturn("0");
when(this.srv.getTrackerStats()).thenReturn(trackerStats);
@@ -42,7 +42,7 @@ import java.util.HashMap;
import java.util.Map;
@RunWith(MockitoJUnitRunner.class)
public class PropertyRouterTest
public class PropertyRouterIT
{
private PropertyRouter router;
@@ -73,8 +73,6 @@ public class SolrTrackerSchedulerTest
props.put("alfresco.stores", "workspace://SpacesStore");
props.put("alfresco.batch.count", "5000");
props.put("alfresco.maxLiveSearchers", "2");
props.put("enable.slave", "false");
props.put("enable.master", "true");
props.put("shard.count", "1");
props.put("shard.instance", "0");
props.put("shard.method", "SHARD_METHOD_DBID");
@@ -128,7 +126,7 @@ public class SolrTrackerSchedulerTest
{
String exp = "0/4 * * * * ? *";
props.put("alfresco.metadata.tracker.cron", exp);
MetadataTracker metadataTracker = new MetadataTracker(props, client, exp, informationServer);
MetadataTracker metadataTracker = new MetadataTracker(true, props, client, exp, informationServer);
this.trackerScheduler.schedule(metadataTracker, CORE_NAME, props);
verify(spiedQuartzScheduler).scheduleJob(any(JobDetail.class), any(Trigger.class));
checkCronExpression(exp);
@@ -21,7 +21,7 @@ package org.alfresco.solr.transformer;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.search.adaptor.lucene.QueryConstants;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.solr.AbstractAlfrescoDistributedTest;
import org.alfresco.solr.AbstractAlfrescoDistributedIT;
import org.alfresco.solr.client.Acl;
import org.alfresco.solr.client.AclChangeSet;
import org.alfresco.solr.client.AclReaders;
@@ -58,14 +58,14 @@ import static org.alfresco.solr.AlfrescoSolrUtils.list;
@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"})
@SolrTestCaseJ4.SuppressSSL
public class CachedDocTransformerTest extends AbstractAlfrescoDistributedTest
public class CachedDocTransformerIT extends AbstractAlfrescoDistributedIT
{
public static final String ALFRESCO_JSON = "{\"locales\":[\"en\"], \"templates\": [{\"name\":\"t1\", \"template\":\"%cm:content\"}]}";
@BeforeClass
private static void initData() throws Throwable
{
initSolrServers(1, "CachedDocTransformerTest", null);
initSolrServers(1, "CachedDocTransformerIT", null);
populateAlfrescoData();
}
@@ -56,7 +56,7 @@ import org.apache.lucene.util.automaton.CharacterRunAutomaton;
import org.apache.lucene.util.automaton.RegExp;
import org.junit.Test;
public class MinHashFilterTest extends BaseTokenStreamTestCase
public class MinHashFilterIT extends BaseTokenStreamTestCase
{
@Test
public void testIntHash() {
@@ -43,7 +43,7 @@ import org.mockito.Mock;
/**
* Unit tests for the {@link AlfrescoLukeRequestHandler}.
*/
public class AlfrescoLukeRequestHandlerTest
public class AlfrescoLukeRequestHandlerIT
{
/** The reference to text for a search term. */
private static final BytesRef TERM_TEXT = new BytesRef("TermText");
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8" ?>
<config>
<luceneMatchVersion>6.6.5</luceneMatchVersion>
<dataDir>/tmp/test</dataDir>
<schemaFactory class="ClassicIndexSchemaFactory" />
<indexConfig>
<lockType>${solr.lock.type:native}</lockType>
</indexConfig>
<requestDispatcher handleSelect="true">
<requestParsers
enableRemoteStreaming="true"
multipartUploadLimitInKB="2048000"
formdataUploadLimitInKB="2048" />
<httpCaching never304="true" />
</requestDispatcher>
<requestHandler name="/replication" class="io.sease.labs.solr.handler.ReplicationHandler">
<lst name="master">
<str name="replicateAfter">commit</str>
<str name="confFiles">schema.xml</str>
</lst>
</requestHandler>
<requestHandler name="/def" class="solr.SearchHandler" default="true">
<lst name="defaults">
<bool name="sow">false</bool>
<str name="df">id</str>
<str name="defType">lucene</str>
</lst>
</requestHandler>
<admin>
<defaultQuery>Query me!</defaultQuery>
</admin>
</config>
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8" ?>
<config>
<luceneMatchVersion>6.6.5</luceneMatchVersion>
<dataDir>/tmp/test</dataDir>
<schemaFactory class="ClassicIndexSchemaFactory" />
<indexConfig>
<lockType>${solr.lock.type:native}</lockType>
</indexConfig>
<requestDispatcher handleSelect="true">
<requestParsers
enableRemoteStreaming="true"
multipartUploadLimitInKB="2048000"
formdataUploadLimitInKB="2048" />
<httpCaching never304="true" />
</requestDispatcher>
<requestHandler name="/replication" class="io.sease.labs.solr.handler.ReplicationHandler">
<lst name="master">
<str name="enable">false</str>
<str name="replicateAfter">commit</str>
<str name="confFiles">schema.xml</str>
</lst>
</requestHandler>
<requestHandler name="/def" class="solr.SearchHandler" default="true">
<lst name="defaults">
<bool name="sow">false</bool>
<str name="df">id</str>
<str name="defType">lucene</str>
</lst>
</requestHandler>
<admin>
<defaultQuery>Query me!</defaultQuery>
</admin>
</config>
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8" ?>
<config>
<luceneMatchVersion>6.6.5</luceneMatchVersion>
<dataDir>/tmp/test</dataDir>
<schemaFactory class="ClassicIndexSchemaFactory" />
<indexConfig>
<lockType>${solr.lock.type:native}</lockType>
</indexConfig>
<requestDispatcher handleSelect="true">
<requestParsers
enableRemoteStreaming="true"
multipartUploadLimitInKB="2048000"
formdataUploadLimitInKB="2048" />
<httpCaching never304="true" />
</requestDispatcher>
<requestHandler name="/replication" class="io.sease.labs.solr.handler.ReplicationHandler">
<lst name="master">
<str name="replicateAfter">commit</str>
<str name="confFiles">schema.xml</str>
</lst>
</requestHandler>
<requestHandler name="/def" class="solr.SearchHandler" default="true">
<lst name="defaults">
<bool name="sow">false</bool>
<str name="df">id</str>
<str name="defType">lucene</str>
</lst>
</requestHandler>
<admin>
<defaultQuery>Query me!</defaultQuery>
</admin>
</config>

Some files were not shown because too many files have changed in this diff Show More