Java tutorial
/* * 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); } }