io.druid.client.BrokerServerView.java Source code

Java tutorial

Introduction

Here is the source code for io.druid.client.BrokerServerView.java

Source

/*
 * Druid - a distributed column store.
 * Copyright 2012 - 2015 Metamarkets Group Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.druid.client;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Ordering;
import com.google.inject.Inject;
import com.metamx.common.logger.Logger;
import com.metamx.emitter.service.ServiceEmitter;
import com.metamx.http.client.HttpClient;
import io.druid.client.selector.QueryableDruidServer;
import io.druid.client.selector.ServerSelector;
import io.druid.client.selector.TierSelectorStrategy;
import io.druid.concurrent.Execs;
import io.druid.guice.annotations.Client;
import io.druid.guice.annotations.Smile;
import io.druid.query.DataSource;
import io.druid.query.QueryRunner;
import io.druid.query.QueryToolChestWarehouse;
import io.druid.query.QueryWatcher;
import io.druid.server.coordination.DruidServerMetadata;
import io.druid.timeline.DataSegment;
import io.druid.timeline.TimelineLookup;
import io.druid.timeline.VersionedIntervalTimeline;
import io.druid.timeline.partition.PartitionChunk;

import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;

/**
 */
public class BrokerServerView implements TimelineServerView {
    private static final Logger log = new Logger(BrokerServerView.class);

    private final Object lock = new Object();

    private final ConcurrentMap<String, QueryableDruidServer> clients;
    private final Map<String, ServerSelector> selectors;
    private final Map<String, VersionedIntervalTimeline<String, ServerSelector>> timelines;

    private final QueryToolChestWarehouse warehouse;
    private final QueryWatcher queryWatcher;
    private final ObjectMapper smileMapper;
    private final HttpClient httpClient;
    private final ServerInventoryView baseView;
    private final TierSelectorStrategy tierSelectorStrategy;
    private final ServiceEmitter emitter;

    private volatile boolean initialized = false;

    @Inject
    public BrokerServerView(QueryToolChestWarehouse warehouse, QueryWatcher queryWatcher,
            @Smile ObjectMapper smileMapper, @Client HttpClient httpClient, ServerInventoryView baseView,
            TierSelectorStrategy tierSelectorStrategy, ServiceEmitter emitter) {
        this.warehouse = warehouse;
        this.queryWatcher = queryWatcher;
        this.smileMapper = smileMapper;
        this.httpClient = httpClient;
        this.baseView = baseView;
        this.tierSelectorStrategy = tierSelectorStrategy;
        this.emitter = emitter;

        this.clients = Maps.newConcurrentMap();
        this.selectors = Maps.newHashMap();
        this.timelines = Maps.newHashMap();

        ExecutorService exec = Execs.singleThreaded("BrokerServerView-%s");
        baseView.registerSegmentCallback(exec, new ServerView.SegmentCallback() {
            @Override
            public ServerView.CallbackAction segmentAdded(DruidServerMetadata server, DataSegment segment) {
                serverAddedSegment(server, segment);
                return ServerView.CallbackAction.CONTINUE;
            }

            @Override
            public ServerView.CallbackAction segmentRemoved(final DruidServerMetadata server, DataSegment segment) {
                serverRemovedSegment(server, segment);
                return ServerView.CallbackAction.CONTINUE;
            }

            @Override
            public CallbackAction segmentViewInitialized() {
                initialized = true;
                return ServerView.CallbackAction.CONTINUE;
            }
        });

        baseView.registerServerCallback(exec, new ServerView.ServerCallback() {
            @Override
            public ServerView.CallbackAction serverRemoved(DruidServer server) {
                removeServer(server);
                return ServerView.CallbackAction.CONTINUE;
            }
        });
    }

    public boolean isInitialized() {
        return initialized;
    }

    public void clear() {
        synchronized (lock) {
            final Iterator<String> clientsIter = clients.keySet().iterator();
            while (clientsIter.hasNext()) {
                clientsIter.remove();
            }

            timelines.clear();

            final Iterator<ServerSelector> selectorsIter = selectors.values().iterator();
            while (selectorsIter.hasNext()) {
                final ServerSelector selector = selectorsIter.next();
                selectorsIter.remove();
                while (!selector.isEmpty()) {
                    final QueryableDruidServer pick = selector.pick();
                    selector.removeServer(pick);
                }
            }
        }
    }

    private QueryableDruidServer addServer(DruidServer server) {
        QueryableDruidServer retVal = new QueryableDruidServer(server, makeDirectClient(server));
        QueryableDruidServer exists = clients.put(server.getName(), retVal);
        if (exists != null) {
            log.warn("QueryRunner for server[%s] already existed!? Well it's getting replaced", server);
        }

        return retVal;
    }

    private DirectDruidClient makeDirectClient(DruidServer server) {
        return new DirectDruidClient(warehouse, queryWatcher, smileMapper, httpClient, server.getHost(), emitter);
    }

    private QueryableDruidServer removeServer(DruidServer server) {
        for (DataSegment segment : server.getSegments().values()) {
            serverRemovedSegment(server.getMetadata(), segment);
        }
        return clients.remove(server.getName());
    }

    private void serverAddedSegment(final DruidServerMetadata server, final DataSegment segment) {
        String segmentId = segment.getIdentifier();
        synchronized (lock) {
            log.debug("Adding segment[%s] for server[%s]", segment, server);

            ServerSelector selector = selectors.get(segmentId);
            if (selector == null) {
                selector = new ServerSelector(segment, tierSelectorStrategy);

                VersionedIntervalTimeline<String, ServerSelector> timeline = timelines.get(segment.getDataSource());
                if (timeline == null) {
                    timeline = new VersionedIntervalTimeline<>(Ordering.natural());
                    timelines.put(segment.getDataSource(), timeline);
                }

                timeline.add(segment.getInterval(), segment.getVersion(),
                        segment.getShardSpec().createChunk(selector));
                selectors.put(segmentId, selector);
            }

            QueryableDruidServer queryableDruidServer = clients.get(server.getName());
            if (queryableDruidServer == null) {
                queryableDruidServer = addServer(baseView.getInventoryValue(server.getName()));
            }
            selector.addServer(queryableDruidServer);
        }
    }

    private void serverRemovedSegment(DruidServerMetadata server, DataSegment segment) {
        String segmentId = segment.getIdentifier();
        final ServerSelector selector;

        synchronized (lock) {
            log.debug("Removing segment[%s] from server[%s].", segmentId, server);

            selector = selectors.get(segmentId);
            if (selector == null) {
                log.warn("Told to remove non-existant segment[%s]", segmentId);
                return;
            }

            QueryableDruidServer queryableDruidServer = clients.get(server.getName());
            if (!selector.removeServer(queryableDruidServer)) {
                log.warn("Asked to disassociate non-existant association between server[%s] and segment[%s]",
                        server, segmentId);
            }

            if (selector.isEmpty()) {
                VersionedIntervalTimeline<String, ServerSelector> timeline = timelines.get(segment.getDataSource());
                selectors.remove(segmentId);

                final PartitionChunk<ServerSelector> removedPartition = timeline.remove(segment.getInterval(),
                        segment.getVersion(), segment.getShardSpec().createChunk(selector));

                if (removedPartition == null) {
                    log.warn("Asked to remove timeline entry[interval: %s, version: %s] that doesn't exist",
                            segment.getInterval(), segment.getVersion());
                }
            }
        }
    }

    @Override
    public VersionedIntervalTimeline<String, ServerSelector> getTimeline(DataSource dataSource) {
        String table = Iterables.getOnlyElement(dataSource.getNames());
        synchronized (lock) {
            return timelines.get(table);
        }
    }

    @Override
    public <T> QueryRunner<T> getQueryRunner(DruidServer server) {
        synchronized (lock) {
            QueryableDruidServer queryableDruidServer = clients.get(server.getName());
            if (queryableDruidServer == null) {
                log.error("WTF?! No QueryableDruidServer found for %s", server.getName());
                return null;
            }
            return queryableDruidServer.getClient();
        }
    }

    @Override
    public void registerServerCallback(Executor exec, ServerCallback callback) {
        baseView.registerServerCallback(exec, callback);
    }

    @Override
    public void registerSegmentCallback(Executor exec, SegmentCallback callback) {
        baseView.registerSegmentCallback(exec, callback);
    }
}