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

com.qwazr.cluster.ClusterNodeMap Maven / Gradle / Ivy

There is a newer version: 1.5.2
Show newest version
/*
 * Copyright 2015-2017 Emmanuel Keller / QWAZR
 * 

* 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 com.qwazr.cluster; import com.qwazr.utils.LoggerUtils; import com.qwazr.utils.StringUtils; import com.qwazr.utils.concurrent.ReadWriteLock; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.SortedSet; import java.util.TreeMap; import java.util.TreeSet; import java.util.UUID; import java.util.logging.Logger; class ClusterNodeMap { private static final Logger LOGGER = LoggerUtils.getLogger(ClusterNodeMap.class); private final ClusterManager clusterManager; private final InetSocketAddress myAddress; private final ReadWriteLock readWriteLock = ReadWriteLock.stamped(); private final HashMap nodesMap; private final HashMap> groupsMap; private final HashMap> servicesMap; private volatile Cache cache; private class Cache { private final HashMap cacheNodesMap; private final Set fullNodesAddresses; private final Set externalNodesAddresses; private final TreeMap> cacheGroupsMap; private final TreeMap> cacheServicesMap; private Cache() { externalNodesAddresses = new HashSet<>(); fullNodesAddresses = new HashSet<>(); cacheNodesMap = new HashMap<>(); nodesMap.forEach((address, clusterNode) -> { if (!myAddress.equals(clusterNode.address.address)) externalNodesAddresses.add(clusterNode.address.address); fullNodesAddresses.add(clusterNode.address.address); cacheNodesMap.put(address, clusterNode); }); cacheGroupsMap = new TreeMap<>(); groupsMap.forEach((key, nodes) -> cacheGroupsMap.put(key, new TreeSet<>(nodes))); cacheServicesMap = new TreeMap<>(); servicesMap.forEach((key, nodes) -> cacheServicesMap.put(key, new TreeSet<>(nodes))); } } ClusterNodeMap(final ClusterManager clusterManager, final InetSocketAddress myAddress) { this.clusterManager = clusterManager; this.myAddress = myAddress; nodesMap = new HashMap<>(); groupsMap = new HashMap<>(); servicesMap = new HashMap<>(); cache = new Cache(); } private final SortedSet EMPTY = Collections.unmodifiableSortedSet(new TreeSet<>()); /** * @param group the name of the group * @param service the name of the service * @return a set of nodes for the given group and service */ final SortedSet getGroupService(final String group, final String service) { final Cache cc = cache; final TreeSet groupSet = group == null ? null : cc.cacheGroupsMap.get(group); final TreeSet serviceSet = service == null ? null : cc.cacheServicesMap.get(service); if (!StringUtils.isEmpty(group) && (groupSet == null || groupSet.isEmpty())) return EMPTY; if (!StringUtils.isEmpty(service) && (serviceSet == null || serviceSet.isEmpty())) return EMPTY; if (groupSet == null && serviceSet == null) return EMPTY; final TreeSet nodes = new TreeSet<>(); if (groupSet == null) { nodes.addAll(serviceSet); return nodes; } if (serviceSet == null) { nodes.addAll(groupSet); return nodes; } groupSet.forEach(node -> { if (serviceSet.contains(node)) nodes.add(node); }); return nodes; } private static TreeSet getNodes(final String key, final TreeMap> nodesMap) { final TreeSet nodeSet = nodesMap.get(key); final TreeSet nodes = new TreeSet<>(); if (nodeSet != null) nodes.addAll(nodeSet); return nodes; } final TreeSet getByGroup(final String group) { return getNodes(group, cache.cacheGroupsMap); } final TreeSet getByService(final String service) { return getNodes(service, cache.cacheServicesMap); } final TreeMap> getGroups() { return cache.cacheGroupsMap; } final TreeMap> getServices() { return cache.cacheServicesMap; } /** * @return a map which contains the nodes */ final Map getNodesMap() { return cache.cacheNodesMap; } final Set getExternalNodeAddresses() { return cache.externalNodesAddresses; } final Set getFullNodeAddresses() { return cache.fullNodesAddresses; } private static void registerSet(final Collection keys, final HashMap> nodesMap, final String address) { for (final String key : keys) { final HashSet nodeSet = nodesMap.computeIfAbsent(key, k -> new HashSet<>()); nodeSet.add(address); } } private static void unregisterSet(final HashMap> nodesMap, final String address) { final List toRemove = new ArrayList<>(); nodesMap.forEach((key, nodeSet) -> { nodeSet.remove(address); if (nodeSet.isEmpty()) toRemove.add(key); }); nodesMap.remove(address); toRemove.forEach(nodesMap::remove); } private ClusterNode put(final String httpAddress, final UUID nodeLiveId, final Long expirationTimeNs) { final ClusterNodeAddress clusterNodeAddress = new ClusterNodeAddress(httpAddress, 9091); final ClusterNode node = new ClusterNode(clusterNodeAddress, nodeLiveId, expirationTimeNs); nodesMap.put(clusterNodeAddress.httpAddressKey, node); return node; } private ClusterNode registerNode(final String httpAddress, final UUID nodeLiveId, final Long expirationTimeMs) { final ClusterNode node = nodesMap.get(httpAddress); if (node == null) return put(httpAddress, nodeLiveId, expirationTimeMs); if (nodeLiveId == null) return node; if (nodeLiveId.equals(node.nodeLiveId)) { node.setExpirationTime(expirationTimeMs); return node; } return put(httpAddress, nodeLiveId, expirationTimeMs); } /** * Insert or update a node * * @param httpAddress the address of the node */ final ClusterNode register(final String httpAddress) { if (httpAddress == null) return null; return readWriteLock.write(() -> { final ClusterNode clusterNode = registerNode(httpAddress, null, null); cache = new Cache(); return clusterNode; }); } final void register(final Collection httpAddresses) { if (httpAddresses == null) return; httpAddresses.forEach(this::register); } final ClusterNode registerAddress(final AddressContent message, final Long expirationTimeMs) { if (message == null) return null; final String address = message.getAddress(); if (address == null) return null; return readWriteLock.writeEx(() -> { final ClusterNode clusterNode = registerNode(address, message.getNodeLiveId(), expirationTimeMs); cache = new Cache(); return clusterNode; }); } final ClusterNode registerFull(final FullContent message, final Long expirationTimeMs) { if (message == null) return null; final String address = message.getAddress(); if (address == null) return null; return readWriteLock.writeEx(() -> { final ClusterNode clusterNode = registerNode(address, message.getNodeLiveId(), expirationTimeMs); unregisterSet(groupsMap, clusterNode.address.httpAddressKey); unregisterSet(servicesMap, clusterNode.address.httpAddressKey); clusterNode.registerGroups(message.groups); clusterNode.registerServices(message.services); registerSet(message.groups, groupsMap, address); registerSet(message.services, servicesMap, address); cache = new Cache(); return clusterNode; }); } /** * Unregister the node * * @param address the node to unregister */ private void unregisterAll(final String address) { LOGGER.info(() -> "Unregister " + address + " from " + myAddress); final ClusterNode clusterNode = nodesMap.get(address); final ClusterNodeAddress nodeAddress = clusterNode != null ? clusterNode.address : new ClusterNodeAddress(address, 9091); if (clusterNode != null) { clusterNode.registerGroups(Collections.emptyList()); clusterNode.registerServices(Collections.emptyList()); } unregisterSet(groupsMap, nodeAddress.httpAddressKey); unregisterSet(servicesMap, nodeAddress.httpAddressKey); if (!clusterManager.isMaster(nodeAddress)) nodesMap.remove(nodeAddress.httpAddressKey); } /** * Remove the node * * @param message the node to unregister */ final void unregister(final AddressContent message) { if (message == null) return; readWriteLock.writeEx(() -> { unregisterAll(message.getAddress()); cache = new Cache(); }); } final synchronized void removeExpired() { final List deleteAdresses = new ArrayList<>(); final long currentMs = System.currentTimeMillis(); readWriteLock.writeEx(() -> { nodesMap.forEach((address, node) -> { if (node.isExpired(currentMs)) deleteAdresses.add(address); }); if (deleteAdresses.isEmpty()) return; deleteAdresses.forEach(this::unregisterAll); cache = new Cache(); }); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy