All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.graylog2.buffers.Buffers Maven / Gradle / Ivy

There is a newer version: 6.0.2
Show newest version
/*
 * Copyright (C) 2020 Graylog, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the Server Side Public License, version 1,
 * as published by MongoDB, Inc.
 *
 * This program 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
 * Server Side Public License for more details.
 *
 * You should have received a copy of the Server Side Public License
 * along with this program. If not, see
 * .
 */
package org.graylog2.buffers;

import com.github.rholder.retry.RetryException;
import com.github.rholder.retry.Retryer;
import com.github.rholder.retry.RetryerBuilder;
import com.github.rholder.retry.StopStrategies;
import com.github.rholder.retry.WaitStrategies;
import com.google.common.base.Predicates;
import org.graylog2.plugin.buffers.EventBuffer;
import org.graylog2.plugin.buffers.InputBuffer;
import org.graylog2.shared.buffers.ProcessBuffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Inject;
import java.util.EnumSet;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static org.graylog2.buffers.Buffers.Type.INPUT;
import static org.graylog2.buffers.Buffers.Type.OUTPUT;
import static org.graylog2.buffers.Buffers.Type.PROCESS;

public class Buffers {
    public enum Type {
        INPUT,
        PROCESS,
        OUTPUT,
    }

    private static final Logger LOG = LoggerFactory.getLogger(Buffers.class);
    private static final long DEFAULT_MAX_WAIT = 30L;

    private final InputBuffer inputBuffer;
    private final ProcessBuffer processBuffer;
    private final OutputBuffer outputBuffer;

    @Inject
    public Buffers(InputBuffer inputBuffer, final ProcessBuffer processBuffer, final OutputBuffer outputBuffer) {
        this.inputBuffer = inputBuffer;
        this.processBuffer = processBuffer;
        this.outputBuffer = outputBuffer;
    }

    /**
     * @deprecated Use {@link #waitForEmptyBuffers(EnumSet)} instead
     */
    @Deprecated
    public void waitForEmptyBuffers() {
        waitForEmptyBuffers(EnumSet.of(PROCESS, OUTPUT));
    }

    /**
     * Wait until the buffers of the given types have been drained or abort after 30 seconds
     */
    public void waitForEmptyBuffers(EnumSet bufferTypes) {
        waitForEmptyBuffers(bufferTypes, DEFAULT_MAX_WAIT, TimeUnit.SECONDS);
    }

    /**
     * @deprecated Use {@link #waitForEmptyBuffers(EnumSet, long, TimeUnit)} instead
     */
    @Deprecated
    public void waitForEmptyBuffers(final long maxWait, final TimeUnit timeUnit) {
        waitForEmptyBuffers(EnumSet.of(PROCESS, OUTPUT), maxWait, timeUnit);
    }

    /**
     * Wait until the buffers of the given types have been drained or abort after a given maximum waiting time
     */
    public void waitForEmptyBuffers(EnumSet bufferTypes, final long maxWait, final TimeUnit timeUnit) {
        if (bufferTypes.isEmpty()) {
            return;
        }
        LOG.info("Waiting until {} buffers are empty.", bufferTypes);

        final Map buffersByTypes = buffersByTypes(bufferTypes);

        final Retryer retryer = RetryerBuilder.newBuilder()
                .retryIfResult(Predicates.not(Predicates.equalTo(Boolean.TRUE)))
                .withWaitStrategy(WaitStrategies.fixedWait(1, TimeUnit.SECONDS))
                .withStopStrategy(StopStrategies.stopAfterDelay(maxWait, timeUnit))
                .build();

        try {
            retryer.call(() -> {
                if (buffersByTypes.values().stream().allMatch(EventBuffer::isEmpty)) {
                    return true;
                } else {
                    LOG.info("Waiting for buffers to drain. ({})", getUsageStats(buffersByTypes));
                }
                return false;
            });
        } catch (RetryException e) {
            LOG.info("Buffers not empty after {} {}. Giving up.", maxWait, timeUnit.name().toLowerCase(Locale.ENGLISH));
            return;
        } catch (ExecutionException e) {
            LOG.error("Error while waiting for empty buffers.", e);
            return;
        }

        LOG.info("All buffers are empty. Continuing.");
    }

    // e.g. 123i/432p/545o
    private String getUsageStats(Map buffersByTypes) {
        return buffersByTypes.entrySet().stream()
                .map(e -> e.getValue().getUsage() + e.getKey().name().substring(0, 1).toLowerCase(Locale.ENGLISH))
                .collect(Collectors.joining("/"));
    }

    private Map buffersByTypes(EnumSet bufferTypes) {
        Map bufferMap = new LinkedHashMap<>();
        if (bufferTypes.contains(INPUT)) {
            bufferMap.put(INPUT, inputBuffer);
        }
        if (bufferTypes.contains(PROCESS)) {
            bufferMap.put(PROCESS, processBuffer);
        }
        if (bufferTypes.contains(OUTPUT)) {
            bufferMap.put(OUTPUT, outputBuffer);
        }
        return bufferMap;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy