diff --git a/java_src/build.xml b/java_src/build.xml new file mode 100644 index 00000000..1531814d --- /dev/null +++ b/java_src/build.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + out + ../yz-build + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java_src/com/basho/yokozuna/handler/EntropyData.java b/java_src/com/basho/yokozuna/handler/EntropyData.java index ec2d6ea2..6750f465 100644 --- a/java_src/com/basho/yokozuna/handler/EntropyData.java +++ b/java_src/com/basho/yokozuna/handler/EntropyData.java @@ -16,30 +16,40 @@ package com.basho.yokozuna.handler; -import java.io.IOException; -import javax.xml.bind.DatatypeConverter; +import java.io.IOException; +import java.util.Optional; +//import java.util.function.*; -import org.apache.lucene.util.Bits; -import org.apache.lucene.util.BytesRef; -import org.apache.lucene.index.AtomicReader; -import org.apache.lucene.index.DocsEnum; +import org.apache.commons.codec.binary.Base64; +import org.apache.lucene.index.LeafReader; +import org.apache.lucene.index.PostingsEnum; import org.apache.lucene.index.Terms; import org.apache.lucene.index.TermsEnum; -import org.apache.lucene.search.DocIdSetIterator; - +import org.apache.lucene.util.Bits; +import org.apache.lucene.util.BytesRef; import org.apache.solr.common.SolrDocument; import org.apache.solr.common.SolrDocumentList; +import org.apache.solr.common.SolrException; +import org.apache.solr.common.SolrException.ErrorCode; import org.apache.solr.core.PluginInfo; import org.apache.solr.handler.RequestHandlerBase; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.response.SolrQueryResponse; import org.apache.solr.search.SolrIndexSearcher; import org.apache.solr.util.plugin.PluginInfoInitialized; - +//import org.codehaus.jackson.map.Serializers; +//import org.jetbrains.annotations.Contract; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.apache.commons.codec.binary.Base64; +//import org.apache.lucene.search.IndexSearcher; +//import org.apache.solr.search.BitDocSet; +//import org.apache.lucene.index.AtomicReader; +//import org.apache.lucene.index.DocsEnum; + + /** * This class provides handler logic to iterate over the entropy data * stored in the index. This data can be used to build a hash tree to @@ -49,150 +59,215 @@ public class EntropyData extends RequestHandlerBase implements PluginInfoInitialized { - protected static final Logger log = LoggerFactory.getLogger(EntropyData.class); - static final BytesRef DEFAULT_CONT = null; - static final int DEFAULT_N = 1000; + private static final Logger log = LoggerFactory.getLogger(EntropyData.class); + private static final BytesRef DEFAULT_CONT = null; + private static final int DEFAULT_N = 1000; + // @SuppressWarnings("WeakerAccess") static final String ENTROPY_DATA_FIELD = "_yz_ed"; // Pass info from solrconfig.xml public void init(final PluginInfo info) { - init(info.initArgs); + this.init(info.initArgs); } @Override - public void handleRequestBody(final SolrQueryRequest req, final SolrQueryResponse rsp) - throws Exception, InstantiationException, IllegalAccessException { + public void handleRequestBody(final SolrQueryRequest req, final SolrQueryResponse response) + throws SolrException { + final String contParam = req.getParams().get("continue"); - final BytesRef cont = contParam != null ? - decodeCont(contParam) : DEFAULT_CONT; + final BytesRef cont = contParam != null ? decodeCont(contParam) : DEFAULT_CONT; final int n = req.getParams().getInt("n", DEFAULT_N); final String partition = req.getParams().get("partition"); if (partition == null) { - throw new Exception("Parameter 'partition' is required"); + throw new SolrException(ErrorCode.BAD_REQUEST, "Parameter 'partition' is required"); } - final SolrDocumentList docs = new SolrDocumentList(); - - // Add docs here and modify object inline in code - rsp.add("response", docs); + final SolrDocumentList resultDocs = new SolrDocumentList(); + // Add docs here and modify ‘docs’ inline in code + response.add("response", resultDocs); try { final SolrIndexSearcher searcher = req.getSearcher(); - final AtomicReader rdr = searcher.getAtomicReader(); - BytesRef tmp = null; - final Terms terms = rdr.terms(ENTROPY_DATA_FIELD); + final LeafReader rdr = searcher.getSlowAtomicReader(); + + final Optional terms = Optional.ofNullable(rdr.terms(this.ENTROPY_DATA_FIELD)); - if (terms == null) { - rsp.add("more", false); + if (!terms.isPresent()) { + noMore(response); return; } - final TermsEnum te = terms.iterator(null); + final TermsEnum te = terms.get().iterator(); + if (isContinue(cont)) { if (log.isDebugEnabled()) { - log.debug("continue from " + cont); + log.debug("continue from {}", cont); } - final TermsEnum.SeekStatus status = te.seekCeil(cont); - - if (status == TermsEnum.SeekStatus.END) { - rsp.add("more", false); + final TermsEnum.SeekStatus sought = te.seekCeil(cont); + if (log.isDebugEnabled()) + log.debug("seek({}) → {}", cont, sought); + switch (sought) { + case END: + noMore(response); return; - } else if (status == TermsEnum.SeekStatus.FOUND) { - // If this term has already been seen then skip it. - tmp = te.next(); - if (endOfItr(tmp)) { - rsp.add("more", false); + case FOUND: + // If this term has already been seen then skip it. + if (te.next() == null) { + noMore(response); return; } - } else if (status == TermsEnum.SeekStatus.NOT_FOUND) { - tmp = te.next(); + break; + + case NOT_FOUND: + te.next(); + break; } - } else { - tmp = te.next(); + } + /* no cont parameter */ + else { + te.next(); } - int count = 0; - BytesRef current = null; - final Bits liveDocs = rdr.getLiveDocs(); + int count = 0; // TODO just do docs.size()? - while(!endOfItr(tmp) && count < n) { - if (isLive(liveDocs, te)) { - current = BytesRef.deepCopyOf(tmp); - final String text = tmp.utf8ToString(); - if (log.isDebugEnabled()) { - log.debug("text: " + text); - } - final String [] vals = text.split(" "); - - final String docPartition = vals[1]; - - /* - If the partition matches the one we are looking for, - parse the version, bkey, and object hash from the - entropy data field (term). - */ - if (partition.equals(docPartition)) { - final String vsn = vals[0]; - - final String [] decoded = decodeForVersion(vsn, - vals[2], - vals[3], - vals[4]); - - final String hash = vals[5]; - - final SolrDocument tmpDoc = new SolrDocument(); - tmpDoc.addField("vsn", vsn); - tmpDoc.addField("riak_bucket_type", decoded[0]); - tmpDoc.addField("riak_bucket_name", decoded[1]); - tmpDoc.addField("riak_key", decoded[2]); - tmpDoc.addField("base64_hash", hash); - docs.add(tmpDoc); - count++; + BytesRef lastSeen = null; + + { + final Bits liveDocs = rdr.getLiveDocs(); + + for (BytesRef ref = te.term(); ref != null; ref = te.next()) { + if (count < n && isLive(liveDocs, te)) { + lastSeen = BytesRef.deepCopyOf(ref); + Optional x = getDocIfPn(partition, lastSeen); + if (x.isPresent()) { + resultDocs.add(x.get()); + count++; + } } } - tmp = te.next(); - } + } //liveDocs if (count < n) { - rsp.add("more", false); + noMore(response); } else { - rsp.add("more", true); - final String newCont = - org.apache.commons.codec.binary.Base64.encodeBase64URLSafeString(current.bytes); + response.add("more", true); + + assert lastSeen != null; + + final String newCont = Base64.encodeBase64URLSafeString(lastSeen.bytes); // The continue context for next req to start where // this one finished. - rsp.add("continuation", newCont); + response.add("continuation", newCont); } - docs.setNumFound(count); + resultDocs.setNumFound(count); + } + catch (final Exception e) { + log.error("bad things, {}", e); + } - } catch (final Exception e) { - e.printStackTrace(); + } + + + private void noMore(SolrQueryResponse rsp) { + rsp.add("more", false); + } + + + // @Contract("null, _ -> true") + private static boolean isLive(final Bits liveDocs, final TermsEnum te) { + if (liveDocs == null) + return true; + + try { + PostingsEnum posts = te.postings(null, PostingsEnum.NONE); + int firstDid = posts.nextDoc(); + assert firstDid != -1; // as we've called nextDoc() + assert firstDid != posts.NO_MORE_DOCS; // there should be one + boolean alive = liveDocs.get(firstDid); + + { + // FIXME Is this even possible? + // Being overly causious. + int did; + boolean firstAlive = alive; + while ((did = posts.nextDoc()) != posts.NO_MORE_DOCS) { + // Solr, are you drunk + boolean a = liveDocs.get(did); + log.info("Same-terms docs: first was {} [alive={}] and now {} [alive={}]", firstDid, firstAlive, did, a); + alive = alive || a; + } + } + + if (log.isDebugEnabled()) { + if (!alive) + log.debug("Dead! docid={}", firstDid); + } + return alive; + } catch (IOException e) { + log.error("cannot get postings for TermsEnum {}", te); + return false; } + + } - static boolean isLive(final Bits liveDocs, final TermsEnum te) throws IOException { - final DocsEnum de = te.docs(liveDocs, null); - return de.nextDoc() != DocIdSetIterator.NO_MORE_DOCS; + /** + * Get a {@link SolrDocument} encoded in tmp, if it matches {@param partition} + */ + private Optional getDocIfPn(String partition, BytesRef tmp) { + final String text = tmp.utf8ToString(); + if (log.isTraceEnabled()) + log.trace("getDoc if p={}", partition); + + final String[] vals = text.split(" "); + + final String docPartition = vals[1]; + + /* + If the partition matches the one we are looking for, + parse the version, bkey, and object hash from the + entropy data field (term). + */ + if (partition.equals(docPartition)) { + if (log.isDebugEnabled()) + log.debug(" getDoc 「{}」", text); + + final String vsn = vals[0]; + final String[] decoded = decodeForVersion(vsn, + vals[2], + vals[3], + vals[4]); + + final String hash = vals[5]; + + final SolrDocument tmpDoc = new SolrDocument(); + tmpDoc.addField("vsn", vsn); + tmpDoc.addField("riak_bucket_type", decoded[0]); + tmpDoc.addField("riak_bucket_name", decoded[1]); + tmpDoc.addField("riak_key", decoded[2]); + tmpDoc.addField("base64_hash", hash); + return Optional.of(tmpDoc); + } + return Optional.empty(); } - static BytesRef decodeCont(final String cont) { + private static BytesRef decodeCont(final String cont) { final byte[] bytes = org.apache.commons.codec.binary.Base64.decodeBase64(cont); return new BytesRef(bytes); } - static boolean endOfItr(final BytesRef returnValue) { - return returnValue == null; - } + // private static boolean endOfItr(final BytesRef returnValue) { + // return returnValue == null; + // } - static boolean isContinue(final BytesRef cont) { + private static boolean isContinue(final BytesRef cont) { return DEFAULT_CONT != cont; } @@ -201,48 +276,45 @@ public String getDescription() { return "vector clock data iterator"; } - @Override - public String getVersion() { - return "0.0.1"; - } - - @Override - public String getSource() { - return "TODO: implement getSource"; - } + // @Override + // public String getVersion() { + // return "0.0.1"; + // } /** - @param vsn a String vsn number referring to the item's ed handler version - @param riakBType riak bucket-type - @param riakBName riak bucket-name - @param riakKey riak key - @return a String array consisting of a Bucket Type, Bucket Name, and Riak Key - */ - private String [] decodeForVersion(String vsn, String riakBType, String riakBName, String riakKey) { - final String [] bKeyInfo; - switch(Integer.parseInt(vsn)) { - case 1: - bKeyInfo = new String [] {riakBType, riakBName, riakKey}; - break; - default: - bKeyInfo = new String [] - { - decodeBase64DocPart(riakBType), - decodeBase64DocPart(riakBName), - decodeBase64DocPart(riakKey) - }; - break; + * @param vsn a String vsn number referring to the item's ed handler version + * @param riakBType riak bucket-type + * @param riakBName riak bucket-name + * @param riakKey riak key + * @return a String array consisting of a Bucket Type, Bucket Name, and Riak Key + */ + private String[] decodeForVersion(String vsn, String riakBType, String riakBName, String riakKey) { + final String[] bKeyInfo; + switch (Integer.parseInt(vsn)) { + case 1: + bKeyInfo = new String[]{riakBType, riakBName, riakKey}; + break; + default: + bKeyInfo = new String[] + { + decodeBase64DocPart(riakBType), + decodeBase64DocPart(riakBName), + decodeBase64DocPart(riakKey) + }; + break; } return bKeyInfo; } /** - @param base64EncodedVal base64 encoded string - @return a string of decoded base64 bytes - */ - private String decodeBase64DocPart(String base64EncodedVal) { - return new String(DatatypeConverter.parseBase64Binary( - base64EncodedVal)); + * @param base64EncodedVal base64 encoded string + * @return a string of decoded base64 bytes + */ + + public static String decodeBase64DocPart(String base64EncodedVal) { + //return new String(DatatypeConverter.parseBase64Binary( + // base64EncodedVal)); + return new String(Base64.decodeBase64(base64EncodedVal)); } } diff --git a/java_src/com/basho/yokozuna/handler/component/FQShardTranslator.java b/java_src/com/basho/yokozuna/handler/component/FQShardTranslator.java index 1e1a02d5..8fafe79e 100644 --- a/java_src/com/basho/yokozuna/handler/component/FQShardTranslator.java +++ b/java_src/com/basho/yokozuna/handler/component/FQShardTranslator.java @@ -8,10 +8,8 @@ import org.apache.solr.handler.component.ShardRequest; import org.apache.solr.request.SolrQueryRequest; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.slf4j.*; -import java.io.IOException; /** * Translate custom Yokozuna filter query shard params to normal @@ -33,20 +31,23 @@ * each shard by passing a query param with the name `$host:$port` and * a value of the filter query to run. For example: * - * ?10.0.1.100:10014=_yz_pn:1 OR _yz_pn:7 OR ...\ - * &10.0.1.101:10014=_yz_pn:4 OR _yz_pn:10 OR ... - * + *
+ * {@code
+ * ?10.0.1.100:10014=_yz_pn:1 OR _yz_pn:7 OR ...\
+ *    &10.0.1.101:10014=_yz_pn:4 OR _yz_pn:10 OR ...
+ * }
+ * 
*/ public class FQShardTranslator extends SearchComponent { protected static final Logger log = LoggerFactory.getLogger(FQShardTranslator.class); public static final String COMPONENT_NAME = "fq_shard_translator"; @Override - public void prepare(ResponseBuilder rb) throws IOException { + public void prepare(ResponseBuilder rb) { SolrQueryRequest req = rb.req; SolrParams params = req.getParams(); - if (!isDistrib(params)) { + if (! rb.isDistributed()) { String shardUrl = params.get(ShardParams.SHARD_URL); if (shardUrl != null) { String hostPort = shardUrl.substring(0, shardUrl.indexOf('/')); @@ -58,32 +59,21 @@ public void prepare(ResponseBuilder rb) throws IOException { } @Override - public void process(ResponseBuilder rb) throws IOException { - return; + public void process(ResponseBuilder rb) { } @Override - public void modifyRequest(ResponseBuilder rb, SearchComponent who, ShardRequest sreq) { - return; - } + public void modifyRequest(ResponseBuilder rb, SearchComponent who, ShardRequest sreq) {} + @Override public String getDescription() { return "Yokozuna's FQ Shard Translator"; } - @Override + // @Override public String getSource() { return "https://github.com/basho/yokozuna"; } - private boolean isDistrib(SolrParams params) { - // Based on HttpShardHandler because rb.isDistrib is not public. - boolean distrib = params.getBool("distrib", false); - String shards = params.get(ShardParams.SHARDS); - boolean hasShardURL = shards != null; - - return hasShardURL || distrib; - } - } diff --git a/java_src/com/basho/yokozuna/handler/package-info.java b/java_src/com/basho/yokozuna/handler/package-info.java new file mode 100644 index 00000000..4e2208b5 --- /dev/null +++ b/java_src/com/basho/yokozuna/handler/package-info.java @@ -0,0 +1,2 @@ +package com.basho.yokozuna.handler; + diff --git a/java_src/com/basho/yokozuna/monitor/Monitor.java b/java_src/com/basho/yokozuna/monitor/Monitor.java index 51c028e4..e1ca4c96 100644 --- a/java_src/com/basho/yokozuna/monitor/Monitor.java +++ b/java_src/com/basho/yokozuna/monitor/Monitor.java @@ -15,10 +15,11 @@ */ package com.basho.yokozuna.monitor; +import org.slf4j.*; + import java.io.IOException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; + /** * Kill Solr when stdin closes, as it will when the Erlang VM shuts @@ -37,28 +38,31 @@ public void run() { log.debug("Monitor attempting read on stdin"); } if (System.in.read() < 0) { - if (log.isInfoEnabled()) { - log.info("Yokozuna has exited - shutting down Solr"); - } - System.exit(0); + die(); } if (log.isDebugEnabled()) { log.debug("Monitoring succeeded reading stdin"); } } catch (final IOException ioe) { - if (log.isInfoEnabled()) { - log.info("Yokozuna has exited - shutting down Solr"); - } - System.exit(0); + die(); } } + // for dtrace’s sake + private void die() { + if (log.isInfoEnabled()) { + log.info("Yokozuna has exited - shutting down Solr"); + } + System.exit(0); + } + /** * Start monitoring stdin in a background thread */ public static Monitor monitor() { final Monitor m = new Monitor(); + m.setName("riak superviser thread"); m.start(); return m; } @@ -72,7 +76,7 @@ public static void main(String[] args) { try { while(true) { // hang out until thread sees stdin close - Thread.sleep(1000); + Thread.sleep(1000L); } } catch (final InterruptedException ie) { diff --git a/java_src/com/basho/yokozuna/monitor/package-info.java b/java_src/com/basho/yokozuna/monitor/package-info.java new file mode 100644 index 00000000..6fde928f --- /dev/null +++ b/java_src/com/basho/yokozuna/monitor/package-info.java @@ -0,0 +1 @@ +package com.basho.yokozuna.monitor; diff --git a/java_src/com/basho/yokozuna/query/EntropyClient.java b/java_src/com/basho/yokozuna/query/EntropyClient.java new file mode 100644 index 00000000..78c93956 --- /dev/null +++ b/java_src/com/basho/yokozuna/query/EntropyClient.java @@ -0,0 +1,39 @@ +/** + * Lucene index walker client. + * + */ + + + + +package com.basho.yokozuna.query; + +import java.io.IOException; +import java.nio.file.FileSystems; +import java.nio.file.Path; + + +import org.apache.lucene.index.DirectoryReader; +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.index.IndexReaderContext; +import org.apache.lucene.index.LeafReaderContext; +import org.apache.lucene.store.Directory; +import org.apache.lucene.store.MMapDirectory; + +public class EntropyClient { + public static void main(String... args) throws IOException { + + String dirS = args[0]; + Path pa = FileSystems.getDefault().getPath(dirS); + Directory dir = new MMapDirectory(pa); + + try (DirectoryReader reader = DirectoryReader.open(dir)) { + reader.leaves().stream().forEachOrdered((LeafReaderContext x) -> { + System.out.printf("\u001b[4m=== %s\u001b[m\nbase=%d\n", x, x.docBase); + }); + } + + System.err.println("Done."); + + } +} diff --git a/java_src/com/basho/yokozuna/query/SimpleQueryExample.java b/java_src/com/basho/yokozuna/query/SimpleQueryExample.java index 38c22936..288a214d 100644 --- a/java_src/com/basho/yokozuna/query/SimpleQueryExample.java +++ b/java_src/com/basho/yokozuna/query/SimpleQueryExample.java @@ -4,38 +4,49 @@ * * Usage: * - * java -cp priv/java_lib/yokozuna.jar:priv/solr-jars/WEB-INF/lib/* com.basho.yokozuna.query.SimpleQueryExample BASE_URL INDEX FIELD TERM + * java -cp priv/solr-jars/WEB-INF/lib/* com.basho.yokozuna.query.SimpleQueryExample BASE_URL INDEX FIELD TERM * * Example: * - * java -cp priv/java_lib/yokozuna.jar:priv/solr-jars/WEB-INF/lib/* com.basho.yokozuna.query.SimpleQueryExample http://localhost:8098/search fruit text apple + * java -cp priv/solr-jars/WEB-INF/lib/* com.basho.yokozuna.query.SimpleQueryExample http://localhost:8098/search fruit text apple */ package com.basho.yokozuna.query; -import org.apache.solr.client.solrj.SolrRequest; -import org.apache.solr.client.solrj.SolrServer; +import java.io.IOException; + +import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrServerException; -import org.apache.solr.client.solrj.impl.HttpSolrServer; +import org.apache.solr.client.solrj.impl.HttpSolrClient; +//import org.apache.solr.client.solrj.request.QueryRequest; +import org.apache.solr.client.solrj.impl.HttpSolrClient.Builder; import org.apache.solr.client.solrj.response.QueryResponse; -import org.apache.solr.client.solrj.request.QueryRequest; import org.apache.solr.common.params.ModifiableSolrParams; +//@SuppressWarnings("UseOfSystemOutOrSystemErr") public class SimpleQueryExample { - public static void main(String[] args) throws SolrServerException { + + + + public static void main(final String[] args) + throws SolrServerException, IOException { final String baseURL = args[0]; final String index = args[1]; final String field = args[2]; final String term = args[3]; - final SolrServer solr = new HttpSolrServer(baseURL + "/" + index); - final ModifiableSolrParams params = new ModifiableSolrParams(); + String prefix = baseURL + "/" + index; + SolrClient solr = new Builder(prefix).build(); + + + ModifiableSolrParams params = new ModifiableSolrParams(); params.set("qt", "/"); params.set("q", field + ":" + term); - final SolrRequest req = new QueryRequest(params); + //SolrRequest req = new QueryRequest(params); + + QueryResponse resp = solr.query(params); - final QueryResponse resp = solr.query(params); System.out.println("resp: " + resp); } } diff --git a/priv/conf/solrconfig.xml b/priv/conf/solrconfig.xml index 521f75df..3a598976 100644 --- a/priv/conf/solrconfig.xml +++ b/priv/conf/solrconfig.xml @@ -633,8 +633,8 @@ Admin Handlers - This will register all the standard admin RequestHandlers. --> - + + - - - - _yz_id:ping_query - - + + + + + + diff --git a/priv/default_schema.xml b/priv/default_schema.xml index 32058ca6..8543a9b4 100644 --- a/priv/default_schema.xml +++ b/priv/default_schema.xml @@ -20,7 +20,7 @@ - + @@ -48,7 +48,6 @@ - @@ -141,6 +140,8 @@ + + @@ -456,18 +457,6 @@ - - - - - - - - - - - - diff --git a/priv/solr/contexts/solr-jetty-context.xml b/priv/solr/contexts/solr-jetty-context.xml index 6a811851..21be01ce 100644 --- a/priv/solr/contexts/solr-jetty-context.xml +++ b/priv/solr/contexts/solr-jetty-context.xml @@ -1,8 +1,20 @@ - - + + - - /webapps/solr.war - /etc/webdefault.xml - /solr-webapp + + + + /solr-webapp/webapp + /etc/webdefault.xml + false + + + + + + + + + + diff --git a/priv/solr/etc/jetty-http.xml b/priv/solr/etc/jetty-http.xml new file mode 100644 index 00000000..2bac8e98 --- /dev/null +++ b/priv/solr/etc/jetty-http.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/priv/solr/etc/jetty.xml b/priv/solr/etc/jetty.xml index a6898712..c2fd61bc 100644 --- a/priv/solr/etc/jetty.xml +++ b/priv/solr/etc/jetty.xml @@ -1,5 +1,5 @@ - + @@ -12,126 +12,153 @@ - - - - + + + + + + + + + + + + + + + + + + + + + + solr.jetty + + + + + + + + + + + false + + + + + + + + + + + + + + + + + + + + https + + + + + + + + + + + - - - - - - 10 - 10000 - false - - - - - + + + true + false + requestedPath - - - - - - - log4j.configuration etc/log4j.properties - - - 60000 - - 5000 - - - false + + + + ^/$ + /solr/ - - - - - + + + + + + /v2/* + /solr/____v2 + + + + + + + /api/* + /solr/____v2 + + + + + + + + + /solr/* + /internal_solr + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - + - true - false - false - 1000 false false - - - - + org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern .*/servlet-api-[^/]*\.jar$ - + + + + + /contexts + 0 + + +