/* This file is part of VoltDB. * Copyright (C) 2008-2017 VoltDB Inc. * * This program 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 VoltDB. If not, see <http://www.gnu.org/licenses/>. */ package org.voltdb.dtxn; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.voltcore.utils.CoreUtils; import org.voltdb.MailboxNodeContent; import org.voltdb.VoltDB; import org.voltdb.VoltZK.MailboxType; import com.google_voltpatches.common.collect.ImmutableList; import com.google_voltpatches.common.collect.ImmutableMap; import com.google_voltpatches.common.collect.ImmutableSet; public class SiteTracker { private final int m_hostId; private boolean m_isFirstHost; public final int m_version; public final ImmutableSet<Integer> m_allHostsImmutable; /* * Includes initiator sites, execution sites, and stats agents. Not really "all" */ public final ImmutableSet<Long> m_allSitesImmutable; public final ImmutableSet<Long> m_allExecutionSitesImmutable; private final long m_allExecutionSitesArray[]; public final ImmutableSet<Long> m_allInitiatorsImmutable; public final ImmutableMap<Integer, ImmutableList<Long>> m_hostsToSitesImmutable; public final ImmutableMap<Integer, ImmutableList<Integer>> m_hostsToPartitionsImmutable; public final ImmutableMap<Integer, ImmutableList<Long>> m_partitionsToSitesImmutable; public final ImmutableMap<Long, Integer> m_sitesToPartitionsImmutable; public final ImmutableMap<Integer, ImmutableList<Long>> m_hostsToInitiatorsImmutable; public final ImmutableMap<MailboxType, ImmutableList<Long>> m_otherHSIdsImmutable; public final ImmutableMap<MailboxType, ImmutableMap<Integer, ImmutableList<Long>>> m_hostsToOtherHSIdsImmutable; public final int m_numberOfPartitions; public final int m_numberOfHosts; public final int m_numberOfExecutionSites; private final int m_allPartitions[]; private long m_statsAgents[]; public SiteTracker() { m_allExecutionSitesArray = null; m_allPartitions = null; m_hostId = 0; m_hostsToInitiatorsImmutable = null; m_hostsToOtherHSIdsImmutable = null; m_partitionsToSitesImmutable = null; m_hostsToPartitionsImmutable = null; m_allExecutionSitesImmutable = null; m_allHostsImmutable = null; m_allSitesImmutable = null; m_allInitiatorsImmutable = null; m_hostsToSitesImmutable = null; m_numberOfHosts = 1; m_numberOfExecutionSites = 0; m_numberOfPartitions = 0; m_otherHSIdsImmutable = null; m_sitesToPartitionsImmutable = null; m_version = 0; } public SiteTracker(int hostId, Map<MailboxType, List<MailboxNodeContent>> mailboxes) { this(hostId, mailboxes, 0); } public SiteTracker(int hostId, Map<MailboxType, List<MailboxNodeContent>> mailboxes, int version) { m_version = version; m_hostId = hostId; Map<Integer, List<Long>> hostsToSites = new HashMap<Integer, List<Long>>(); Map<Integer, List<Integer>> hostsToPartitions = new HashMap<Integer, List<Integer>>(); Map<Integer, List<Long>> partitionsToSites = new HashMap<Integer, List<Long>>(); ImmutableMap.Builder<Long, Integer> sitesToPartitions = ImmutableMap.<Long, Integer>builder(); Map<Integer, List<Long>> hostsToInitiators = new HashMap<Integer, List<Long>>(); Map<MailboxType, List<Long>> otherHSIds = new HashMap<MailboxType, List<Long>>(); ImmutableSet.Builder<Integer> allHosts = ImmutableSet.<Integer>builder(); ImmutableSet.Builder<Long> allExecutionSites = ImmutableSet.<Long>builder(); ImmutableSet.Builder<Long> allInitiators = ImmutableSet.<Long>builder(); Map<MailboxType, Map<Integer, List<Long>>> hostsToOtherHSIds = new HashMap<MailboxType, Map<Integer, List<Long>>>(); for (Entry<MailboxType, List<MailboxNodeContent>> e : mailboxes.entrySet()) { if (e.getKey().equals(MailboxType.ExecutionSite)) { populateSites( e.getValue(), hostsToSites, hostsToPartitions, partitionsToSites, sitesToPartitions, allHosts, allExecutionSites); } else if (e.getKey().equals(MailboxType.Initiator)) { populateInitiators(e.getValue(), hostsToInitiators, allInitiators); } else if (e.getKey().equals(MailboxType.StatsAgent)) { populateStatsAgents(e.getValue()); } else { populateOtherHSIds(e.getKey(), e.getValue(), otherHSIds, hostsToOtherHSIds); } } m_hostsToSitesImmutable = CoreUtils.unmodifiableMapCopy(hostsToSites); m_hostsToPartitionsImmutable = CoreUtils.unmodifiableMapCopy(hostsToPartitions); m_partitionsToSitesImmutable = CoreUtils.unmodifiableMapCopy(partitionsToSites); m_sitesToPartitionsImmutable = sitesToPartitions.build(); m_hostsToInitiatorsImmutable = CoreUtils.unmodifiableMapCopy(hostsToInitiators); m_otherHSIdsImmutable = CoreUtils.unmodifiableMapCopy(otherHSIds); m_allInitiatorsImmutable = allInitiators.build(); m_allExecutionSitesImmutable = allExecutionSites.build(); m_allHostsImmutable = allHosts.build(); ImmutableMap.Builder<MailboxType, ImmutableMap<Integer, ImmutableList<Long>>> hostsToOtherHSIdsReplacement = ImmutableMap.<MailboxType, ImmutableMap<Integer, ImmutableList<Long>>>builder(); for (Map.Entry<MailboxType, Map<Integer, List<Long>>> e : hostsToOtherHSIds.entrySet()) { hostsToOtherHSIdsReplacement.put(e.getKey(), CoreUtils.unmodifiableMapCopy(e.getValue())); } m_hostsToOtherHSIdsImmutable = hostsToOtherHSIdsReplacement.build(); m_allExecutionSitesArray = new long[m_allExecutionSitesImmutable.size()]; int ii = 0; for (Long site : m_allExecutionSitesImmutable) { m_allExecutionSitesArray[ii++] = site; } m_numberOfPartitions = m_partitionsToSitesImmutable.keySet().size(); m_numberOfHosts = m_hostsToSitesImmutable.keySet().size(); m_numberOfExecutionSites = m_sitesToPartitionsImmutable.keySet().size(); m_allPartitions = new int[m_numberOfPartitions]; ii = 0; for (Integer partition : m_partitionsToSitesImmutable.keySet()) { m_allPartitions[ii++] = partition; } ImmutableSet.Builder<Long> allSites = ImmutableSet.<Long>builder(); allSites.addAll(m_allExecutionSitesImmutable); allSites.addAll(m_allInitiatorsImmutable); for (List<Long> siteIds : otherHSIds.values()) { allSites.addAll(siteIds); } m_allSitesImmutable = allSites.build(); } public int[] getAllPartitions() { return Arrays.copyOf(m_allPartitions, m_allPartitions.length); } private void populateStatsAgents(List<MailboxNodeContent> value) { m_statsAgents = new long[value.size()]; int ii = 0; for (MailboxNodeContent mnc : value) { m_statsAgents[ii] = mnc.HSId; ii++; } } public long[] getStatsAgents() { return Arrays.copyOf(m_statsAgents, m_statsAgents.length); } private void populateSites( List<MailboxNodeContent> objs, Map<Integer, List<Long>> hostsToSites, Map<Integer, List<Integer>> hostsToPartitions, Map<Integer, List<Long>> partitionsToSites, ImmutableMap.Builder<Long, Integer> sitesToPartitions, ImmutableSet.Builder<Integer> allHosts, ImmutableSet.Builder<Long> allExecutionSites) { int firstHostId = -1; for (MailboxNodeContent obj : objs) { int hostId = CoreUtils.getHostIdFromHSId(obj.HSId); if (firstHostId == -1) { firstHostId = hostId; } List<Long> hostSiteList = hostsToSites.get(hostId); if (hostSiteList == null) { hostSiteList = new ArrayList<Long>(); hostsToSites.put(hostId, hostSiteList); } hostSiteList.add(obj.HSId); List<Integer> hostPartList = hostsToPartitions.get(hostId); if (hostPartList == null) { hostPartList = new ArrayList<Integer>(); hostsToPartitions.put(hostId, hostPartList); } hostPartList.add(obj.partitionId); List<Long> partSiteList = partitionsToSites.get(obj.partitionId); if (partSiteList == null) { partSiteList = new ArrayList<Long>(); partitionsToSites.put(obj.partitionId, partSiteList); } partSiteList.add(obj.HSId); allHosts.add(hostId); allExecutionSites.add(obj.HSId); sitesToPartitions.put(obj.HSId, obj.partitionId); } m_isFirstHost = (m_hostId == firstHostId); } private void populateInitiators(List<MailboxNodeContent> objs, Map<Integer, List<Long>> hostsToInitiators, ImmutableSet.Builder<Long> allInitiators) { for (MailboxNodeContent obj : objs) { int hostId = CoreUtils.getHostIdFromHSId(obj.HSId); List<Long> initiators = hostsToInitiators.get(hostId); if (initiators == null) { initiators = new ArrayList<Long>(); hostsToInitiators.put(hostId, initiators); } if (obj.partitionId == null) { initiators.add(obj.HSId); allInitiators.add(obj.HSId); } } } private void populateOtherHSIds(MailboxType type, List<MailboxNodeContent> objs, Map<MailboxType, List<Long>> otherHSIds, Map<MailboxType, Map<Integer, List<Long>>> hostsToOtherHSIds) { List<Long> hsids = otherHSIds.get(type); if (hsids == null) { hsids = new ArrayList<Long>(); otherHSIds.put(type, hsids); } Map<Integer, List<Long>> hostToIds = hostsToOtherHSIds.get(type); if (hostToIds == null) { hostToIds = new HashMap<Integer, List<Long>>(); hostsToOtherHSIds.put(type, hostToIds); } for (MailboxNodeContent obj : objs) { int hostId = CoreUtils.getHostIdFromHSId(obj.HSId); hsids.add(obj.HSId); List<Long> hostIdList = hostToIds.get(hostId); if (hostIdList == null) { hostIdList = new ArrayList<Long>(); hostToIds.put(hostId, hostIdList); } hostIdList.add(obj.HSId); } } public static long[] longListToArray(List<Long> longs) { long retval[] = new long[longs.size()]; for (int ii = 0; ii < retval.length; ii++) { retval[ii] = longs.get(ii); } return retval; } public Set<Long> getAllSites() { return m_allExecutionSitesImmutable; } public long[] getAllSitesExcluding(long site) { long allSitesMinusOne[] = new long[m_allExecutionSitesArray.length - 1]; int zz = 0; for (int ii = 0; ii < m_allExecutionSitesArray.length; ii++) { if (m_allExecutionSitesArray[ii] == site) { continue; } allSitesMinusOne[zz++] = m_allExecutionSitesArray[ii]; } return allSitesMinusOne; } public Set<Integer> getAllHosts() { return m_allHostsImmutable; } public Set<Long> getAllInitiators() { return m_allInitiatorsImmutable; } /** * Get the ids of all live sites that contain a copy of the * partition specified. * * @param partition A VoltDB partition id. * @return An array of VoltDB site ids. */ public List<Long> getSitesForPartition(int partition) { return m_partitionsToSitesImmutable.get(partition); } /** * Get the ids of all sites that contain a copy of ANY of * the given partitions. * @param partitions as ArrayList */ public List<Long> getSitesForPartitions(int[] partitions) { ArrayList<Long> all_sites = new ArrayList<Long>(); for (int p : partitions) { List<Long> sites = getSitesForPartition(p); for (long site : sites) { all_sites.add(site); } } return all_sites; } /** * Whether we are the leader. It doesn't mean that we have the lowest host * ID, it just guarantees that there is only one node in the cluster that is * the leader. * * @return */ public boolean isFirstHost() { return m_isFirstHost; } /** * Get the ids of all live sites that contain a copy of ANY of * the given partitions. * * @param partitions A set of unique, non-null VoltDB * partition ids. * @return An array of VoltDB site ids. */ public long[] getSitesForPartitionsAsArray(int[] partitions) { ArrayList<Long> all_sites = new ArrayList<Long>(); for (int p : partitions) { List<Long> sites = getSitesForPartition(p); for (long site : sites) { all_sites.add(site); } } return longListToArray(all_sites); } /** * Get the list of all site IDs that are on a specific host ID * @param hostId * @return An ArrayList of VoltDB site IDs. */ public List<Long> getSitesForHost(int hostId) { return m_hostsToSitesImmutable.get(hostId); } /** * Get the host id for a specific site * @param siteid * @return Integer host id for that site */ public static int getHostForSite(long siteId) { return CoreUtils.getHostIdFromHSId(siteId); } /** * Return the id of the partition stored by a given site. * * @param siteId The id of a VoltDB site. * @return The id of the partition stored at the given site. */ public int getPartitionForSite(long siteId) { return m_sitesToPartitionsImmutable.get(siteId); } /** * @param hostId * @return the ID of the lowest execution site on the given hostId */ public Long getLowestSiteForHost(int hostId) { List<Long> sites = getSitesForHost(hostId); return Collections.min(sites); } /* * Get an array of local sites that need heartbeats. This will get individually generated heartbeats. */ public long[] getLocalSites() { int hostId = VoltDB.instance().getHostMessenger().getHostId(); return longListToArray(m_hostsToSitesImmutable.get(hostId)); } /* * An array per up host, there will be no entry for this host */ public long[][] getRemoteSites() { int localhost = VoltDB.instance().getHostMessenger().getHostId(); long[][] retval = new long[m_allHostsImmutable.size() - 1][]; int i = 0; for (int host : m_allHostsImmutable) { if (host != localhost) { retval[i++] = longListToArray(m_hostsToSitesImmutable.get(host)); } } return retval; } public List<Long> getInitiatorsForHost(int host) { return m_hostsToInitiatorsImmutable.get(host); } public Map<Long, Integer> getSitesToPartitions() { return m_sitesToPartitionsImmutable; } public List<Integer> getPartitionsForHost(int host) { return m_hostsToPartitionsImmutable.get(host); } public List<Long> getHSIdsForHost(MailboxType type, int host) { ImmutableMap<Integer, ImmutableList<Long>> hostIdList = m_hostsToOtherHSIdsImmutable.get(type); if (hostIdList == null) { return new ArrayList<Long>(); } return hostIdList.get(host); } }