/** * diqube: Distributed Query Base. * * Copyright (C) 2015 Bastian Gloeckle * * This file is part of diqube. * * diqube is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * 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 * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.diqube.ui; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import javax.websocket.Session; import org.diqube.context.AutoInstatiate; import org.diqube.remote.query.thrift.QueryResultService; import org.diqube.util.Pair; import org.diqube.util.Triple; /** * A registry for queries that have been sent to the cluster nodes for processing - and the result handlers that should * be called as soon as some result data is available. * * @author Bastian Gloeckle */ @AutoInstatiate public class UiQueryRegistry { /** * queryUuid to triple of * <ul> * <li>websocket session that initialized the query * <li>Pair of hostname and port of the diqube-server the query was sent to (the query master) * <li>The result handler. * </ul> */ private Map<UUID, Triple<Session, Pair<String, Short>, QueryResultService.Iface>> infoByQueryUuid = new ConcurrentHashMap<>(); private Map<Session, Map<String, UUID>> sessionsToRequestIdToQueryUuid = new ConcurrentHashMap<>(); /** * Register a {@link QueryResultService} callback that will be informed as soon as results for the given query have * been received. * * @param session * The Websocket {@link Session} that initialized the query. This is needed as the following parameter, * requestId, is unique only within one {@link Session}. * @param requestId * The ID provided by the client that uniquely identifies the request it sent in the context of the websocket * session. The installed result handler will provide result data for that request. * @param diqubeServerAddr * The server address to which the query is sent to for execution. * @param queryUuid * The query that has been sent to the diqube-server to identify the query. * @param resultHandler * The handler which will get informed. */ public void registerThriftResultCallback(Session session, String requestId, Pair<String, Short> diqubeServerAddr, UUID queryUuid, QueryResultService.Iface resultHandler) { infoByQueryUuid.put(queryUuid, new Triple<>(session, diqubeServerAddr, resultHandler)); Map<String, UUID> sessionMap = sessionsToRequestIdToQueryUuid.get(session); if (sessionMap == null) { synchronized (sessionsToRequestIdToQueryUuid) { if (!sessionsToRequestIdToQueryUuid.containsKey(session)) sessionsToRequestIdToQueryUuid.put(session, new ConcurrentHashMap<>()); sessionMap = sessionsToRequestIdToQueryUuid.get(session); } } sessionMap.put(requestId, queryUuid); } /** * Unregister the callback of a specific query. */ public void unregisterQuery(String requestId, UUID queryUuid) { Triple<Session, Pair<String, Short>, QueryResultService.Iface> oldTriple = infoByQueryUuid.remove(queryUuid); if (oldTriple != null) { Session session = oldTriple.getLeft(); sessionsToRequestIdToQueryUuid.get(session).remove(requestId); if (sessionsToRequestIdToQueryUuid.get(session).isEmpty()) { synchronized (sessionsToRequestIdToQueryUuid) { if (sessionsToRequestIdToQueryUuid.get(session).isEmpty()) sessionsToRequestIdToQueryUuid.remove(session); } } } } /** * Find and return the queryUuid that was used to start a query on the diqube-servers based on the given request by a * client. * * @param session * The websocket session in which we initiated the request. * @param requestId * The request ID that was sent by th client to uniquely identify the request within the session. * @return The Query UUID of the query that was triggered, or <code>null</code> if not available. */ public UUID getQueryUuid(Session session, String requestId) { Map<String, UUID> sessionMap = sessionsToRequestIdToQueryUuid.get(session); if (sessionMap == null) return null; return sessionMap.get(requestId); } /** * Finds the address of the diqube-server that a specific query was sent to for execution. * * @param queryUuid * The UUID of the query that we're searching. * @return Pair of hostname and port or <code>null</code> if not available. */ public Pair<String, Short> getDiqubeServerAddr(UUID queryUuid) { Triple<Session, Pair<String, Short>, QueryResultService.Iface> p = infoByQueryUuid.get(queryUuid); if (p == null) return null; return p.getMiddle(); } /** * Get the handler that is registered for a specific query or <code>null</code> if there is none. */ public QueryResultService.Iface getHandler(UUID queryUuid) { Triple<Session, Pair<String, Short>, QueryResultService.Iface> p = infoByQueryUuid.get(queryUuid); if (p == null) return null; return p.getRight(); } }