/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 org.apache.hadoop.corona; import java.util.EnumMap; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.net.Node; public class ClusterNode { /** Class logger */ public static final Log LOG = LogFactory.getLog(ClusterNode.class); public long lastHeartbeatTime; public boolean deleted = false; public final Node hostNode; private ClusterNodeInfo clusterNodeInfo; private volatile ComputeSpecs freeSpecs; private Map<ResourceType, Integer> resourceTypeToMaxCpu = new EnumMap<ResourceType, Integer>(ResourceType.class); private Map<ResourceType, Stats> resourceTypeToStatsMap = new EnumMap<ResourceType, Stats>(ResourceType.class); protected Map<GrantId, ResourceRequestInfo> grants = new HashMap<GrantId, ResourceRequestInfo>(); protected ComputeSpecs granted = new ComputeSpecs(); // All integral fields get initialized to 0. public static class Stats { private volatile int allocatedCpu; private volatile int grantCount; } /** * Metadata about a granted resource on a node. */ public static class GrantId { /** Session identifier */ private final String sessionId; /** Request identifier */ private final int requestId; /** Unique name based on sessionId and requestId */ private final String unique; /** * Constructor. * * @param sessionId Session id using this grant * @param requestId Grant id */ public GrantId(String sessionId, int requestId) { this.sessionId = sessionId; this.requestId = requestId; this.unique = sessionId + requestId; } public String getSessionId() { return sessionId; } public int getRequestId() { return requestId; } @Override public int hashCode() { return unique.hashCode(); } @Override public boolean equals(Object that) { if (that == null) { return false; } if (that instanceof GrantId) { return this.equals((GrantId) that); } return false; } /** * Check if it equals another GrantId * * @param that Other GrandId * @return True if the same, false otherwise */ public boolean equals(GrantId that) { if (that == null) { return false; } return this.unique.equals(that.unique); } } /** * Based on the mapping of cpus to resources, find the appropriate resources * for a given number of cpus and initialize the resource type to allocated * cpu mapping. * * @param cpuToResourcePartitioning Mapping of cpus to resources to be used */ private void initResourceTypeToCpu( Map<Integer, Map<ResourceType, Integer>> cpuToResourcePartitioning) { resourceTypeToMaxCpu = getResourceTypeToCountMap((int) clusterNodeInfo.total.numCpus, cpuToResourcePartitioning); for (ResourceType type : ResourceType.values()) { resourceTypeToStatsMap.put(type, new Stats()); } } /** * Get a mapping of the resource type to amount of resources for a given * number of cpus. * * @param numCpus Number of cpus available * @param cpuToResourcePartitioning Mapping of number of cpus to resources * @return Resources for this amount of cpus */ public static Map<ResourceType, Integer> getResourceTypeToCountMap( int numCpus, Map<Integer, Map<ResourceType, Integer>> cpuToResourcePartitioning) { Map<ResourceType, Integer> ret = cpuToResourcePartitioning.get(numCpus); if (ret == null) { Map<ResourceType, Integer> oneCpuMap = cpuToResourcePartitioning.get(1); if (oneCpuMap == null) { throw new RuntimeException( "No matching entry for cpu count: " + numCpus + " in node and no 1 cpu map"); } ret = new EnumMap<ResourceType, Integer>(ResourceType.class); for (ResourceType key: oneCpuMap.keySet()) { ret.put(key, oneCpuMap.get(key).intValue() * numCpus); } } return ret; } public ClusterNode( ClusterNodeInfo clusterNodeInfo, Node node, Map<Integer, Map<ResourceType, Integer>> cpuToResourcePartitioning) { clusterNodeInfo.address.host = clusterNodeInfo.address.host.intern(); this.clusterNodeInfo = clusterNodeInfo; this.freeSpecs = clusterNodeInfo.getFree(); lastHeartbeatTime = ClusterManager.clock.getTime(); this.hostNode = node; initResourceTypeToCpu(cpuToResourcePartitioning); } public void addGrant(String sessionId, ResourceRequestInfo req) { if (deleted) throw new RuntimeException ("Node " + getName() + " has been deleted"); grants.put(new GrantId(sessionId, req.getId()), req); incrementGrantCount(req.getType()); // update allocated counts Utilities.incrComputeSpecs(granted, req.getSpecs()); Stats stats = resourceTypeToStatsMap.get(req.getType()); stats.allocatedCpu += req.getSpecs().numCpus; //LOG.info("Node " + getName() + " has granted " + granted.numCpus + " cpus"); } public ResourceRequestInfo getRequestForGrant(String sessionId, int requestId) { return grants.get(new GrantId(sessionId, requestId)); } public void cancelGrant(String sessionId, int requestId) { if (deleted) throw new RuntimeException ("Node " + getName() + " has been deleted"); ResourceRequestInfo req = grants.remove(new GrantId(sessionId, requestId)); if (req != null) { Utilities.decrComputeSpecs(granted, req.getSpecs()); Stats stats = resourceTypeToStatsMap.get(req.getType()); stats.allocatedCpu -= req.getSpecs().numCpus; decrementGrantCount(req.getType()); } } public boolean checkForGrant( ResourceRequest req, ResourceLimit resourceLimit) { if (deleted) throw new RuntimeException ("Node " + getName() + " has been deleted"); int cpuAlloced = resourceTypeToStatsMap.get(req.type).allocatedCpu; Integer cpuMax = resourceTypeToMaxCpu.get(req.type); boolean enoughCpu = cpuMax.intValue() >= req.getSpecs().numCpus + cpuAlloced; boolean enoughMem = resourceLimit.hasEnoughResource(this); return enoughCpu && enoughMem; } public void heartbeat(ClusterNodeInfo newClusterNodeInfo) { lastHeartbeatTime = ClusterManager.clock.getTime(); freeSpecs = newClusterNodeInfo.getFree(); } public String getName() { return clusterNodeInfo.name; } public String getHost() { return clusterNodeInfo.address.host; } public InetAddress getAddress() { return clusterNodeInfo.address; } public ComputeSpecs getFree() { return freeSpecs; } public ComputeSpecs getTotal() { return clusterNodeInfo.getTotal(); } public Set<GrantId> getGrants() { HashSet<GrantId> ret = new HashSet<GrantId> (); ret.addAll(grants.keySet()); return (ret); } private void incrementGrantCount(ResourceType type) { resourceTypeToStatsMap.get(type).grantCount++; } private void decrementGrantCount(ResourceType type) { resourceTypeToStatsMap.get(type).grantCount--; } public int getGrantCount(ResourceType type) { return resourceTypeToStatsMap.get(type).grantCount; } public Set<GrantId> getGrants(ResourceType type) { HashSet<GrantId> ret = new HashSet<GrantId> (); for (Map.Entry<GrantId, ResourceRequestInfo> entry : grants.entrySet()) { if (entry.getValue().getType().equals(type)) { ret.add(entry.getKey()); } } return ret; } public int getMaxCpuForType(ResourceType type) { Integer i = resourceTypeToMaxCpu.get(type); if (i == null) return 0; else return i.intValue(); } public int getAllocatedCpuForType(ResourceType type) { return resourceTypeToStatsMap.get(type).allocatedCpu; } }