Search in sources :

Example 1 with MessageQueue

use of com.cinchapi.concourse.server.plugin.io.MessageQueue in project concourse by cinchapi.

the class BackgroundThreadTest method testBackgroundExecutorHasCorrectInformation.

@Test
public void testBackgroundExecutorHasCorrectInformation() throws InterruptedException {
    InterProcessCommunication outgoing = new MessageQueue();
    ConcurrentMap<AccessToken, RemoteMethodResponse> responses = Maps.newConcurrentMap();
    BackgroundExecutor executor = PluginExecutors.newCachedBackgroundExecutor(outgoing, responses);
    CountDownLatch latch = new CountDownLatch(1);
    final AtomicBoolean passed = new AtomicBoolean(true);
    executor.execute(Random.getSimpleString(), () -> {
        InterProcessCommunication myOutgoing = ((BackgroundThread) Thread.currentThread()).outgoing();
        ConcurrentMap<AccessToken, RemoteMethodResponse> myResponses = ((BackgroundThread) Thread.currentThread()).responses();
        try {
            Assert.assertSame(outgoing, myOutgoing);
            Assert.assertSame(responses, myResponses);
        } catch (AssertionError e) {
            passed.set(false);
            e.printStackTrace();
        }
        latch.countDown();
    });
    latch.await();
    Assert.assertTrue(passed.get());
}
Also used : AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) MessageQueue(com.cinchapi.concourse.server.plugin.io.MessageQueue) AccessToken(com.cinchapi.concourse.thrift.AccessToken) InterProcessCommunication(com.cinchapi.concourse.server.plugin.io.InterProcessCommunication) CountDownLatch(java.util.concurrent.CountDownLatch) Test(org.junit.Test)

Example 2 with MessageQueue

use of com.cinchapi.concourse.server.plugin.io.MessageQueue in project concourse by cinchapi.

the class RealTimePlugin method run.

@Override
public final void run() {
    Reflection.call(this, "setReadyState");
    // For a RealTimePlugin, the first fromServer message contains the
    // address for the stream channel
    ByteBuffer data = fromServer.read();
    RemoteMessage message = serializer.deserialize(data);
    if (message.type() == RemoteMessage.Type.ATTRIBUTE) {
        RemoteAttributeExchange attribute = (RemoteAttributeExchange) message;
        if (attribute.key().equalsIgnoreCase(STREAM_ATTRIBUTE)) {
            log.debug("Listening for streamed packets at {}", attribute.value());
            @SuppressWarnings("resource") final InterProcessCommunication stream = new MessageQueue(attribute.value());
            // Create a separate event loop to process Packets of writes
            // that come from the server.
            Thread loop = new Thread(() -> {
                ByteBuffer bytes = null;
                while ((bytes = stream.read()) != null) {
                    final Packet packet = serializer.deserialize(bytes);
                    // Each packet should be processed in a separate
                    // worker thread
                    workers.execute(() -> {
                        log.debug("Received packet from Concourse Server: {}", packet);
                        handlePacket(packet);
                    });
                }
            });
            loop.setDaemon(true);
            loop.start();
            // Start normal plugin operations
            super.run();
        } else {
            throw new IllegalStateException("Unsupported attribute " + attribute);
        }
    } else {
        throw new IllegalStateException();
    }
}
Also used : MessageQueue(com.cinchapi.concourse.server.plugin.io.MessageQueue) InterProcessCommunication(com.cinchapi.concourse.server.plugin.io.InterProcessCommunication) ByteBuffer(java.nio.ByteBuffer)

Example 3 with MessageQueue

use of com.cinchapi.concourse.server.plugin.io.MessageQueue in project concourse by cinchapi.

the class PluginManager method startStreamToPlugin.

/**
 * Create a {@link InterProcessCommunication} segment over which the
 * PluginManager will stream real-time {@link Packet packets} that contain
 * writes.
 *
 * @param id the plugin id
 */
private void startStreamToPlugin(String id) {
    String tempDir = getPluginTempDirectory(id);
    String streamFile = FileSystem.tempFile(tempDir, "RT-", ".shm");
    Logger.debug("Creating real-time stream for {} at {}", id, streamFile);
    InterProcessCommunication stream = new MessageQueue(streamFile);
    Logger.debug("Shared memory for real-time stream of '{} is located at " + "'{}", id, streamFile);
    RemoteAttributeExchange attribute = new RemoteAttributeExchange("stream", streamFile);
    InterProcessCommunication fromServer = (InterProcessCommunication) registry.get(id, RegistryData.FROM_SERVER);
    ByteBuffer buffer = serializer.serialize(attribute);
    fromServer.write(buffer);
    streams.add(stream);
}
Also used : MessageQueue(com.cinchapi.concourse.server.plugin.io.MessageQueue) InterProcessCommunication(com.cinchapi.concourse.server.plugin.io.InterProcessCommunication) ByteBuffer(java.nio.ByteBuffer)

Example 4 with MessageQueue

use of com.cinchapi.concourse.server.plugin.io.MessageQueue in project concourse by cinchapi.

the class PluginManager method launch.

/**
 * <p>
 * This method is called from {@link #activate(String, ActivationType)} once
 * any pre-launch checks have successfully completed.
 * </p>
 * <p>
 * Launch the {@code plugin} from {@code dist} within a separate JVM
 * configured with the specified {@code classpath} and the values from the
 * {@code prefs} file.
 * </p>
 *
 * @param bundle the bundle directory that contains the plugin libraries
 * @param prefs the {@link Path} to the config file
 * @param plugin the class to launch in a separate JVM
 * @param classpath the classpath for the separate JVM
 */
private void launch(final String bundle, final Path prefs, final Class<?> plugin, final List<String> classpath) {
    // Write an arbitrary main class that'll construct the Plugin and run it
    String launchClass = plugin.getName();
    String launchClassShort = plugin.getSimpleName();
    String processName = "Concourse_" + launchClassShort;
    String tempDir = getPluginTempDirectory(launchClass);
    String fromServer = FileSystem.tempFile(tempDir, "FS-", ".shm");
    String fromPlugin = FileSystem.tempFile(tempDir, "FP-", ".shm");
    String source = pluginLaunchClassTemplate.replace("INSERT_PROCESS_NAME", processName).replace("INSERT_IMPORT_STATEMENT", launchClass).replace("INSERT_FROM_SERVER", fromServer).replace("INSERT_FROM_PLUGIN", fromPlugin).replace("INSERT_CLASS_NAME", launchClassShort);
    // Create an external JavaApp in which the Plugin will run. Get the
    // plugin config to size the JVM properly.
    PluginConfiguration config = Reflection.newInstance(StandardPluginConfiguration.class, prefs);
    Logger.info("Configuring plugin '{}' from bundle '{}' with " + "preferences located in {}", plugin, bundle, prefs);
    long heapSize = config.getHeapSize() / BYTES_PER_MB;
    for (String alias : config.getAliases()) {
        if (!aliases.containsKey(alias) && !ambiguous.contains(alias)) {
            aliases.put(alias, plugin.getName());
            Logger.info("Registering '{}' as an alias for {}", alias, plugin);
        } else {
            aliases.remove(alias);
            ambiguous.add(alias);
            Logger.info("Alias '{}' can't be used because it is " + "associated with multiple plugins", alias);
        }
    }
    String pluginHome = home + File.separator + bundle;
    String serviceToken = BaseEncoding.base32Hex().encode(server.newServiceToken().bufferForData().array());
    ArrayList<String> options = new ArrayList<String>();
    if (config.getRemoteDebuggerEnabled()) {
        options.add("-Xdebug");
        options.add("-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=" + config.getRemoteDebuggerPort());
    }
    options.add("-Xms" + heapSize + "M");
    options.add("-Xmx" + heapSize + "M");
    options.add("-D" + Plugin.PLUGIN_HOME_JVM_PROPERTY + "=" + pluginHome);
    options.add("-D" + Plugin.PLUGIN_SERVICE_TOKEN_JVM_PROPERTY + "=" + serviceToken);
    String cp = StringUtils.join(classpath, JavaApp.CLASSPATH_SEPARATOR);
    JavaApp app = new JavaApp(cp, source, options);
    app.run();
    if (app.isRunning()) {
        Logger.info("Starting plugin '{}' from bundle '{}'", launchClass, bundle);
    }
    app.onPrematureShutdown((out, err) -> {
        try {
            List<String> outLines = CharStreams.readLines(new InputStreamReader(out));
            List<String> errLines = CharStreams.readLines(new InputStreamReader(err));
            Logger.warn("Plugin '{}' unexpectedly crashed. ", plugin);
            Logger.warn("Standard Output for {}: {}", plugin, StringUtils.join(outLines, System.lineSeparator()));
            Logger.warn("Standard Error for {}: {}", plugin, StringUtils.join(errLines, System.lineSeparator()));
            Logger.warn("Restarting {} now...", plugin);
            Iterator<Entry<String, String>> it = aliases.entrySet().iterator();
            while (it.hasNext()) {
                Entry<String, String> entry = it.next();
                if (entry.getValue().equals(plugin.getName())) {
                    it.remove();
                }
            }
            // TODO: it would be nice to just restart the same JavaApp
            // instance (e.g. app.restart();)
            launch(bundle, prefs, plugin, classpath);
        } catch (IOException e) {
            throw CheckedExceptions.wrapAsRuntimeException(e);
        }
    });
    // Ensure that the Plugin is ready to run before adding it to the
    // registry to avoid premature invocations
    Path readyCheck = com.cinchapi.common.io.Files.getHashedFilePath(serviceToken);
    try {
        while (!Files.deleteIfExists(readyCheck)) {
            Thread.sleep(1000);
            continue;
        }
        Logger.info("Plugin '{}' is ready", plugin);
    } catch (IOException | InterruptedException e) {
    }
    // Store metadata about the Plugin
    String id = launchClass;
    registry.put(id, RegistryData.PLUGIN_BUNDLE, bundle);
    registry.put(id, RegistryData.FROM_SERVER, new MessageQueue(fromServer));
    registry.put(id, RegistryData.FROM_PLUGIN, new MessageQueue(fromPlugin));
    registry.put(id, RegistryData.STATUS, PluginStatus.ACTIVE);
    registry.put(id, RegistryData.APP_INSTANCE, app);
    registry.put(id, RegistryData.FROM_PLUGIN_RESPONSES, Maps.<AccessToken, RemoteMethodResponse>newConcurrentMap());
    Logger.debug("Shared memory for server-based communication to '{} is " + "located at '{}", id, fromServer);
    Logger.debug("Shared memory for plugin-based communication from '{} is " + "located at '{}", id, fromPlugin);
}
Also used : JavaApp(com.cinchapi.concourse.server.io.process.JavaApp) Path(java.nio.file.Path) InputStreamReader(java.io.InputStreamReader) ArrayList(java.util.ArrayList) IOException(java.io.IOException) Entry(java.util.Map.Entry) MessageQueue(com.cinchapi.concourse.server.plugin.io.MessageQueue)

Example 5 with MessageQueue

use of com.cinchapi.concourse.server.plugin.io.MessageQueue in project concourse by cinchapi.

the class BackgroundThreadTest method testBackgroundExecutorSetsEnvironmentCorrectly.

@Test
public void testBackgroundExecutorSetsEnvironmentCorrectly() throws InterruptedException {
    InterProcessCommunication outgoing = new MessageQueue();
    ConcurrentMap<AccessToken, RemoteMethodResponse> responses = Maps.newConcurrentMap();
    String environment1 = Random.getSimpleString();
    String environment2 = Random.getSimpleString();
    MockConcourseRuntime runtime = new MockConcourseRuntime();
    BackgroundExecutor executor = PluginExecutors.newCachedBackgroundExecutor(outgoing, responses);
    CountDownLatch latch = new CountDownLatch(2);
    final AtomicBoolean passed = new AtomicBoolean(true);
    executor.execute(environment1, () -> {
        try {
            Assert.assertEquals(environment1, runtime.environment());
            latch.countDown();
        } catch (AssertionError e) {
            passed.set(false);
            e.printStackTrace();
        }
    });
    executor.execute(environment2, () -> {
        try {
            Assert.assertEquals(environment2, runtime.environment());
            latch.countDown();
        } catch (AssertionError e) {
            passed.set(false);
            e.printStackTrace();
        }
    });
    latch.await();
    Assert.assertTrue(passed.get());
}
Also used : AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) MessageQueue(com.cinchapi.concourse.server.plugin.io.MessageQueue) AccessToken(com.cinchapi.concourse.thrift.AccessToken) InterProcessCommunication(com.cinchapi.concourse.server.plugin.io.InterProcessCommunication) CountDownLatch(java.util.concurrent.CountDownLatch) Test(org.junit.Test)

Aggregations

MessageQueue (com.cinchapi.concourse.server.plugin.io.MessageQueue)5 InterProcessCommunication (com.cinchapi.concourse.server.plugin.io.InterProcessCommunication)4 AccessToken (com.cinchapi.concourse.thrift.AccessToken)2 ByteBuffer (java.nio.ByteBuffer)2 CountDownLatch (java.util.concurrent.CountDownLatch)2 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)2 Test (org.junit.Test)2 JavaApp (com.cinchapi.concourse.server.io.process.JavaApp)1 IOException (java.io.IOException)1 InputStreamReader (java.io.InputStreamReader)1 Path (java.nio.file.Path)1 ArrayList (java.util.ArrayList)1 Entry (java.util.Map.Entry)1