From db32d4cb929c6931825875d80ef8d4ff2dc367e1 Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Sat, 1 Dec 2018 18:33:01 -0800 Subject: Revert "Bratseth/remove unused rpc server take 3" --- .../main/java/com/yahoo/container/ConfigHack.java | 31 +++++ .../main/java/com/yahoo/container/Container.java | 30 ++++- .../src/main/java/com/yahoo/container/Server.java | 50 +++++++- .../yahoo/container/config/StatisticsEmitter.java | 20 ++++ .../container/config/StatisticsRequestHandler.java | 55 +++++++++ .../com/yahoo/container/config/package-info.java | 5 + .../yahoo/container/config/testutil/TestUtil.java | 85 ++++++++++++++ .../core/slobrok/SlobrokConfigurator.java | 26 +++++ .../yahoo/container/osgi/AbstractRpcAdaptor.java | 15 +++ .../yahoo/container/osgi/ContainerRpcAdaptor.java | 129 +++++++++++++++++++++ .../com/yahoo/container/osgi/package-info.java | 5 + .../src/main/java/com/yahoo/osgi/OsgiImpl.java | 2 + 12 files changed, 444 insertions(+), 9 deletions(-) create mode 100644 container-core/src/main/java/com/yahoo/container/ConfigHack.java create mode 100644 container-core/src/main/java/com/yahoo/container/config/StatisticsEmitter.java create mode 100644 container-core/src/main/java/com/yahoo/container/config/StatisticsRequestHandler.java create mode 100644 container-core/src/main/java/com/yahoo/container/config/package-info.java create mode 100644 container-core/src/main/java/com/yahoo/container/config/testutil/TestUtil.java create mode 100644 container-core/src/main/java/com/yahoo/container/core/slobrok/SlobrokConfigurator.java create mode 100644 container-core/src/main/java/com/yahoo/container/osgi/AbstractRpcAdaptor.java create mode 100644 container-core/src/main/java/com/yahoo/container/osgi/ContainerRpcAdaptor.java create mode 100644 container-core/src/main/java/com/yahoo/container/osgi/package-info.java (limited to 'container-core') diff --git a/container-core/src/main/java/com/yahoo/container/ConfigHack.java b/container-core/src/main/java/com/yahoo/container/ConfigHack.java new file mode 100644 index 00000000000..55cf208e163 --- /dev/null +++ b/container-core/src/main/java/com/yahoo/container/ConfigHack.java @@ -0,0 +1,31 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.container; + +import com.yahoo.container.config.StatisticsEmitter; + +/** + * Distribution point for QRS specific stuff in a more or less + * container agnostic way. This is only a stepping stone to moving these things + * to Container and other pertinent classes, or simply removing the problems. + * + *

+ * This class should not reach a final release. + * + * @author Steinar Knutsen + */ +public final class ConfigHack { + + private volatile StatisticsEmitter statisticsEmitter = new StatisticsEmitter(); + public static final String TILED_TEMPLATE = "tiled"; + + public static final ConfigHack instance = new ConfigHack(); + + public StatisticsEmitter getStatisticsHandler() { + return statisticsEmitter; + } + + public void setStatisticsEmitter(StatisticsEmitter statisticsEmitter) { + this.statisticsEmitter = statisticsEmitter; + } + +} diff --git a/container-core/src/main/java/com/yahoo/container/Container.java b/container-core/src/main/java/com/yahoo/container/Container.java index c83dd2199ea..f378e7d51bd 100755 --- a/container-core/src/main/java/com/yahoo/container/Container.java +++ b/container-core/src/main/java/com/yahoo/container/Container.java @@ -4,6 +4,8 @@ package com.yahoo.container; import com.yahoo.component.AbstractComponent; import com.yahoo.component.provider.ComponentRegistry; import com.yahoo.container.core.config.BundleLoader; +import com.yahoo.container.osgi.AbstractRpcAdaptor; +import com.yahoo.container.osgi.ContainerRpcAdaptor; import com.yahoo.filedistribution.fileacquirer.FileAcquirer; import com.yahoo.filedistribution.fileacquirer.FileAcquirerFactory; import com.yahoo.jdisc.handler.RequestHandler; @@ -31,23 +33,35 @@ public class Container { private volatile ComponentRegistry serverProviderRegistry; private volatile ComponentRegistry componentRegistry; private volatile FileAcquirer fileAcquirer; + private Osgi osgi; + + private final ContainerRpcAdaptor rpcAdaptor = new ContainerRpcAdaptor(osgi); private volatile BundleLoader bundleLoader; private static Logger logger = Logger.getLogger(Container.class.getName()); - // TODO: Make this final again. + //TODO: Make this final again. private static Container instance = new Container(); public static Container get() { return instance; } public void setOsgi(Osgi osgi) { + this.osgi = osgi; bundleLoader = new BundleLoader(osgi); } public void shutdown() { + com.yahoo.container.Server.get().shutdown(); if (fileAcquirer != null) fileAcquirer.shutdown(); + + rpcAdaptor.shutdown(); + } + + /** Returns the rpc adaptor owned by this */ + public ContainerRpcAdaptor getRpcAdaptor() { + return rpcAdaptor; } //Used to acquire files originating from the application package. @@ -61,13 +75,22 @@ public class Container { return bundleLoader; } - /** - * Hack. For internal use only, will be removed later + /** Hack. For internal use only, will be removed later * * Used by Application to be able to repeatedly set up containers. **/ public static void resetInstance() { instance = new Container(); + com.yahoo.container.Server.resetInstance(); + } + + /** + * Add an application specific RPC adaptor. + * + * @param adaptor the RPC adaptor to add to the Container + */ + public void addOptionalRpcAdaptor(AbstractRpcAdaptor adaptor) { + rpcAdaptor.bindRpcAdaptor(adaptor); } public ComponentRegistry getRequestHandlerRegistry() { @@ -142,5 +165,4 @@ public class Container { } }); } - } diff --git a/container-core/src/main/java/com/yahoo/container/Server.java b/container-core/src/main/java/com/yahoo/container/Server.java index a4dec6de5a2..293e8b4674e 100644 --- a/container-core/src/main/java/com/yahoo/container/Server.java +++ b/container-core/src/main/java/com/yahoo/container/Server.java @@ -3,43 +3,83 @@ package com.yahoo.container; import com.yahoo.config.subscription.ConfigSubscriber; import com.yahoo.container.QrConfig.Rpc; +import com.yahoo.container.osgi.ContainerRpcAdaptor; /** * The http server singleton managing listeners for various ports, * and the threads used to respond to requests on the ports * * @author bratseth - * @deprecated */ @SuppressWarnings("deprecation") -@Deprecated // TODO: Remove this when the last usage og getServerDiscriminator is removed public class Server { //TODO: Make this final again. - private static final Server instance = new Server(); + private static Server instance = new Server(); + private ConfigSubscriber subscriber = new ConfigSubscriber(); + + /** The OSGi container instance of this server */ + private Container container = Container.get(); /** A short string which is different for all the qrserver instances on a given node. */ private String localServerDiscriminator = "qrserver.0"; + /** Creates a new server instance. Not usually useful, use get() to get the current server */ private Server() { } + /** @deprecated returns 0 */ + @Deprecated + public int searchQueriesInFlight() { + return 0; + } + + /** + * An estimate of current number of connections. It is better to be + * inaccurate than to acquire a lock per query fsync. + * + * @return The current number of open search connections + */ + /** @deprecated returns 0 */ + @Deprecated + public int getCurrentConnections() { + return 0; + } + public static Server get() { return instance; } + private void initRpcServer(Rpc rpcConfig) { + if (rpcConfig.enabled()) { + ContainerRpcAdaptor rpcAdaptor = container.getRpcAdaptor(); + rpcAdaptor.listen(rpcConfig.port()); + rpcAdaptor.setSlobrokId(rpcConfig.slobrokId()); + } + } + + /** Ugly hack, see Container.resetInstance */ + static void resetInstance() { + instance = new Server(); + } + + // TODO: Make independent of config public void initialize(QrConfig config) { localServerDiscriminator = config.discriminator(); + container.setupFileAcquirer(config.filedistributor()); + initRpcServer(config.rpc()); } /** * A string unique for this QRS on this server. * * @return a server specific string - * @deprecated do not use */ - @Deprecated public String getServerDiscriminator() { return localServerDiscriminator; } + public void shutdown() { + if (subscriber!=null) subscriber.close(); + } + } diff --git a/container-core/src/main/java/com/yahoo/container/config/StatisticsEmitter.java b/container-core/src/main/java/com/yahoo/container/config/StatisticsEmitter.java new file mode 100644 index 00000000000..0e9d7ec9ce8 --- /dev/null +++ b/container-core/src/main/java/com/yahoo/container/config/StatisticsEmitter.java @@ -0,0 +1,20 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.container.config; + + +import com.yahoo.container.jdisc.HttpRequest; + +/** + * An insulating layer between HTTP and whatever kind of HTTP statistics + * interface is made available. This is an intermediary step towards a + * generalized network layer. + * + * @author Steinar Knutsen + */ +public class StatisticsEmitter { + + public StringBuilder respond(HttpRequest request) { + return new StringBuilder("No statistics available yet."); + } + +} diff --git a/container-core/src/main/java/com/yahoo/container/config/StatisticsRequestHandler.java b/container-core/src/main/java/com/yahoo/container/config/StatisticsRequestHandler.java new file mode 100644 index 00000000000..e0b6392b64a --- /dev/null +++ b/container-core/src/main/java/com/yahoo/container/config/StatisticsRequestHandler.java @@ -0,0 +1,55 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.container.config; + +import com.google.inject.Inject; +import com.yahoo.jdisc.Metric; +import com.yahoo.container.ConfigHack; +import com.yahoo.container.jdisc.HttpRequest; +import com.yahoo.container.jdisc.HttpResponse; +import com.yahoo.container.jdisc.ThreadedHttpRequestHandler; +import com.yahoo.container.logging.AccessLog; +import com.yahoo.text.Utf8; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.util.concurrent.Executor; + +/** + * Handler of statistics http requests. Temporary hack as a step towards a more + * general network interface. + * + * @author Steinar Knutsen + * @author Einar M R Rosenvinge + */ +public class StatisticsRequestHandler extends ThreadedHttpRequestHandler { + + @Inject + public StatisticsRequestHandler(Executor executor, Metric metric) { + super(executor, metric); + } + + @Override + public HttpResponse handle(HttpRequest request) { + return new StatisticsResponse(ConfigHack.instance.getStatisticsHandler().respond(request)); + } + + protected static class StatisticsResponse extends HttpResponse { + + private final StringBuilder string; + + private StatisticsResponse(StringBuilder stringBuilder) { + super(com.yahoo.jdisc.http.HttpResponse.Status.OK); + this.string = stringBuilder; + } + + @Override + public void render(OutputStream stream) throws IOException { + Writer osWriter = new OutputStreamWriter(stream, Utf8.getCharset()); + osWriter.write(string.toString()); + osWriter.flush(); + osWriter.close(); + } + } +} diff --git a/container-core/src/main/java/com/yahoo/container/config/package-info.java b/container-core/src/main/java/com/yahoo/container/config/package-info.java new file mode 100644 index 00000000000..b8e45b636dc --- /dev/null +++ b/container-core/src/main/java/com/yahoo/container/config/package-info.java @@ -0,0 +1,5 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +@ExportPackage +package com.yahoo.container.config; + +import com.yahoo.osgi.annotation.ExportPackage; diff --git a/container-core/src/main/java/com/yahoo/container/config/testutil/TestUtil.java b/container-core/src/main/java/com/yahoo/container/config/testutil/TestUtil.java new file mode 100644 index 00000000000..dbf8be8e1dc --- /dev/null +++ b/container-core/src/main/java/com/yahoo/container/config/testutil/TestUtil.java @@ -0,0 +1,85 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.container.config.testutil; + +import com.yahoo.container.core.config.HandlersConfigurerDi; + +import java.io.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author gjoranv + */ +public class TestUtil { + + public static void createComponentsConfig(String configFile, + String componentsFile, + String componentType) throws IOException { + createComponentsConfig(configFile, componentsFile, componentType, false); + } + + /** + * Copies the component ids from another config, e.g. 'handlers' to a 'components' array in a new components file, + * to avoid a manually written 'components' file for tests where the bundle spec is given by the component id. + * @param configFile Full path to the original config file, e.g. 'handlers' + * @param componentsFile Full path to the new 'components' file + * @param componentType The type of component, e.g. 'handler' + * @param append 'true' will append to an already existing 'componentsFile' + */ + public static void createComponentsConfig(String configFile, + String componentsFile, + String componentType, + boolean append) throws IOException { + StringBuilder buf = new StringBuilder(); + String line; + int i = 0; + if (append) { + final Pattern p = Pattern.compile("^[a-z]+" + "\\[\\d+\\]\\.id (.+)"); + BufferedReader reader = new BufferedReader(new InputStreamReader( + new FileInputStream(new File(componentsFile)), "UTF-8")); + while ((line = reader.readLine()) != null) { + Matcher m = p.matcher(line); + if (m.matches() && !m.group(1).equals(HandlersConfigurerDi.RegistriesHack.class.getName())) { + buf.append("components[").append(i).append("].id ").append(m.group(1)).append("\n"); + i++; + } + } + reader.close(); + } + BufferedReader reader = new BufferedReader(new InputStreamReader( + new FileInputStream(new File(configFile)), "UTF-8")); + final Pattern component = Pattern.compile("^" + componentType + "\\[\\d+\\]\\.id (.+)"); + while ((line = reader.readLine()) != null) { + Matcher m = component.matcher(line); + if (m.matches()) { + buf.append("components[").append(i).append("].id ").append(m.group(1)).append("\n"); + i++; + } + } + buf.append("components[").append(i).append("].id "). + append(HandlersConfigurerDi.RegistriesHack.class.getName()).append("\n"); + i++; + reader.close(); + buf.insert(0, "components["+i+"]\n"); + + Writer writer = new OutputStreamWriter(new FileOutputStream(new File(componentsFile)), "UTF-8"); + writer.write(buf.toString()); + writer.flush(); + writer.close(); + } + + /** + * Copies src file to dst file. If the dst file does not exist, it is created. + */ + public static void copyFile(String srcName, File dstFile) throws IOException { + InputStream src = new FileInputStream(new File(srcName)); + OutputStream dst = new FileOutputStream(dstFile); + byte[] buf = new byte[1024]; + int len; + while ((len = src.read(buf)) > 0) { + dst.write(buf, 0, len); + } + src.close(); + dst.close(); + } +} diff --git a/container-core/src/main/java/com/yahoo/container/core/slobrok/SlobrokConfigurator.java b/container-core/src/main/java/com/yahoo/container/core/slobrok/SlobrokConfigurator.java new file mode 100644 index 00000000000..9472fa07bb5 --- /dev/null +++ b/container-core/src/main/java/com/yahoo/container/core/slobrok/SlobrokConfigurator.java @@ -0,0 +1,26 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.container.core.slobrok; + +import com.yahoo.cloud.config.SlobroksConfig; +import com.yahoo.cloud.config.SlobroksConfig.Slobrok; +import com.yahoo.container.Container; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * Configures which slobrok nodes the container should register with. + * @author Tony Vaagenes + */ +public class SlobrokConfigurator { + public SlobrokConfigurator(SlobroksConfig config) { + Container.get().getRpcAdaptor().registerInSlobrok( + connectionSpecs(config.slobrok())); + } + + private static List connectionSpecs(List slobroks) { + return slobroks.stream(). + map(Slobrok::connectionspec). + collect(Collectors.toList()); + } +} diff --git a/container-core/src/main/java/com/yahoo/container/osgi/AbstractRpcAdaptor.java b/container-core/src/main/java/com/yahoo/container/osgi/AbstractRpcAdaptor.java new file mode 100644 index 00000000000..9486fe367f9 --- /dev/null +++ b/container-core/src/main/java/com/yahoo/container/osgi/AbstractRpcAdaptor.java @@ -0,0 +1,15 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.container.osgi; + +import com.yahoo.jrt.Supervisor; + +/** + * Helper class for optional RPC adaptors in the Container. + * + * @author Steinar Knutsen + */ +public abstract class AbstractRpcAdaptor { + + public abstract void bindCommands(Supervisor supervisor); + +} diff --git a/container-core/src/main/java/com/yahoo/container/osgi/ContainerRpcAdaptor.java b/container-core/src/main/java/com/yahoo/container/osgi/ContainerRpcAdaptor.java new file mode 100644 index 00000000000..7db7d4032d5 --- /dev/null +++ b/container-core/src/main/java/com/yahoo/container/osgi/ContainerRpcAdaptor.java @@ -0,0 +1,129 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.container.osgi; + +import com.yahoo.jrt.Acceptor; +import com.yahoo.jrt.ErrorCode; +import com.yahoo.jrt.ListenFailedException; +import com.yahoo.jrt.Method; +import com.yahoo.jrt.Request; +import com.yahoo.jrt.Spec; +import com.yahoo.jrt.StringValue; +import com.yahoo.jrt.Supervisor; +import com.yahoo.jrt.Transport; +import com.yahoo.jrt.slobrok.api.Register; +import com.yahoo.jrt.slobrok.api.SlobrokList; +import com.yahoo.net.HostName; +import com.yahoo.log.LogLevel; +import com.yahoo.osgi.Osgi; +import com.yahoo.yolean.Exceptions; +import org.osgi.framework.Bundle; + +import java.util.List; +import java.util.Optional; +import java.util.logging.Logger; + +/** + * An rpc adaptor to container Osgi commands. + * + * @author bratseth + */ +public class ContainerRpcAdaptor extends AbstractRpcAdaptor { + + private static final Logger log = Logger.getLogger(ContainerRpcAdaptor.class.getName()); + + private Acceptor acceptor; + private final Supervisor supervisor; + + private final Osgi osgi; + private final String hostname; + + private Optional slobrokId = Optional.empty(); + private Optional slobrokRegistrator = Optional.empty(); + + public ContainerRpcAdaptor(Osgi osgi) { + this.osgi = osgi; + this.supervisor = new Supervisor(new Transport()); + this.hostname = HostName.getLocalhost(); + + bindCommands(supervisor); + } + + public void list(Request request) { + try { + StringBuilder buffer=new StringBuilder("Installed bundles:"); + for (Bundle bundle : osgi.getBundles()) { + if (bundle.getSymbolicName().equals("system.bundle")) continue; + buffer.append("\n"); + buffer.append(bundle.getSymbolicName()); + buffer.append(" ("); + buffer.append(bundle.getLocation()); + buffer.append(")"); + } + request.returnValues().add(new StringValue(buffer.toString())); + } + catch (Exception e) { + request.setError(ErrorCode.METHOD_FAILED,Exceptions.toMessageString(e)); + } + } + + public void bindCommands(Supervisor supervisor) { + supervisor.addMethod(new Method("list","","s",this,"list")); + } + + public synchronized void listen(int port) { + Spec spec = new Spec(port); + try { + acceptor = supervisor.listen(spec); + log.log(LogLevel.DEBUG, "Added new rpc server listening at" + " port '" + port + "'."); + } catch (ListenFailedException e) { + throw new RuntimeException("Could not create rpc server listening on " + spec, e); + } + } + + public synchronized void setSlobrokId(String slobrokId) { + this.slobrokId = Optional.of(slobrokId); + } + + public synchronized void registerInSlobrok(List slobrokConnectionSpecs) { + shutdownSlobrokRegistrator(); + + if (slobrokConnectionSpecs.isEmpty()) { + return; + } + + if (!slobrokId.isPresent()) { + throw new AssertionError("Slobrok id must be set first"); + } + + SlobrokList slobrokList = new SlobrokList(); + slobrokList.setup(slobrokConnectionSpecs.stream().toArray(String[]::new)); + + Spec mySpec = new Spec(hostname, acceptor.port()); + + Register register = new Register(supervisor, slobrokList, mySpec); + register.registerName(slobrokId.get()); + slobrokRegistrator = Optional.of(register); + + log.log(LogLevel.INFO, "Registered name '" + slobrokId.get() + "' at " + mySpec + " with: " + slobrokList); + } + + private synchronized void shutdownSlobrokRegistrator() { + slobrokRegistrator.ifPresent(Register::shutdown); + slobrokRegistrator = Optional.empty(); + } + + public synchronized void shutdown() { + shutdownSlobrokRegistrator(); + + if (acceptor != null) { + acceptor.shutdown().join(); + } + supervisor.transport().shutdown().join(); + } + + + public synchronized void bindRpcAdaptor(AbstractRpcAdaptor adaptor) { + adaptor.bindCommands(supervisor); + } + +} diff --git a/container-core/src/main/java/com/yahoo/container/osgi/package-info.java b/container-core/src/main/java/com/yahoo/container/osgi/package-info.java new file mode 100644 index 00000000000..0768489a767 --- /dev/null +++ b/container-core/src/main/java/com/yahoo/container/osgi/package-info.java @@ -0,0 +1,5 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +@ExportPackage +package com.yahoo.container.osgi; + +import com.yahoo.osgi.annotation.ExportPackage; diff --git a/container-core/src/main/java/com/yahoo/osgi/OsgiImpl.java b/container-core/src/main/java/com/yahoo/osgi/OsgiImpl.java index 2e37a278387..d9ccd5c590f 100644 --- a/container-core/src/main/java/com/yahoo/osgi/OsgiImpl.java +++ b/container-core/src/main/java/com/yahoo/osgi/OsgiImpl.java @@ -16,6 +16,8 @@ import java.util.logging.Logger; */ public class OsgiImpl implements Osgi { + private static final Logger log = Logger.getLogger(OsgiImpl.class.getName()); + private final OsgiFramework jdiscOsgi; public OsgiImpl(OsgiFramework jdiscOsgi) { -- cgit v1.2.3