mirror of
https://github.com/Alfresco/SearchServices.git
synced 2026-09-16 18:12:56 +00:00
Feature/search 703 (#12)
* SEARCH-703: Initial commit with first test cases * SEAERCH-703: Updated to reflect new design * SEARCH-703: Fix best guess formula * SEARCH-703: Remove System.outs * SEARCH-703: Code review fixes * SEARCH-703: Add initialization check * SEARCH-703: Do not wait for searcher on hard commit * SEARCH-703: Respond -1 if hard commit fails rather then throw exception. * SEARCH-703: Continue improvments to tests
This commit is contained in:
committed by
Tuna Aksoy
parent
a7dae942e0
commit
b60274ed4f
+173
-4
@@ -259,6 +259,12 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler
|
||||
case "ACLTXREPORT":
|
||||
actionACLTXREPORT(rsp, params, cname);
|
||||
break;
|
||||
case "RANGECHECK":
|
||||
rangeCheck(rsp, cname);
|
||||
break;
|
||||
case "EXPAND":
|
||||
expand(rsp, params, cname);
|
||||
break;
|
||||
case "REPORT":
|
||||
actionREPORT(rsp, params, cname);
|
||||
break;
|
||||
@@ -368,7 +374,7 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler
|
||||
String shardIds = params.get("shardIds");
|
||||
|
||||
Properties properties = extractCustomProperties(params);
|
||||
return newCore(coreName,numShards,storeRef,templateName,replicationFactor,nodeInstance,numNodes,shardIds,properties,rsp);
|
||||
return newCore(coreName, numShards, storeRef, templateName, replicationFactor, nodeInstance, numNodes, shardIds, properties, rsp);
|
||||
}
|
||||
|
||||
private boolean newDefaultCore(SolrQueryRequest req, SolrQueryResponse rsp) {
|
||||
@@ -384,7 +390,7 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler
|
||||
storeRef = new StoreRef(store);
|
||||
}
|
||||
|
||||
return newDefaultCore(coreName,storeRef,templateName,extraProperties,rsp);
|
||||
return newDefaultCore(coreName, storeRef, templateName, extraProperties, rsp);
|
||||
}
|
||||
|
||||
protected boolean newDefaultCore(String coreName, StoreRef storeRef, String templateName, Properties extraProperties, SolrQueryResponse rsp)
|
||||
@@ -502,7 +508,6 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler
|
||||
|
||||
/**
|
||||
* @param rsp
|
||||
* @param params
|
||||
* @param storeRef
|
||||
* @param template
|
||||
* @param coreName
|
||||
@@ -781,7 +786,7 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler
|
||||
AclTracker tracker = trackerRegistry.getTrackerForCore(cname, AclTracker.class);
|
||||
Long acltxid = Long.valueOf(params.get(ARG_ACLTXID));
|
||||
NamedList<Object> report = new SimpleOrderedMap<Object>();
|
||||
report.add(cname, buildAclTxReport(getTrackerRegistry(), informationServers.get(cname),cname, tracker, acltxid));
|
||||
report.add(cname, buildAclTxReport(getTrackerRegistry(), informationServers.get(cname), cname, tracker, acltxid));
|
||||
rsp.add("report", report);
|
||||
}
|
||||
else
|
||||
@@ -838,6 +843,170 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler
|
||||
}
|
||||
}
|
||||
|
||||
private DocRouter getDocRouter(String cname)
|
||||
{
|
||||
Collection<Tracker> trackers = trackerRegistry.getTrackersForCore(cname);
|
||||
MetadataTracker metadataTracker = null;
|
||||
for(Tracker tracker : trackers)
|
||||
{
|
||||
if(tracker instanceof MetadataTracker)
|
||||
{
|
||||
metadataTracker = (MetadataTracker)tracker;
|
||||
}
|
||||
}
|
||||
|
||||
DocRouter docRouter = metadataTracker.getDocRouter();
|
||||
return docRouter;
|
||||
}
|
||||
|
||||
|
||||
private void rangeCheck(SolrQueryResponse rsp,String cname) throws IOException
|
||||
{
|
||||
InformationServer informationServer = informationServers.get(cname);
|
||||
|
||||
DocRouter docRouter = getDocRouter(cname);
|
||||
|
||||
if(docRouter instanceof DBIDRangeRouter) {
|
||||
|
||||
DBIDRangeRouter dbidRangeRouter = (DBIDRangeRouter) docRouter;
|
||||
|
||||
if(!dbidRangeRouter.getInitialized())
|
||||
{
|
||||
rsp.add("expand", 0);
|
||||
rsp.add("exception", "DBIDRangeRouter not initialized yet.");
|
||||
return;
|
||||
}
|
||||
|
||||
long startRange = dbidRangeRouter.getStartRange();
|
||||
long endRange = dbidRangeRouter.getEndRange();
|
||||
|
||||
long maxNodeId = informationServer.maxNodeId();
|
||||
long minNodeId = informationServer.minNodeId();
|
||||
long nodeCount = informationServer.nodeCount();
|
||||
|
||||
long bestGuess = -1; // -1 means expansion cannot be done. Either because expansion
|
||||
// has already happened or we're above safe range
|
||||
|
||||
long range = endRange - startRange; // We want this many nodes on the server
|
||||
|
||||
long midpoint = startRange + ((long) (range * .5));
|
||||
|
||||
long safe = startRange + ((long) (range * .75));
|
||||
|
||||
long offset = maxNodeId-startRange;
|
||||
|
||||
double density = 0;
|
||||
|
||||
if(offset > 0) {
|
||||
density = ((double)nodeCount) / ((double)offset); // This is how dense we are so far.
|
||||
}
|
||||
|
||||
if (!dbidRangeRouter.getExpanded())
|
||||
{
|
||||
if(maxNodeId <= safe)
|
||||
{
|
||||
if (maxNodeId >= midpoint)
|
||||
{
|
||||
if(density >= 1)
|
||||
{
|
||||
//This is fully dense shard. I'm not sure if it's possible to have more nodes on the shards
|
||||
//then the offset, but if it does happen don't expand.
|
||||
bestGuess=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
double multiplier = 1/density;
|
||||
bestGuess = (long)(range*multiplier)-range; // This is how much to add
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bestGuess = 0; // We're below the midpoint so it's to early to make a guess.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rsp.add("start", startRange);
|
||||
rsp.add("end", endRange);
|
||||
rsp.add("nodeCount", nodeCount);
|
||||
rsp.add("minDbid", minNodeId);
|
||||
rsp.add("maxDbid", maxNodeId);
|
||||
rsp.add("density", Math.abs(density));
|
||||
rsp.add("expand", bestGuess);
|
||||
rsp.add("expanded", dbidRangeRouter.getExpanded());
|
||||
} else {
|
||||
rsp.add("expand", -1);
|
||||
rsp.add("exception", "ERROR: Wrong document router type:"+docRouter.getClass().getSimpleName());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void expand(SolrQueryResponse rsp, SolrParams params, String cname)
|
||||
throws IOException
|
||||
{
|
||||
InformationServer informationServer = informationServers.get(cname);
|
||||
DocRouter docRouter = getDocRouter(cname);
|
||||
|
||||
if(docRouter instanceof DBIDRangeRouter)
|
||||
{
|
||||
long expansion = Long.parseLong(params.get("add"));
|
||||
DBIDRangeRouter dbidRangeRouter = (DBIDRangeRouter)docRouter;
|
||||
|
||||
if(!dbidRangeRouter.getInitialized())
|
||||
{
|
||||
rsp.add("expand", -1);
|
||||
rsp.add("exception", "DBIDRangeRouter not initialized yet.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(dbidRangeRouter.getExpanded())
|
||||
{
|
||||
rsp.add("expand", -1);
|
||||
rsp.add("exception", "dbid range has already been expanded.");
|
||||
return;
|
||||
}
|
||||
|
||||
long currentEndRange = dbidRangeRouter.getEndRange();
|
||||
long startRange = dbidRangeRouter.getStartRange();
|
||||
long maxNodeId = informationServer.maxNodeId();
|
||||
|
||||
long range = currentEndRange-startRange;
|
||||
long safe = startRange + ((long) (range * .75));
|
||||
|
||||
if(maxNodeId > safe)
|
||||
{
|
||||
rsp.add("expand", -1);
|
||||
rsp.add("exception", "Expansion cannot occur if max DBID in the index is more then 75% of range.");
|
||||
return;
|
||||
}
|
||||
|
||||
long newEndRange = expansion+dbidRangeRouter.getEndRange();
|
||||
try
|
||||
{
|
||||
informationServer.capIndex(newEndRange);
|
||||
informationServer.hardCommit();
|
||||
dbidRangeRouter.setEndRange(newEndRange);
|
||||
dbidRangeRouter.setExpanded(true);
|
||||
assert newEndRange == dbidRangeRouter.getEndRange();
|
||||
rsp.add("expand", dbidRangeRouter.getEndRange());
|
||||
return;
|
||||
}
|
||||
catch(Throwable t)
|
||||
{
|
||||
rsp.add("expand", -1);
|
||||
rsp.add("exception", t.getMessage());
|
||||
log.error("exception expanding", t);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rsp.add("expand", -1);
|
||||
rsp.add("exception", "Wrong document router type:"+docRouter.getClass().getSimpleName());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void actionNODEREPORTS(SolrQueryResponse rsp, SolrParams params, String cname) throws IOException,
|
||||
JSONException
|
||||
{
|
||||
|
||||
+14
@@ -58,6 +58,8 @@ public interface InformationServer extends InformationServerCollectionProvider
|
||||
|
||||
void commit() throws IOException;
|
||||
|
||||
void hardCommit() throws IOException;
|
||||
|
||||
boolean commit(boolean openSearcher) throws IOException;
|
||||
|
||||
void indexAclTransaction(AclChangeSet changeSet, boolean overwrite) throws IOException;
|
||||
@@ -72,6 +74,18 @@ public interface InformationServer extends InformationServerCollectionProvider
|
||||
|
||||
void deleteByNodeId(Long nodeId) throws IOException;
|
||||
|
||||
void capIndex(long nodeId) throws IOException;
|
||||
|
||||
long getIndexCap() throws IOException;
|
||||
|
||||
long nodeCount() throws IOException;
|
||||
|
||||
long maxNodeId() throws IOException;
|
||||
|
||||
long minNodeId() throws IOException;
|
||||
|
||||
void maintainCap(long nodeId) throws Exception;
|
||||
|
||||
void indexNode(Node node, boolean overwrite) throws IOException, AuthenticationException, JSONException;
|
||||
|
||||
void indexNodes(List<Node> nodes, boolean overwrite, boolean cascade) throws IOException, AuthenticationException, JSONException;
|
||||
|
||||
+135
-50
@@ -18,56 +18,6 @@
|
||||
*/
|
||||
package org.alfresco.solr;
|
||||
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_ACLID;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_ACLTXCOMMITTIME;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_ACLTXID;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_ANAME;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_ANCESTOR;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_APATH;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_ASPECT;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_ASSOCTYPEQNAME;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_CASCADE_FLAG;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_DBID;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_DENIED;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_DOC_TYPE;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_EXCEPTION_MESSAGE;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_EXCEPTION_STACK;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_FIELDS;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_FTSSTATUS;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_GEO;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_INACLTXID;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_INTXID;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_ISNODE;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_LID;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_NPATH;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_NULLPROPERTIES;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_OWNER;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_PARENT;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_PARENT_ASSOC_CRC;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_PATH;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_PNAME;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_PRIMARYASSOCQNAME;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_PRIMARYASSOCTYPEQNAME;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_PRIMARYPARENT;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_PROPERTIES;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_QNAME;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_READER;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_SITE;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_SOLR4_ID;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_S_ACLTXCOMMITTIME;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_S_ACLTXID;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_S_INACLTXID;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_S_INTXID;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_S_TXCOMMITTIME;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_S_TXID;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_TAG;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_TAG_SUGGEST;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_TENANT;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_TXCOMMITTIME;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_TXID;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_TYPE;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_VERSION;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -199,6 +149,8 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.extensions.surf.util.I18NUtil;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.*;
|
||||
|
||||
/**
|
||||
* This is the Solr4 implementation of the information server (index).
|
||||
* @author Ahmed Owian
|
||||
@@ -232,6 +184,8 @@ public class SolrInformationServer implements InformationServer
|
||||
public static final String SOLR_PORT = "solr.port";
|
||||
public static final String SOLR_BASEURL = "solr.baseurl";
|
||||
|
||||
public static String indexCapId = "TRACKER!STATE!CAP";
|
||||
|
||||
|
||||
private static final Pattern CAPTURE_SITE = Pattern.compile("^/\\{http\\://www\\.alfresco\\.org/model/application/1\\.0\\}company\\_home/\\{http\\://www\\.alfresco\\.org/model/site/1\\.0\\}sites/\\{http\\://www\\.alfresco\\.org/model/content/1\\.0}([^/]*)/.*" );
|
||||
private static final Pattern CAPTURE_TAG = Pattern.compile("^/\\{http\\://www\\.alfresco\\.org/model/content/1\\.0\\}taggable/\\{http\\://www\\.alfresco\\.org/model/content/1\\.0\\}([^/]*)/\\{\\}member");
|
||||
@@ -956,6 +910,37 @@ public class SolrInformationServer implements InformationServer
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hardCommit() throws IOException
|
||||
{
|
||||
// avoid multiple commits and warming searchers
|
||||
commitAndRollbackLock.writeLock().lock();
|
||||
try
|
||||
{
|
||||
SolrQueryRequest request = null;
|
||||
UpdateRequestProcessor processor = null;
|
||||
try
|
||||
{
|
||||
request = getLocalSolrQueryRequest();
|
||||
processor = this.core.getUpdateProcessingChain(null).createProcessor(request, new SolrQueryResponse());
|
||||
CommitUpdateCommand commitUpdateCommand = new CommitUpdateCommand(request, false);
|
||||
commitUpdateCommand.openSearcher = false;
|
||||
commitUpdateCommand.softCommit = false;
|
||||
commitUpdateCommand.waitSearcher = false;
|
||||
processor.processCommit(commitUpdateCommand);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if(processor != null) {processor.finish();}
|
||||
if(request != null) {request.close();}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
commitAndRollbackLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean commit(boolean openSearcher) throws IOException
|
||||
{
|
||||
canUpdate();
|
||||
@@ -1674,6 +1659,106 @@ public class SolrInformationServer implements InformationServer
|
||||
}
|
||||
}
|
||||
|
||||
public void capIndex(long dbid) throws IOException
|
||||
{
|
||||
SolrQueryRequest request = null;
|
||||
UpdateRequestProcessor processor = null;
|
||||
|
||||
try
|
||||
{
|
||||
request = getLocalSolrQueryRequest();
|
||||
processor = this.core.getUpdateProcessingChain(null).createProcessor(request, new SolrQueryResponse());
|
||||
AddUpdateCommand cmd = new AddUpdateCommand(request);
|
||||
cmd.overwrite = true;
|
||||
SolrInputDocument input = new SolrInputDocument();
|
||||
input.addField(FIELD_SOLR4_ID, indexCapId);
|
||||
input.addField(FIELD_VERSION, 0);
|
||||
input.addField(FIELD_DBID, -dbid); //Making this negative to ensure it is never confused with node DBID
|
||||
input.addField(FIELD_DOC_TYPE, DOC_TYPE_STATE);
|
||||
cmd.solrDoc = input;
|
||||
processor.processAdd(cmd);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if(processor != null) {processor.finish();}
|
||||
if(request != null) {request.close();}
|
||||
}
|
||||
}
|
||||
|
||||
public void maintainCap(long dbid) throws IOException {
|
||||
String deleteByQuery = FIELD_DBID+":{"+dbid+" TO *}";
|
||||
deleteByQuery(deleteByQuery);
|
||||
}
|
||||
|
||||
public long nodeCount()
|
||||
{
|
||||
return getDocListSize(FIELD_DOC_TYPE+":"+DOC_TYPE_NODE);
|
||||
}
|
||||
|
||||
public long maxNodeId() {
|
||||
return topNodeId("desc");
|
||||
}
|
||||
|
||||
public long minNodeId() {
|
||||
return topNodeId("asc");
|
||||
}
|
||||
|
||||
private long topNodeId(String sortDir)
|
||||
{
|
||||
SolrQueryRequest request = null;
|
||||
try
|
||||
{
|
||||
request = this.getLocalSolrQueryRequest();
|
||||
ModifiableSolrParams params = new ModifiableSolrParams(request.getParams());
|
||||
params.set("q", FIELD_DOC_TYPE+":"+DOC_TYPE_NODE);
|
||||
// Sets the rows to zero, because we actually just want the count
|
||||
params.set("rows", 1);
|
||||
params.set("sort", FIELD_DBID + " "+sortDir);
|
||||
params.set("fl", FIELD_DBID);
|
||||
SolrDocumentList docs = cloud.getSolrDocumentList(nativeRequestHandler, request, params);
|
||||
Iterator<SolrDocument> it = docs.iterator();
|
||||
if(it.hasNext()) {
|
||||
SolrDocument doc = it.next();
|
||||
long dbid = getFieldValueLong(doc, FIELD_DBID);
|
||||
return dbid;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (request != null) { request.close(); }
|
||||
}
|
||||
}
|
||||
|
||||
public long getIndexCap()
|
||||
{
|
||||
SolrQueryRequest request = null;
|
||||
try
|
||||
{
|
||||
request = this.getLocalSolrQueryRequest();
|
||||
ModifiableSolrParams params = new ModifiableSolrParams(request.getParams());
|
||||
params.set("q", FIELD_SOLR4_ID+":"+indexCapId);
|
||||
params.set("rows", 1);
|
||||
params.set("fl", FIELD_DBID);
|
||||
SolrDocumentList docs = cloud.getSolrDocumentList(nativeRequestHandler, request, params);
|
||||
Iterator<SolrDocument> it = docs.iterator();
|
||||
if(it.hasNext()) {
|
||||
SolrDocument doc = it.next();
|
||||
long dbid = getFieldValueLong(doc, FIELD_DBID);
|
||||
return Math.abs(dbid);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (request != null) { request.close(); }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void indexNode(Node node, boolean overwrite) throws IOException, AuthenticationException, JSONException
|
||||
{
|
||||
|
||||
+1
-1
@@ -80,7 +80,7 @@ public class CommitTracker extends AbstractTracker
|
||||
lastSearcherOpened = lastCommit = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public boolean hasMaintenance()
|
||||
public boolean hasMaintenance() throws Exception
|
||||
{
|
||||
return (metadataTracker.hasMaintenance() || aclTracker.hasMaintenance());
|
||||
}
|
||||
|
||||
+36
-4
@@ -22,6 +22,9 @@ import org.apache.solr.common.util.Hash;
|
||||
import org.alfresco.solr.client.Node;
|
||||
import org.alfresco.solr.client.Acl;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
|
||||
/*
|
||||
* @author Joel
|
||||
@@ -29,13 +32,42 @@ import org.alfresco.solr.client.Acl;
|
||||
|
||||
public class DBIDRangeRouter implements DocRouter
|
||||
{
|
||||
|
||||
private long startRange;
|
||||
private long endRange;
|
||||
private AtomicLong expandableRange;
|
||||
private AtomicBoolean expanded = new AtomicBoolean(false);
|
||||
private AtomicBoolean initialized = new AtomicBoolean(false);
|
||||
|
||||
public DBIDRangeRouter(long startRange, long endRange) {
|
||||
this.startRange = startRange;
|
||||
this.endRange = endRange;
|
||||
this.expandableRange = new AtomicLong(endRange);
|
||||
}
|
||||
|
||||
public void setEndRange(long endRange) {
|
||||
expandableRange.set(endRange);
|
||||
}
|
||||
|
||||
public void setExpanded(boolean expanded) {
|
||||
this.expanded.set(expanded);
|
||||
}
|
||||
|
||||
public void setInitialized(boolean initialized) {
|
||||
this.initialized.set(initialized);
|
||||
}
|
||||
|
||||
public boolean getInitialized() {
|
||||
return this.initialized.get();
|
||||
}
|
||||
|
||||
public long getEndRange() {
|
||||
return expandableRange.longValue();
|
||||
}
|
||||
|
||||
public long getStartRange() {
|
||||
return this.startRange;
|
||||
}
|
||||
|
||||
public boolean getExpanded() {
|
||||
return this.expanded.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -47,7 +79,7 @@ public class DBIDRangeRouter implements DocRouter
|
||||
@Override
|
||||
public boolean routeNode(int shardCount, int shardInstance, Node node) {
|
||||
long dbid = node.getId();
|
||||
if(dbid >= startRange && dbid < endRange) {
|
||||
if(dbid >= startRange && dbid < expandableRange.longValue()) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
||||
+9
-7
@@ -23,7 +23,6 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
/*
|
||||
* @author Joel
|
||||
@@ -40,12 +39,15 @@ public class DocRouterFactory
|
||||
log.info("Sharding via DB_ID");
|
||||
return new DBIDRouter();
|
||||
case DB_ID_RANGE:
|
||||
String range = properties.getProperty("shard.range");
|
||||
String[] rangeParts = range.split("-");
|
||||
long startRange = Long.parseLong(rangeParts[0].trim());
|
||||
long endRange = Long.parseLong(rangeParts[1].trim());
|
||||
log.info("Sharding via DB_ID_RANGE");
|
||||
return new DBIDRangeRouter(startRange, endRange);
|
||||
//
|
||||
if(properties.containsKey("shard.range"))
|
||||
{
|
||||
log.info("Sharding via DB_ID_RANGE");
|
||||
String[] pair =properties.getProperty("shard.range").split("-");
|
||||
long start = Long.parseLong(pair[0]);
|
||||
long end = Long.parseLong(pair[1]);
|
||||
return new DBIDRangeRouter(start, end);
|
||||
}
|
||||
case ACL_ID:
|
||||
log.info("Sharding via ACL_ID");
|
||||
return new ACLIDMurmurRouter();
|
||||
|
||||
+27
-3
@@ -80,7 +80,6 @@ public class MetadataTracker extends AbstractTracker implements Tracker
|
||||
InformationServer informationServer)
|
||||
{
|
||||
super(p, client, coreName, informationServer, Tracker.Type.MetaData);
|
||||
//System.out.println("####### MetadatTracker() ########");
|
||||
transactionDocsBatchSize = Integer.parseInt(p.getProperty("alfresco.transactionDocsBatchSize", "100"));
|
||||
shardMethod = p.getProperty("shard.method", SHARD_METHOD_DBID);
|
||||
String shardKey = p.getProperty("shard.key");
|
||||
@@ -98,6 +97,10 @@ public class MetadataTracker extends AbstractTracker implements Tracker
|
||||
super(Tracker.Type.MetaData);
|
||||
}
|
||||
|
||||
public DocRouter getDocRouter() {
|
||||
return this.docRouter;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doTrack() throws AuthenticationException, IOException, JSONException, EncoderException
|
||||
{
|
||||
@@ -120,8 +123,8 @@ public class MetadataTracker extends AbstractTracker implements Tracker
|
||||
indexNodes();
|
||||
}
|
||||
|
||||
public boolean hasMaintenance() {
|
||||
return transactionsToReindex.size() > 0 ||
|
||||
public boolean hasMaintenance() throws Exception {
|
||||
return transactionsToReindex.size() > 0 ||
|
||||
transactionsToIndex.size() > 0 ||
|
||||
transactionsToPurge.size() > 0 ||
|
||||
nodesToReindex.size() > 0 ||
|
||||
@@ -130,6 +133,8 @@ public class MetadataTracker extends AbstractTracker implements Tracker
|
||||
queriesToReindex.size() > 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void trackRepository() throws IOException, AuthenticationException, JSONException, EncoderException
|
||||
{
|
||||
//System.out.println("########################### MetadataTracker.trackRepository ##########");
|
||||
@@ -152,6 +157,21 @@ public class MetadataTracker extends AbstractTracker implements Tracker
|
||||
checkRepoAndIndexConsistency(state);
|
||||
}
|
||||
|
||||
if(docRouter instanceof DBIDRangeRouter)
|
||||
{
|
||||
DBIDRangeRouter dbidRangeRouter = (DBIDRangeRouter)docRouter;
|
||||
long indexCap = infoSrv.getIndexCap();
|
||||
long endRange = dbidRangeRouter.getEndRange();
|
||||
assert(indexCap == -1 || indexCap >= endRange);
|
||||
|
||||
if(indexCap > endRange) {
|
||||
dbidRangeRouter.setExpanded(true);
|
||||
dbidRangeRouter.setEndRange(indexCap);
|
||||
}
|
||||
|
||||
dbidRangeRouter.setInitialized(true);
|
||||
}
|
||||
|
||||
checkShutdown();
|
||||
trackTransactions();
|
||||
}
|
||||
@@ -596,6 +616,10 @@ public class MetadataTracker extends AbstractTracker implements Tracker
|
||||
getWriteLock().acquire();
|
||||
//System.out.println("######## Metadata Tracket Acquiring Write Lock ########");
|
||||
|
||||
/*
|
||||
* Check to see if we are using the capped router, and if the cap has already been set.
|
||||
*/
|
||||
|
||||
TrackerState state = getTrackerState();
|
||||
|
||||
//System.out.println("######## Do Track Transactions ########:"+docCount);
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ public interface Tracker
|
||||
|
||||
void maintenance() throws Exception;
|
||||
|
||||
boolean hasMaintenance();
|
||||
boolean hasMaintenance() throws Exception;
|
||||
|
||||
Semaphore getWriteLock();
|
||||
|
||||
|
||||
+222
-7
@@ -6,10 +6,9 @@ import org.alfresco.solr.client.NodeMetaData;
|
||||
import org.alfresco.solr.client.SOLRAPIQueueClient;
|
||||
import org.alfresco.solr.client.Transaction;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.lucene.index.IndexableField;
|
||||
import org.apache.lucene.index.Term;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.search.TermQuery;
|
||||
import org.apache.lucene.search.TopDocs;
|
||||
import org.apache.lucene.search.*;
|
||||
import org.apache.solr.SolrTestCaseJ4;
|
||||
import org.apache.solr.client.solrj.SolrClient;
|
||||
import org.apache.solr.client.solrj.SolrRequest;
|
||||
@@ -33,6 +32,7 @@ import org.apache.solr.common.params.ModifiableSolrParams;
|
||||
import org.apache.solr.common.params.SolrParams;
|
||||
import org.apache.solr.common.util.ContentStream;
|
||||
import org.apache.solr.common.util.ContentStreamBase;
|
||||
import org.apache.lucene.document.Document;
|
||||
import org.apache.solr.common.util.NamedList;
|
||||
import org.apache.solr.core.CoreContainer;
|
||||
import org.apache.solr.core.SolrCore;
|
||||
@@ -40,6 +40,8 @@ import org.apache.solr.request.LocalSolrQueryRequest;
|
||||
import org.apache.solr.request.SolrQueryRequest;
|
||||
import org.apache.solr.response.SolrQueryResponse;
|
||||
import org.apache.solr.search.SolrIndexSearcher;
|
||||
import org.apache.solr.update.AddUpdateCommand;
|
||||
import org.apache.solr.update.CommitUpdateCommand;
|
||||
import org.apache.solr.util.RefCounted;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.junit.Assert;
|
||||
@@ -58,7 +60,7 @@ import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_DOC_TYPE;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.*;
|
||||
import static org.alfresco.solr.AlfrescoSolrUtils.createCoreUsingTemplate;
|
||||
|
||||
/**
|
||||
@@ -261,6 +263,16 @@ public abstract class AbstractAlfrescoDistributedTest extends SolrTestCaseJ4
|
||||
}
|
||||
}
|
||||
|
||||
public void waitForDocCountAllShards(Query query, int count, long waitMillis) throws Exception
|
||||
{
|
||||
List<SolrCore> cores = getJettyCores(jettyShards);
|
||||
long begin = System.currentTimeMillis();
|
||||
for (SolrCore core : cores) {
|
||||
waitForDocCountCore(core, query, count, waitMillis, begin);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Delele by query on all Clients
|
||||
* @param q
|
||||
@@ -342,6 +354,8 @@ public abstract class AbstractAlfrescoDistributedTest extends SolrTestCaseJ4
|
||||
SolrIndexSearcher searcher = refCounted.get();
|
||||
TopDocs topDocs = searcher.search(query, 10);
|
||||
totalCount += topDocs.totalHits;
|
||||
//System.out.println("####### shard count:"+core.getName()+":"+totalCount);
|
||||
Thread.sleep(2000);
|
||||
} finally {
|
||||
refCounted.decref();
|
||||
}
|
||||
@@ -353,6 +367,34 @@ public abstract class AbstractAlfrescoDistributedTest extends SolrTestCaseJ4
|
||||
throw new Exception("Cluster:Wait error expected "+count+" found "+totalCount+" : "+query.toString());
|
||||
}
|
||||
|
||||
protected void injectDocToShards(long txnId, long aclId, long dbId, String owner) throws Exception {
|
||||
List<SolrCore> cores = getJettyCores(jettyShards);
|
||||
for(SolrCore core : cores) {
|
||||
SolrInputDocument doc = new SolrInputDocument();
|
||||
String id = AlfrescoSolrDataModel.getNodeDocumentId(AlfrescoSolrDataModel.DEFAULT_TENANT, aclId, dbId);
|
||||
doc.addField(FIELD_SOLR4_ID, id);
|
||||
doc.addField(FIELD_VERSION, 0);
|
||||
doc.addField(FIELD_DBID, "" + dbId);
|
||||
doc.addField(FIELD_INTXID, "" + txnId);
|
||||
doc.addField(FIELD_ACLID, "" + aclId);
|
||||
doc.addField(FIELD_OWNER, owner);
|
||||
|
||||
AbstractAlfrescoSolrTests.SolrServletRequest solrQueryRequest = null;
|
||||
try
|
||||
{
|
||||
solrQueryRequest = new AbstractAlfrescoSolrTests.SolrServletRequest(core, null);
|
||||
AddUpdateCommand addDocCmd = new AddUpdateCommand(solrQueryRequest);
|
||||
addDocCmd.overwrite = true;
|
||||
addDocCmd.solrDoc = doc;
|
||||
core.getUpdateHandler().addDoc(addDocCmd);
|
||||
}
|
||||
finally
|
||||
{
|
||||
solrQueryRequest.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cores for the jetty instances
|
||||
* @return
|
||||
@@ -367,6 +409,18 @@ public abstract class AbstractAlfrescoDistributedTest extends SolrTestCaseJ4
|
||||
return cores;
|
||||
}
|
||||
|
||||
protected List<AlfrescoCoreAdminHandler> getAdminHandlers(Collection<JettySolrRunner> runners)
|
||||
{
|
||||
List<AlfrescoCoreAdminHandler> coreAdminHandlers = new ArrayList();
|
||||
for (JettySolrRunner jettySolrRunner : runners)
|
||||
{
|
||||
CoreContainer coreContainer = jettySolrRunner.getCoreContainer();
|
||||
AlfrescoCoreAdminHandler coreAdminHandler = (AlfrescoCoreAdminHandler) coreContainer.getMultiCoreHandler();
|
||||
coreAdminHandlers.add(coreAdminHandler);
|
||||
}
|
||||
return coreAdminHandlers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Default test client.
|
||||
* @return
|
||||
@@ -638,6 +692,7 @@ public abstract class AbstractAlfrescoDistributedTest extends SolrTestCaseJ4
|
||||
|
||||
|
||||
String[] ranges = {"0-100", "100-200", "200-300", "300-400"};
|
||||
|
||||
for (int i = 0; i < numShards; i++)
|
||||
{
|
||||
Properties props = new Properties();
|
||||
@@ -647,8 +702,8 @@ public abstract class AbstractAlfrescoDistributedTest extends SolrTestCaseJ4
|
||||
props.put("shard.instance", Integer.toString(i));
|
||||
props.put("shard.count", Integer.toString(numShards));
|
||||
|
||||
if("DB_ID_RANGE".equalsIgnoreCase(props.getProperty("shard.method"))) {
|
||||
//Add
|
||||
if("DB_ID_RANGE".equalsIgnoreCase(props.getProperty("shard.method")))
|
||||
{
|
||||
props.put("shard.range", ranges[i]);
|
||||
}
|
||||
|
||||
@@ -1627,7 +1682,7 @@ public abstract class AbstractAlfrescoDistributedTest extends SolrTestCaseJ4
|
||||
Properties coreProperties = new Properties();
|
||||
coreProperties.setProperty("name", coreName);
|
||||
coreProperties.setProperty("shard", "${shard:}");
|
||||
coreProperties.setProperty("collection", "${collection:"+coreName+"}");
|
||||
coreProperties.setProperty("collection", "${collection:" + coreName + "}");
|
||||
coreProperties.setProperty("config", "${solrconfig:solrconfig.xml}");
|
||||
coreProperties.setProperty("schema", "${schema:schema.xml}");
|
||||
coreProperties.setProperty("coreNodeName", "${coreNodeName:}");
|
||||
@@ -1682,6 +1737,166 @@ public abstract class AbstractAlfrescoDistributedTest extends SolrTestCaseJ4
|
||||
return response;
|
||||
}
|
||||
|
||||
protected SolrQueryResponse callExpand(AlfrescoCoreAdminHandler coreAdminHandler,
|
||||
SolrCore testingCore,
|
||||
int value) {
|
||||
SolrQueryRequest request = new LocalSolrQueryRequest(testingCore,
|
||||
params(CoreAdminParams.ACTION, "EXPAND",
|
||||
CoreAdminParams.CORE, testingCore.getName(),
|
||||
"add", Integer.toString(value)));
|
||||
SolrQueryResponse response = new SolrQueryResponse();
|
||||
coreAdminHandler.handleCustomAction(request, response);
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
protected List<Long> assertCapOnAllShards(String[] starts) throws Exception
|
||||
{
|
||||
List<SolrCore> cores = getJettyCores(jettyShards);
|
||||
List<Long> caps = new ArrayList();
|
||||
List<AlfrescoCoreAdminHandler> alfrescoCoreAdminHandlers = getAdminHandlers(jettyShards);
|
||||
for (int i=0; i<cores.size(); i++) {
|
||||
caps.add(assertCapForCore(alfrescoCoreAdminHandlers.get(i), cores.get(i), Long.parseLong(starts[i])));
|
||||
}
|
||||
|
||||
return caps;
|
||||
}
|
||||
|
||||
public SolrQueryResponse rangeCheck(int shard) throws Exception {
|
||||
while(true) {
|
||||
List<SolrCore> cores = getJettyCores(jettyShards);
|
||||
List<AlfrescoCoreAdminHandler> alfrescoCoreAdminHandlers = getAdminHandlers(jettyShards);
|
||||
SolrCore core = cores.get(shard);
|
||||
AlfrescoCoreAdminHandler alfrescoCoreAdminHandler = alfrescoCoreAdminHandlers.get(shard);
|
||||
SolrQueryResponse response = callHandler(alfrescoCoreAdminHandler, core, "RANGECHECK");
|
||||
NamedList values = response.getValues();
|
||||
String ex = (String)values.get("exception");
|
||||
if(ex == null || ex.indexOf("not initialized") == -1) {
|
||||
return response;
|
||||
} else {
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public SolrQueryResponse expand(int shard, int value) {
|
||||
List<SolrCore> cores = getJettyCores(jettyShards);
|
||||
List<AlfrescoCoreAdminHandler> alfrescoCoreAdminHandlers = getAdminHandlers(jettyShards);
|
||||
SolrCore core = cores.get(shard);
|
||||
AlfrescoCoreAdminHandler alfrescoCoreAdminHandler = alfrescoCoreAdminHandlers.get(shard);
|
||||
SolrQueryResponse response = callExpand(alfrescoCoreAdminHandler, core, value);
|
||||
return response;
|
||||
}
|
||||
|
||||
protected long assertCapForCore(AlfrescoCoreAdminHandler coreAdminHandler,
|
||||
SolrCore core,
|
||||
long start)
|
||||
throws IOException
|
||||
{
|
||||
//Get the cap from the index
|
||||
long cap = -1;
|
||||
RefCounted<SolrIndexSearcher> refCounted = null;
|
||||
Set<String> fields = new HashSet();
|
||||
fields.add(FIELD_DBID);
|
||||
try {
|
||||
refCounted = core.getSearcher();
|
||||
SolrIndexSearcher searcher = refCounted.get();
|
||||
|
||||
TopDocs topDocs = searcher.search(new TermQuery(new Term(FIELD_SOLR4_ID, "TRACKER!STATE!CAP")), 10);
|
||||
ScoreDoc doc = topDocs.scoreDocs[0];
|
||||
Document document = searcher.doc(doc.doc, fields);
|
||||
cap = Math.abs(getFieldValueLong(document, FIELD_DBID));
|
||||
} finally {
|
||||
refCounted.decref();
|
||||
}
|
||||
|
||||
System.out.println("####### got cap:"+cap);
|
||||
|
||||
//Check that the max DBID in the core matches the cap.
|
||||
|
||||
long maxDBID = -1;
|
||||
Query query = new TermQuery(new Term(FIELD_DOC_TYPE, SolrInformationServer.DOC_TYPE_NODE));
|
||||
try {
|
||||
refCounted = core.getSearcher();
|
||||
SolrIndexSearcher searcher = refCounted.get();
|
||||
|
||||
TopDocs topDocs = searcher.search(query,
|
||||
1,
|
||||
new Sort(new SortField(FIELD_DBID, SortField.Type.LONG, true)));
|
||||
System.out.println("####### hits:"+topDocs.totalHits+":"+query);
|
||||
|
||||
ScoreDoc doc = topDocs.scoreDocs[0];
|
||||
Document document = searcher.doc(doc.doc, fields);
|
||||
maxDBID = getFieldValueLong(document, FIELD_DBID);
|
||||
} finally {
|
||||
refCounted.decref();
|
||||
}
|
||||
|
||||
System.out.println("####### got max DBID:"+maxDBID);
|
||||
|
||||
|
||||
if(maxDBID != cap) {
|
||||
throw new IOException("Max DBID should equal cap:"+maxDBID+" != "+cap);
|
||||
}
|
||||
|
||||
long minDBID = -1;
|
||||
try {
|
||||
refCounted = core.getSearcher();
|
||||
SolrIndexSearcher searcher = refCounted.get();
|
||||
|
||||
TopDocs topDocs = searcher.search(query,
|
||||
1,
|
||||
new Sort(new SortField(FIELD_DBID, SortField.Type.LONG, false)));
|
||||
ScoreDoc doc = topDocs.scoreDocs[0];
|
||||
Document document = searcher.doc(doc.doc, fields);
|
||||
minDBID = getFieldValueLong(document, FIELD_DBID);
|
||||
} finally {
|
||||
refCounted.decref();
|
||||
}
|
||||
|
||||
System.out.println("####### got min DBID:"+minDBID);
|
||||
|
||||
if(minDBID != start) {
|
||||
throw new IOException("Min DBID should equal start:"+minDBID+" != "+start);
|
||||
}
|
||||
|
||||
|
||||
SolrQueryResponse response = callHandler(coreAdminHandler, core, "CHECKCAP");
|
||||
NamedList values = response.getValues();
|
||||
long checkCap = (long)values.get("CAP");
|
||||
if(checkCap != cap)
|
||||
{
|
||||
throw new IOException("The admin handler returned bad cap:"+checkCap+":"+cap);
|
||||
}
|
||||
|
||||
return cap;
|
||||
|
||||
}
|
||||
|
||||
private String getFieldValueString(Document doc, String fieldName)
|
||||
{
|
||||
IndexableField field = doc.getField(fieldName);
|
||||
String value = null;
|
||||
if (field != null)
|
||||
{
|
||||
value = field.stringValue();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
private long getFieldValueLong(Document doc, String fieldName)
|
||||
{
|
||||
return Long.parseLong(getFieldValueString(doc, fieldName));
|
||||
}
|
||||
|
||||
protected void assertCHECKCAPAction(long[] caps) throws Exception
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A JUnit Rule to setup Jetty
|
||||
*/
|
||||
|
||||
+412
@@ -0,0 +1,412 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2014 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.solr.tracker;
|
||||
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_DOC_TYPE;
|
||||
import static org.alfresco.repo.search.adaptor.lucene.QueryConstants.FIELD_SOLR4_ID;
|
||||
import static org.alfresco.solr.AlfrescoSolrUtils.getAcl;
|
||||
import static org.alfresco.solr.AlfrescoSolrUtils.getAclChangeSet;
|
||||
import static org.alfresco.solr.AlfrescoSolrUtils.getAclReaders;
|
||||
import static org.alfresco.solr.AlfrescoSolrUtils.getNode;
|
||||
import static org.alfresco.solr.AlfrescoSolrUtils.getNodeMetaData;
|
||||
import static org.alfresco.solr.AlfrescoSolrUtils.getTransaction;
|
||||
import static org.alfresco.solr.AlfrescoSolrUtils.indexAclChangeSet;
|
||||
import static org.alfresco.solr.AlfrescoSolrUtils.list;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.alfresco.solr.AbstractAlfrescoDistributedTest;
|
||||
import org.alfresco.solr.SolrInformationServer;
|
||||
import org.alfresco.solr.client.Acl;
|
||||
import org.alfresco.solr.client.AclChangeSet;
|
||||
import org.alfresco.solr.client.AclReaders;
|
||||
import org.alfresco.solr.client.Node;
|
||||
import org.alfresco.solr.client.NodeMetaData;
|
||||
import org.alfresco.solr.client.Transaction;
|
||||
import org.apache.lucene.index.Term;
|
||||
import org.apache.lucene.search.TermQuery;
|
||||
import org.apache.lucene.util.LuceneTestCase;
|
||||
import org.apache.solr.SolrTestCaseJ4;
|
||||
import org.apache.solr.common.util.NamedList;
|
||||
import org.apache.solr.client.solrj.response.QueryResponse;
|
||||
import org.apache.solr.response.SolrQueryResponse;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author Joel
|
||||
*/
|
||||
@SolrTestCaseJ4.SuppressSSL
|
||||
@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"})
|
||||
public class DistributedExpandDbidRangeAlfrescoSolrTrackerTest extends AbstractAlfrescoDistributedTest
|
||||
{
|
||||
@Rule
|
||||
public JettyServerRule jetty = new JettyServerRule(2,this, getShardMethod());
|
||||
|
||||
@Test
|
||||
public void testDbIdRange() throws Exception
|
||||
{
|
||||
putHandleDefaults();
|
||||
|
||||
int numAcls = 250;
|
||||
AclChangeSet bulkAclChangeSet = getAclChangeSet(numAcls);
|
||||
|
||||
List<Acl> bulkAcls = new ArrayList();
|
||||
List<AclReaders> bulkAclReaders = new ArrayList();
|
||||
|
||||
for(int i=0; i<numAcls; i++) {
|
||||
Acl bulkAcl = getAcl(bulkAclChangeSet);
|
||||
bulkAcls.add(bulkAcl);
|
||||
bulkAclReaders.add(getAclReaders(bulkAclChangeSet,
|
||||
bulkAcl,
|
||||
list("joel"+bulkAcl.getId()),
|
||||
list("phil"+bulkAcl.getId()),
|
||||
null));
|
||||
}
|
||||
|
||||
indexAclChangeSet(bulkAclChangeSet,
|
||||
bulkAcls,
|
||||
bulkAclReaders);
|
||||
|
||||
SolrQueryResponse response0 = rangeCheck(0);
|
||||
NamedList values0 = response0.getValues();
|
||||
//{start=0,end=100,nodeCount=0,maxDbid=0,density=NaN,expand=0,expanded=false}
|
||||
|
||||
assertEquals((long)values0.get("start"), 0);
|
||||
assertEquals((long)values0.get("end"), 100);
|
||||
assertEquals((long)values0.get("nodeCount"), 0);
|
||||
assertEquals((long)values0.get("minDbid"), 0);
|
||||
assertEquals((long)values0.get("maxDbid"), 0);
|
||||
assertEquals((long)values0.get("expand"), 0);
|
||||
assertEquals((boolean)values0.get("expanded"), false);
|
||||
|
||||
System.out.println("RANGECHECK0:"+values0);
|
||||
|
||||
SolrQueryResponse response1 = rangeCheck(1);
|
||||
NamedList values1 = response1.getValues();
|
||||
//{start=100,end=200,nodeCount=0,maxDbid=0,density=0.0,expand=0,expanded=false}
|
||||
System.out.println("RANGECHECK1:" + values1);
|
||||
|
||||
assertEquals((long)values1.get("start"), 100);
|
||||
assertEquals((long)values1.get("end"), 200);
|
||||
assertEquals((long)values1.get("nodeCount"), 0);
|
||||
assertEquals((long)values1.get("minDbid"), 0);
|
||||
assertEquals((long)values1.get("maxDbid"), 0);
|
||||
assertEquals((long)values1.get("expand"), 0);
|
||||
assertEquals((boolean)values1.get("expanded"), false);
|
||||
|
||||
int numNodes = 25;
|
||||
List<Node> nodes = new ArrayList();
|
||||
List<NodeMetaData> nodeMetaDatas = new ArrayList();
|
||||
|
||||
Transaction bigTxn = getTransaction(0, numNodes);
|
||||
|
||||
for(int i=0; i<numNodes; i++) {
|
||||
int aclIndex = i % numAcls;
|
||||
Node node = getNode((long)i, bigTxn, bulkAcls.get(aclIndex), Node.SolrApiNodeStatus.UPDATED);
|
||||
nodes.add(node);
|
||||
NodeMetaData nodeMetaData = getNodeMetaData(node, bigTxn, bulkAcls.get(aclIndex), "mike", null, false);
|
||||
nodeMetaDatas.add(nodeMetaData);
|
||||
}
|
||||
|
||||
indexTransaction(bigTxn, nodes, nodeMetaDatas);
|
||||
waitForDocCount(new TermQuery(new Term("content@s___t@{http://www.alfresco.org/model/content/1.0}content", "world")), numNodes, 100000);
|
||||
waitForDocCountAllCores(new TermQuery(new Term(FIELD_DOC_TYPE, SolrInformationServer.DOC_TYPE_ACL)), numAcls, 80000);
|
||||
|
||||
response0 = rangeCheck(0);
|
||||
values0 = response0.getValues();
|
||||
//{start=0,end=100,nodeCount=25,maxDbid=24,density=1.0416666666666667,expand=0,expanded=false}
|
||||
|
||||
assertEquals((long) values0.get("start"), 0);
|
||||
assertEquals((long) values0.get("end"), 100);
|
||||
assertEquals((long) values0.get("nodeCount"), 25);
|
||||
assertEquals((long)values0.get("minDbid"), 0);
|
||||
assertEquals((long) values0.get("maxDbid"), 24);
|
||||
assertEquals((long) values0.get("expand"), 0);
|
||||
assertEquals((boolean) values0.get("expanded"), false);
|
||||
|
||||
System.out.println("_RANGECHECK0:" + values0);
|
||||
|
||||
response1 = rangeCheck(1);
|
||||
values1 = response1.getValues();
|
||||
assertEquals((long) values1.get("start"), 100);
|
||||
assertEquals((long)values1.get("end"), 200);
|
||||
assertEquals((long) values1.get("nodeCount"), 0);
|
||||
assertEquals((long)values0.get("minDbid"), 0);
|
||||
assertEquals((long) values1.get("maxDbid"), 0);
|
||||
assertEquals((long) values1.get("expand"), 0);
|
||||
assertEquals((boolean) values1.get("expanded"), false);
|
||||
|
||||
System.out.println("_RANGECHECK1:" + values1);
|
||||
|
||||
|
||||
|
||||
numNodes = 26;
|
||||
nodes = new ArrayList();
|
||||
nodeMetaDatas = new ArrayList();
|
||||
|
||||
bigTxn = getTransaction(0, numNodes);
|
||||
|
||||
for(int i=0; i<numNodes; i++) {
|
||||
int aclIndex = i % numAcls;
|
||||
Node node = getNode((long)i+35, bigTxn, bulkAcls.get(aclIndex), Node.SolrApiNodeStatus.UPDATED);
|
||||
nodes.add(node);
|
||||
NodeMetaData nodeMetaData = getNodeMetaData(node, bigTxn, bulkAcls.get(aclIndex), "mike", null, false);
|
||||
nodeMetaDatas.add(nodeMetaData);
|
||||
}
|
||||
|
||||
indexTransaction(bigTxn, nodes, nodeMetaDatas);
|
||||
waitForDocCount(new TermQuery(new Term("content@s___t@{http://www.alfresco.org/model/content/1.0}content", "world")), 51, 100000);
|
||||
|
||||
response0 = rangeCheck(0);
|
||||
values0 = response0.getValues();
|
||||
//{start=0,end=100,nodeCount=51,maxDbid=60,density=0.85,expand=15,expanded=false}
|
||||
|
||||
assertEquals((long) values0.get("start"), 0);
|
||||
assertEquals((long)values0.get("end"), 100);
|
||||
assertEquals((long) values0.get("nodeCount"), 51);
|
||||
assertEquals((long)values0.get("minDbid"), 0);
|
||||
assertEquals((long) values0.get("maxDbid"), 60);
|
||||
assertEquals((double) values0.get("density"), .85, 0.0);
|
||||
assertEquals((long) values0.get("expand"), 17);
|
||||
assertEquals((boolean) values0.get("expanded"), false);
|
||||
|
||||
System.out.println("_RANGECHECK0:" + values0);
|
||||
|
||||
response1 = rangeCheck(1);
|
||||
values1 = response1.getValues();
|
||||
assertEquals((long) values1.get("start"), 100);
|
||||
assertEquals((long)values1.get("end"), 200);
|
||||
assertEquals((long) values1.get("nodeCount"), 0);
|
||||
assertEquals((long)values0.get("minDbid"), 0);
|
||||
assertEquals((long) values1.get("maxDbid"), 0);
|
||||
assertEquals((long) values1.get("expand"), 0);
|
||||
assertEquals((boolean) values1.get("expanded"), false);
|
||||
|
||||
System.out.println("_RANGECHECK1:" + values1);
|
||||
|
||||
numNodes = 5;
|
||||
nodes = new ArrayList();
|
||||
nodeMetaDatas = new ArrayList();
|
||||
|
||||
bigTxn = getTransaction(0, numNodes);
|
||||
|
||||
for(int i=0; i<numNodes; i++) {
|
||||
int aclIndex = i % numAcls;
|
||||
Node node = getNode((long)i+72, bigTxn, bulkAcls.get(aclIndex), Node.SolrApiNodeStatus.UPDATED);
|
||||
nodes.add(node);
|
||||
NodeMetaData nodeMetaData = getNodeMetaData(node, bigTxn, bulkAcls.get(aclIndex), "mike", null, false);
|
||||
nodeMetaDatas.add(nodeMetaData);
|
||||
}
|
||||
|
||||
indexTransaction(bigTxn, nodes, nodeMetaDatas);
|
||||
waitForDocCount(new TermQuery(new Term("content@s___t@{http://www.alfresco.org/model/content/1.0}content", "world")), 56, 100000);
|
||||
|
||||
|
||||
response0 = rangeCheck(0);
|
||||
values0 = response0.getValues();
|
||||
//{start=0,end=100,nodeCount=56,maxDbid=76,density=0.7368421052631579,expand=-1,expanded=false}
|
||||
assertEquals((long) values0.get("start"), 0);
|
||||
assertEquals((long) values0.get("end"), 100);
|
||||
assertEquals((long) values0.get("nodeCount"), 56);
|
||||
assertEquals((long)values0.get("minDbid"), 0);
|
||||
assertEquals((long) values0.get("maxDbid"), 76);
|
||||
assertEquals((double) values0.get("density"), 0.7368421052631579, 0.0);
|
||||
assertEquals((long) values0.get("expand"), -1);
|
||||
assertEquals((boolean) values0.get("expanded"), false);
|
||||
|
||||
SolrQueryResponse expandResponse = expand(0, 35);
|
||||
NamedList expandValues = expandResponse.getValues();
|
||||
String ex = (String)expandValues.get("exception");
|
||||
assertEquals(ex, "Expansion cannot occur if max DBID in the index is more then 75% of range.");
|
||||
Number expanded = (Number)expandValues.get("expand");
|
||||
assertEquals(expanded.intValue(), -1);
|
||||
|
||||
System.out.println("_RANGECHECK0:" + values0);
|
||||
|
||||
response1 = rangeCheck(1);
|
||||
values1 = response1.getValues();
|
||||
System.out.println("_RANGECHECK1:" + values1);
|
||||
|
||||
assertEquals((long) values1.get("start"), 100);
|
||||
assertEquals((long) values1.get("end"), 200);
|
||||
assertEquals((long) values1.get("nodeCount"), 0);
|
||||
assertEquals((long)values0.get("minDbid"), 0);
|
||||
assertEquals((long) values1.get("maxDbid"), 0);
|
||||
assertEquals((long) values1.get("expand"), 0);
|
||||
assertEquals((boolean) values1.get("expanded"), false);
|
||||
|
||||
numNodes = 5;
|
||||
nodes = new ArrayList();
|
||||
nodeMetaDatas = new ArrayList();
|
||||
|
||||
bigTxn = getTransaction(0, numNodes);
|
||||
|
||||
for(int i=0; i<numNodes; i++) {
|
||||
int aclIndex = i % numAcls;
|
||||
Node node = getNode((long)i+100, bigTxn, bulkAcls.get(aclIndex), Node.SolrApiNodeStatus.UPDATED);
|
||||
nodes.add(node);
|
||||
NodeMetaData nodeMetaData = getNodeMetaData(node, bigTxn, bulkAcls.get(aclIndex), "mike", null, false);
|
||||
nodeMetaDatas.add(nodeMetaData);
|
||||
}
|
||||
|
||||
indexTransaction(bigTxn, nodes, nodeMetaDatas);
|
||||
waitForDocCount(new TermQuery(new Term("content@s___t@{http://www.alfresco.org/model/content/1.0}content", "world")), 61, 100000);
|
||||
|
||||
response0 = rangeCheck(0);
|
||||
values0 = response0.getValues();
|
||||
//{start=0,end=100,nodeCount=56,maxDbid=76,density=0.7368421052631579,expand=-1,expanded=false}
|
||||
assertEquals((long) values0.get("start"), 0);
|
||||
assertEquals((long) values0.get("end"), 100);
|
||||
assertEquals((long) values0.get("nodeCount"), 56);
|
||||
assertEquals((long)values0.get("minDbid"), 0);
|
||||
assertEquals((long) values0.get("maxDbid"), 76);
|
||||
assertEquals((double) values0.get("density"), 0.7368421052631579, 0.0);
|
||||
assertEquals((long) values0.get("expand"), -1);
|
||||
assertEquals((boolean) values0.get("expanded"), false);
|
||||
|
||||
response1 = rangeCheck(1);
|
||||
values1 = response1.getValues();
|
||||
System.out.println("_RANGECHECK1:" + values1);
|
||||
|
||||
assertEquals((long) values1.get("start"), 100);
|
||||
assertEquals((long) values1.get("end"), 200);
|
||||
assertEquals((long) values1.get("nodeCount"), 5);
|
||||
assertEquals((long)values1.get("minDbid"), 100);
|
||||
assertEquals((long) values1.get("maxDbid"), 104);
|
||||
assertEquals((long) values1.get("expand"), 0);
|
||||
assertEquals((boolean) values1.get("expanded"), false);
|
||||
|
||||
numNodes = 35;
|
||||
nodes = new ArrayList();
|
||||
nodeMetaDatas = new ArrayList();
|
||||
|
||||
bigTxn = getTransaction(0, numNodes);
|
||||
|
||||
for(int i=0; i<numNodes; i++) {
|
||||
int aclIndex = i % numAcls;
|
||||
Node node = getNode((long)i+120, bigTxn, bulkAcls.get(aclIndex), Node.SolrApiNodeStatus.UPDATED);
|
||||
nodes.add(node);
|
||||
NodeMetaData nodeMetaData = getNodeMetaData(node, bigTxn, bulkAcls.get(aclIndex), "mike", null, false);
|
||||
nodeMetaDatas.add(nodeMetaData);
|
||||
}
|
||||
|
||||
indexTransaction(bigTxn, nodes, nodeMetaDatas);
|
||||
waitForDocCount(new TermQuery(new Term("content@s___t@{http://www.alfresco.org/model/content/1.0}content", "world")), 96 , 100000);
|
||||
|
||||
response0 = rangeCheck(0);
|
||||
values0 = response0.getValues();
|
||||
//{start=0,end=100,nodeCount=56,maxDbid=76,density=0.7368421052631579,expand=-1,expanded=false}
|
||||
assertEquals((long) values0.get("start"), 0);
|
||||
assertEquals((long) values0.get("end"), 100);
|
||||
assertEquals((long) values0.get("nodeCount"), 56);
|
||||
assertEquals((long)values0.get("minDbid"), 0);
|
||||
assertEquals((long) values0.get("maxDbid"), 76);
|
||||
assertEquals((double) values0.get("density"), 0.7368421052631579, 0.0);
|
||||
assertEquals((long) values0.get("expand"), -1);
|
||||
assertEquals((boolean) values0.get("expanded"), false);
|
||||
|
||||
response1 = rangeCheck(1);
|
||||
values1 = response1.getValues();
|
||||
System.out.println("_RANGECHECK1:" + values1);
|
||||
//{start=100,end=200,nodeCount=40,maxDbid=154,density=0.7407407407407407,expand=35,expanded=false}
|
||||
|
||||
assertEquals((long) values1.get("start"), 100);
|
||||
assertEquals((long) values1.get("end"), 200);
|
||||
assertEquals((long) values1.get("nodeCount"), 40);
|
||||
assertEquals((long)values1.get("minDbid"), 100);
|
||||
assertEquals((long) values1.get("maxDbid"), 154);
|
||||
assertEquals((double) values1.get("density"), 0.7407407407407407, 0.0);
|
||||
assertEquals((long) values1.get("expand"), 35);
|
||||
assertEquals((boolean) values1.get("expanded"), false);
|
||||
|
||||
|
||||
//expand shard1 by 20
|
||||
expandResponse = expand(1, 35);
|
||||
expandValues = expandResponse.getValues();
|
||||
|
||||
expanded = (Number)expandValues.get("expand");
|
||||
assertEquals(expanded.intValue(), 235);
|
||||
|
||||
waitForShardsCount(new TermQuery(new Term(FIELD_SOLR4_ID, "TRACKER!STATE!CAP")),
|
||||
1,
|
||||
100000,
|
||||
System.currentTimeMillis());
|
||||
|
||||
response1 = rangeCheck(1);
|
||||
values1 = response1.getValues();
|
||||
System.out.println("_RANGECHECK1:" + values1);
|
||||
//{start=100,end=235,nodeCount=40,maxDbid=154,density=0.7407407407407407,expand=-1,expanded=true}
|
||||
|
||||
assertEquals((long) values1.get("start"), 100);
|
||||
assertEquals((long) values1.get("end"), 235);
|
||||
assertEquals((long) values1.get("nodeCount"), 40);
|
||||
assertEquals((long)values1.get("minDbid"), 100);
|
||||
assertEquals((long) values1.get("maxDbid"), 154);
|
||||
assertEquals((double) values1.get("density"),0.7407407407407407, 0.0);
|
||||
assertEquals((long) values1.get("expand"), -1);
|
||||
assertEquals((boolean) values1.get("expanded"), true);
|
||||
|
||||
numNodes = 3;
|
||||
nodes = new ArrayList();
|
||||
nodeMetaDatas = new ArrayList();
|
||||
|
||||
bigTxn = getTransaction(0, numNodes);
|
||||
|
||||
for(int i=0; i<numNodes; i++)
|
||||
{
|
||||
int aclIndex = i % numAcls;
|
||||
Node node = getNode((long)i+230, bigTxn, bulkAcls.get(aclIndex), Node.SolrApiNodeStatus.UPDATED);
|
||||
nodes.add(node);
|
||||
NodeMetaData nodeMetaData = getNodeMetaData(node, bigTxn, bulkAcls.get(aclIndex), "mike", null, false);
|
||||
nodeMetaDatas.add(nodeMetaData);
|
||||
}
|
||||
|
||||
indexTransaction(bigTxn, nodes, nodeMetaDatas);
|
||||
waitForDocCount(new TermQuery(new Term("content@s___t@{http://www.alfresco.org/model/content/1.0}content", "world")), 99, 100000);
|
||||
|
||||
response1 = rangeCheck(1);
|
||||
values1 = response1.getValues();
|
||||
System.out.println("_RANGECHECK1:" + values1);
|
||||
//{start=100,end=235,nodeCount=43,maxDbid=232,density=0.32575757575757575,expand=-1,expanded=true}
|
||||
|
||||
assertEquals((long) values1.get("start"), 100);
|
||||
assertEquals((long) values1.get("end"), 235);
|
||||
assertEquals((long) values1.get("nodeCount"), 43);
|
||||
assertEquals((long)values1.get("minDbid"), 100);
|
||||
assertEquals((long) values1.get("maxDbid"), 232);
|
||||
assertEquals((double) values1.get("density"), 0.32575757575757575, 0.0);
|
||||
assertEquals((long) values1.get("expand"), -1);
|
||||
assertEquals((boolean) values1.get("expanded"), true);
|
||||
|
||||
//assert(false);
|
||||
|
||||
//Do a reload
|
||||
}
|
||||
|
||||
protected Properties getShardMethod()
|
||||
{
|
||||
Properties prop = new Properties();
|
||||
prop.put("shard.method", "DB_ID_RANGE");
|
||||
return prop;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user