diff options
author | Henning Baldersheim <balder@yahoo-inc.com> | 2020-06-30 22:13:14 +0000 |
---|---|---|
committer | Henning Baldersheim <balder@yahoo-inc.com> | 2020-06-30 22:13:14 +0000 |
commit | 2ef3ab5fa7017e5fea5cdec223bcf98a9edf7550 (patch) | |
tree | 45bf1600236c9e14d12d3c1c3f18121c1153d927 | |
parent | aac7958354aab414dc036a82dcf493a749d6f1d5 (diff) |
Add support for serializing and compressing once, instead of once per backend node.
10 files changed, 85 insertions, 32 deletions
diff --git a/container-disc/src/main/java/com/yahoo/container/jdisc/metric/MetricUpdater.java b/container-disc/src/main/java/com/yahoo/container/jdisc/metric/MetricUpdater.java index e11622b1fa3..05c3b88b788 100644 --- a/container-disc/src/main/java/com/yahoo/container/jdisc/metric/MetricUpdater.java +++ b/container-disc/src/main/java/com/yahoo/container/jdisc/metric/MetricUpdater.java @@ -97,7 +97,6 @@ public class MetricUpdater extends AbstractComponent { this.jrtMetrics = new JrtMetrics(metric); } - @SuppressWarnings("deprecation") @Override public void run() { long freeMemory = runtime.freeMemory(); diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/InterleavedSearchInvoker.java b/container-search/src/main/java/com/yahoo/search/dispatch/InterleavedSearchInvoker.java index e62848a7f9e..d8fb7b46440 100644 --- a/container-search/src/main/java/com/yahoo/search/dispatch/InterleavedSearchInvoker.java +++ b/container-search/src/main/java/com/yahoo/search/dispatch/InterleavedSearchInvoker.java @@ -74,7 +74,7 @@ public class InterleavedSearchInvoker extends SearchInvoker implements ResponseM * will be adjusted accordingly. */ @Override - protected void sendSearchRequest(Query query) throws IOException { + protected Object sendSearchRequest(Query query, Object unusedContext) throws IOException { this.query = query; invokers.forEach(invoker -> invoker.setMonitor(this)); deadline = currentTime() + query.getTimeLeft(); @@ -89,13 +89,15 @@ public class InterleavedSearchInvoker extends SearchInvoker implements ResponseM query.setHits(q); query.setOffset(0); + Object context = null; for (SearchInvoker invoker : invokers) { - invoker.sendSearchRequest(query); + context = invoker.sendSearchRequest(query, context); askedNodes++; } query.setHits(originalHits); query.setOffset(originalOffset); + return null; } @Override diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/SearchErrorInvoker.java b/container-search/src/main/java/com/yahoo/search/dispatch/SearchErrorInvoker.java index a32931c43c8..256759360f7 100644 --- a/container-search/src/main/java/com/yahoo/search/dispatch/SearchErrorInvoker.java +++ b/container-search/src/main/java/com/yahoo/search/dispatch/SearchErrorInvoker.java @@ -35,11 +35,12 @@ public class SearchErrorInvoker extends SearchInvoker { } @Override - protected void sendSearchRequest(Query query) throws IOException { + protected Object sendSearchRequest(Query query, Object context) throws IOException { this.query = query; - if(monitor != null) { + if (monitor != null) { monitor.responseAvailable(this); } + return context; } @Override diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/SearchInvoker.java b/container-search/src/main/java/com/yahoo/search/dispatch/SearchInvoker.java index 45ed1b87746..9fd6ae9063c 100644 --- a/container-search/src/main/java/com/yahoo/search/dispatch/SearchInvoker.java +++ b/container-search/src/main/java/com/yahoo/search/dispatch/SearchInvoker.java @@ -32,14 +32,22 @@ public abstract class SearchInvoker extends CloseableInvoker { * for correct result windowing. */ public Result search(Query query, Execution execution) throws IOException { - sendSearchRequest(query); + sendSearchRequest(query, null); InvokerResult result = getSearchResult(execution); setFinalStatus(result.getResult().hits().getError() == null); result.complete(); return result.getResult(); } - protected abstract void sendSearchRequest(Query query) throws IOException; + /** + * + * @param query The query to send + * @param context A context object that can be used to pass context among different + * invokers. Fx for reuse of preserialized data. + * @return An object that can be passed to the next invocation of sendSearchRequest + * @throws IOException + */ + protected abstract Object sendSearchRequest(Query query, Object context) throws IOException; protected abstract InvokerResult getSearchResult(Execution execution) throws IOException; diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/rpc/ProtobufSerialization.java b/container-search/src/main/java/com/yahoo/search/dispatch/rpc/ProtobufSerialization.java index 51290c245ac..d13f04ea85e 100644 --- a/container-search/src/main/java/com/yahoo/search/dispatch/rpc/ProtobufSerialization.java +++ b/container-search/src/main/java/com/yahoo/search/dispatch/rpc/ProtobufSerialization.java @@ -91,7 +91,8 @@ public class ProtobufSerialization { return traceLevel; } - private static void mergeToSearchRequestFromRanking(Ranking ranking, SearchProtocol.SearchRequest.Builder builder) { + private static void + mergeToSearchRequestFromRanking(Ranking ranking, SearchProtocol.SearchRequest.Builder builder) { builder.setRankProfile(ranking.getProfile()); if (ranking.getQueryCache()) { diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcSearchInvoker.java b/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcSearchInvoker.java index 76240e55c98..e1e3389eb5a 100644 --- a/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcSearchInvoker.java +++ b/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcSearchInvoker.java @@ -44,22 +44,40 @@ public class RpcSearchInvoker extends SearchInvoker implements Client.ResponseRe this.maxHits = maxHits; } + static class Context { + final Compressor.Compression compressionResult; + final int payloadLength; + Context(RpcResourcePool resourcePool, Query query, byte [] payload) { + this.payloadLength = payload.length; + compressionResult = resourcePool.compress(query, payload); + } + } + @Override - protected void sendSearchRequest(Query query) { + protected Object sendSearchRequest(Query query, Object context_in) { this.query = query; Client.NodeConnection nodeConnection = resourcePool.getConnection(node.key()); if (nodeConnection == null) { responses.add(Client.ResponseOrError.fromError("Could not send search to unknown node " + node.key())); responseAvailable(); - return; + return context_in; } query.trace(false, 5, "Sending search request with jrt/protobuf to node with dist key ", node.key()); - var payload = ProtobufSerialization.serializeSearchRequest(query, Math.min(query.getHits(), maxHits), searcher.getServerId()); + Context context; + if (context_in instanceof Context) { + context = (Context) context_in; + } else { + context = new Context(resourcePool, query, + ProtobufSerialization.serializeSearchRequest(query, + Math.min(query.getHits(), maxHits), + searcher.getServerId())); + } double timeoutSeconds = ((double) query.getTimeLeft() - 3.0) / 1000.0; - Compressor.Compression compressionResult = resourcePool.compress(query, payload); - nodeConnection.request(RPC_METHOD, compressionResult.type(), payload.length, compressionResult.data(), this, timeoutSeconds); + nodeConnection.request(RPC_METHOD, context.compressionResult.type(), context.payloadLength, + context.compressionResult.data(), this, timeoutSeconds); + return context; } @Override diff --git a/container-search/src/test/java/com/yahoo/search/dispatch/MockInvoker.java b/container-search/src/test/java/com/yahoo/search/dispatch/MockInvoker.java index c159293d7d9..459dcc83ab0 100644 --- a/container-search/src/test/java/com/yahoo/search/dispatch/MockInvoker.java +++ b/container-search/src/test/java/com/yahoo/search/dispatch/MockInvoker.java @@ -34,9 +34,10 @@ class MockInvoker extends SearchInvoker { } @Override - protected void sendSearchRequest(Query query) throws IOException { + protected Object sendSearchRequest(Query query, Object context) throws IOException { this.query = query; hitsRequested = query.getHits(); + return context; } @Override diff --git a/container-search/src/test/java/com/yahoo/search/dispatch/rpc/RpcSearchInvokerTest.java b/container-search/src/test/java/com/yahoo/search/dispatch/rpc/RpcSearchInvokerTest.java index ce19224b35f..153e462a410 100644 --- a/container-search/src/test/java/com/yahoo/search/dispatch/rpc/RpcSearchInvokerTest.java +++ b/container-search/src/test/java/com/yahoo/search/dispatch/rpc/RpcSearchInvokerTest.java @@ -20,6 +20,7 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -38,7 +39,9 @@ public class RpcSearchInvokerTest { var invoker = new RpcSearchInvoker(mockSearcher(), new Node(7, "seven", 1), mockPool, 1000); Query q = new Query("search/?query=test&hits=10&offset=3"); - invoker.sendSearchRequest(q); + RpcSearchInvoker.Context context = (RpcSearchInvoker.Context) invoker.sendSearchRequest(q, null); + assertTrue( context.payloadLength == lengthHolder.get()); + assertSame(context.compressionResult.data(), payloadHolder.get()); var bytes = mockPool.compressor().decompress(payloadHolder.get(), compressionTypeHolder.get(), lengthHolder.get()); var request = SearchProtocol.SearchRequest.newBuilder().mergeFrom(bytes).build(); @@ -46,6 +49,12 @@ public class RpcSearchInvokerTest { assertEquals(10, request.getHits()); assertEquals(3, request.getOffset()); assertTrue(request.getQueryTreeBlob().size() > 0); + + var invoker2 = new RpcSearchInvoker(mockSearcher(), new Node(8, "eight", 1), mockPool, 1000); + RpcSearchInvoker.Context context2 = (RpcSearchInvoker.Context)invoker2.sendSearchRequest(q, context); + assertSame(context, context2); + assertTrue( context.payloadLength == lengthHolder.get()); + assertSame(context.compressionResult.data(), payloadHolder.get()); } @Test @@ -59,7 +68,7 @@ public class RpcSearchInvokerTest { var invoker = new RpcSearchInvoker(mockSearcher(), new Node(7, "seven", 1), mockPool, maxHits); Query q = new Query("search/?query=test&hits=10&offset=3"); - invoker.sendSearchRequest(q); + invoker.sendSearchRequest(q, null); var bytes = mockPool.compressor().decompress(payloadHolder.get(), compressionTypeHolder.get(), lengthHolder.get()); var request = SearchProtocol.SearchRequest.newBuilder().mergeFrom(bytes).build(); diff --git a/container-search/src/test/java/com/yahoo/search/searchchain/config/test/SearchChainConfigurerTestCase.java b/container-search/src/test/java/com/yahoo/search/searchchain/config/test/SearchChainConfigurerTestCase.java index a57ed07017f..5b16802a65e 100644 --- a/container-search/src/test/java/com/yahoo/search/searchchain/config/test/SearchChainConfigurerTestCase.java +++ b/container-search/src/test/java/com/yahoo/search/searchchain/config/test/SearchChainConfigurerTestCase.java @@ -18,13 +18,29 @@ import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; -import java.io.*; -import java.util.*; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Random; import java.util.regex.Matcher; import java.util.regex.Pattern; import static org.hamcrest.CoreMatchers.*; -import static org.junit.Assert.*; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertThat; /** * @author bratseth @@ -32,8 +48,8 @@ import static org.junit.Assert.*; */ public class SearchChainConfigurerTestCase { - private static Random random = new Random(1); - private static String topCfgDir = System.getProperty("java.io.tmpdir") + File.separator + + private static final Random random = new Random(1); + private static final String topCfgDir = System.getProperty("java.io.tmpdir") + File.separator + "SearchChainConfigurerTestCase" + File.separator; private static final String testDir = "src/test/java/com/yahoo/search/searchchain/config/test/"; @@ -132,7 +148,7 @@ public class SearchChainConfigurerTestCase { * that does not contain any bootstrap configs. */ @Test - public void testSearcherConfigUpdate() throws IOException, InterruptedException { + public void testSearcherConfigUpdate() throws IOException { File cfgDir = getCfgDir(); copyFile(testDir + "handlers.cfg", cfgDir + "/handlers.cfg"); copyFile(testDir + "qr-search.cfg", cfgDir + "/qr-search.cfg"); @@ -171,9 +187,9 @@ public class SearchChainConfigurerTestCase { // Searchers with unchanged config (or that takes no config) are the same as before. Searcher s = searchers.getComponent(DeclaredTestSearcher.class.getName()); - assertThat((DeclaredTestSearcher)s, sameInstance(noConfigSearcher)); + assertThat(s, sameInstance(noConfigSearcher)); s = searchers.getComponent(StringSearcher.class.getName()); - assertThat((StringSearcher)s, sameInstance(stringSearcher)); + assertThat(s, sameInstance(stringSearcher)); configurer.shutdown(); cleanup(cfgDir); @@ -219,7 +235,7 @@ public class SearchChainConfigurerTestCase { assertThat(getSearchChainRegistryFrom(configurer).getSearcherRegistry(), not(searchers)); searchers = getSearchChainRegistryFrom(configurer).getSearcherRegistry(); assertThat(searchers.getComponentCount(), is(3)); - assertThat((IntSearcher)searchers.getComponent(IntSearcher.class.getName()), sameInstance(intSearcher)); + assertThat(searchers.getComponent(IntSearcher.class.getName()), sameInstance(intSearcher)); assertThat(searchers.getComponent(ConfigurableSearcher.class.getName()), instanceOf(ConfigurableSearcher.class)); assertThat(searchers.getComponent(DeclaredTestSearcher.class.getName()), instanceOf(DeclaredTestSearcher.class)); assertThat(searchers.getComponent(StringSearcher.class.getName()), nullValue()); @@ -326,7 +342,7 @@ public class SearchChainConfigurerTestCase { if (append) { Pattern p = Pattern.compile("^[a-z]+" + "\\[\\d+\\]\\.id (.+)"); BufferedReader reader = new BufferedReader(new InputStreamReader( - new FileInputStream(new File(componentsFile)), "UTF-8")); + new FileInputStream(new File(componentsFile)), StandardCharsets.UTF_8)); while ((line = reader.readLine()) != null) { Matcher m = p.matcher(line); if (m.matches() && !m.group(1).equals(HandlersConfigurerDi.RegistriesHack.class.getName())) { @@ -337,7 +353,7 @@ public class SearchChainConfigurerTestCase { reader.close(); } BufferedReader reader = new BufferedReader(new InputStreamReader( - new FileInputStream(new File(configFile)), "UTF-8")); + new FileInputStream(new File(configFile)), StandardCharsets.UTF_8)); Pattern component = Pattern.compile("^" + componentType + "\\[\\d+\\]\\.id (.+)"); while ((line = reader.readLine()) != null) { Matcher m = component.matcher(line); @@ -353,7 +369,7 @@ public class SearchChainConfigurerTestCase { buf.append("components[").append(i++).append("].id ").append(ExecutionFactory.class.getName()).append("\n"); buf.insert(0, "components["+i+"]\n"); - Writer writer = new OutputStreamWriter(new FileOutputStream(new File(componentsFile)), "UTF-8"); + Writer writer = new OutputStreamWriter(new FileOutputStream(new File(componentsFile)), StandardCharsets.UTF_8); writer.write(buf.toString()); writer.flush(); writer.close(); diff --git a/processing/src/main/java/com/yahoo/processing/request/CompoundName.java b/processing/src/main/java/com/yahoo/processing/request/CompoundName.java index 976fb3e2796..09c0879fdbf 100644 --- a/processing/src/main/java/com/yahoo/processing/request/CompoundName.java +++ b/processing/src/main/java/com/yahoo/processing/request/CompoundName.java @@ -5,7 +5,6 @@ import com.google.common.collect.ImmutableList; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.List; import static com.yahoo.text.Lowercase.toLowerCase; @@ -141,9 +140,8 @@ public final class CompoundName { if (nameParts.length == 0) return this; if (isEmpty()) return fromComponents(nameParts); - List<String> newCompounds = new ArrayList<>(); - for (String namePart : nameParts) - newCompounds.add(namePart); + List<String> newCompounds = new ArrayList<>(nameParts.length+compounds.size()); + newCompounds.addAll(Arrays.asList(nameParts)); newCompounds.addAll(this.compounds); return new CompoundName(newCompounds); } |