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

org.graylog2.datanode.DataNodeServiceImpl Maven / Gradle / Ivy

There is a newer version: 6.1.4
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.datanode;

import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import jakarta.inject.Inject;
import org.graylog2.cluster.NodeNotFoundException;
import org.graylog2.cluster.nodes.DataNodeDto;
import org.graylog2.cluster.nodes.DataNodeStatus;
import org.graylog2.cluster.nodes.NodeService;
import org.graylog2.events.ClusterEventBus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DataNodeServiceImpl implements DataNodeService {

    private static final Logger LOG = LoggerFactory.getLogger(DataNodeServiceImpl.class);

    private final ClusterEventBus clusterEventBus;
    private final NodeService nodeService;

    @Inject
    public DataNodeServiceImpl(ClusterEventBus clusterEventBus, NodeService nodeService, EventBus eventBus) {
        this.clusterEventBus = clusterEventBus;
        this.nodeService = nodeService;
        eventBus.register(this);
    }

    @Override
    public DataNodeDto removeNode(String nodeId) throws NodeNotFoundException {
        final DataNodeDto node = nodeService.byNodeId(nodeId);
        if (node.getDataNodeStatus() != DataNodeStatus.AVAILABLE) {
            throw new IllegalArgumentException("Only running data nodes can be removed from the cluster.");
        }
        if (nodeService.allActive().values().stream()
                .filter(n -> n.getDataNodeStatus() == DataNodeStatus.AVAILABLE && n.getActionQueue() == null)
                .count() <= 1) {
            throw new IllegalArgumentException("Cannot remove last data node in the cluster.");
        }
        DataNodeLifecycleTrigger trigger = DataNodeLifecycleTrigger.REMOVE;
        DataNodeStatus lockingStatus = DataNodeStatus.REMOVING;
        addToQueue(node, trigger, lockingStatus);
        return node;
    }

    @Override
    public DataNodeDto resetNode(String nodeId) throws NodeNotFoundException {
        final DataNodeDto node = nodeService.byNodeId(nodeId);
        if (node.getDataNodeStatus() != DataNodeStatus.REMOVED) {
            throw new IllegalArgumentException("Only previously removed data nodes can rejoin the cluster.");
        }
        DataNodeLifecycleEvent e = DataNodeLifecycleEvent.create(node.getNodeId(), DataNodeLifecycleTrigger.RESET);
        clusterEventBus.post(e);
        return node;
    }

    @Override
    public DataNodeDto stopNode(String nodeId) throws NodeNotFoundException {
        final DataNodeDto node = nodeService.byNodeId(nodeId);
        if (node.getDataNodeStatus() != DataNodeStatus.AVAILABLE) {
            throw new IllegalArgumentException("Only running data nodes can be stopped.");
        }
        DataNodeLifecycleEvent e = DataNodeLifecycleEvent.create(node.getNodeId(), DataNodeLifecycleTrigger.STOP);
        clusterEventBus.post(e);
        return node;
    }

    @Override
    public DataNodeDto startNode(String nodeId) throws NodeNotFoundException {
        final DataNodeDto node = nodeService.byNodeId(nodeId);
        if (node.getDataNodeStatus() != DataNodeStatus.UNAVAILABLE) {
            throw new IllegalArgumentException("Only stopped data nodes can be started.");
        }
        DataNodeLifecycleEvent e = DataNodeLifecycleEvent.create(node.getNodeId(), DataNodeLifecycleTrigger.START);
        clusterEventBus.post(e);
        return node;
    }

    private void addToQueue(DataNodeDto node, DataNodeLifecycleTrigger trigger, DataNodeStatus lockingStatus) {
        nodeService.update(node.toBuilder()
                .setActionQueue(trigger)
                .build());
        if (!otherNodeHasStatus(node.getNodeId(), lockingStatus, trigger)) { // post event to bus if no other node is currently performing or waiting
            DataNodeLifecycleEvent e = DataNodeLifecycleEvent.create(node.getNodeId(), trigger);
            clusterEventBus.post(e);
        }
    }

    private boolean otherNodeHasStatus(String nodeId, DataNodeStatus status, DataNodeLifecycleTrigger trigger) {
        return nodeService.allActive().values().stream()
                .anyMatch(n ->
                        !n.getNodeId().equals(nodeId) &&
                                (n.getDataNodeStatus() == status || n.getActionQueue() == trigger)
                );
    }

    @Subscribe
    @SuppressWarnings("unused")
    public void handleDataNodeLifeCycleEvent(DataNodeLifecycleEvent event) {
        switch (event.trigger()) {
            case REMOVED -> handleNextNode(DataNodeLifecycleTrigger.REMOVE);
            case STOPPED -> handleNextNode(DataNodeLifecycleTrigger.STOP);
        }
    }

    private void handleNextNode(DataNodeLifecycleTrigger trigger) {
        nodeService.allActive().values().stream()
                .filter(node -> node.getActionQueue() == trigger)
                .findFirst().ifPresent(node -> {
                    clusterEventBus.post(DataNodeLifecycleEvent.create(node.getNodeId(), trigger));
                });
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy