| /** |
| * 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.hdds.scm.node; |
| |
| import com.google.common.annotations.VisibleForTesting; |
| import org.apache.hadoop.hdds.protocol.DatanodeDetails; |
| import org.apache.hadoop.hdds.protocol.proto |
| .StorageContainerDatanodeProtocolProtos.LayoutVersionProto; |
| import org.apache.hadoop.hdds.protocol.proto |
| .StorageContainerDatanodeProtocolProtos.StorageReportProto; |
| import org.apache.hadoop.hdds.protocol.proto |
| .StorageContainerDatanodeProtocolProtos.MetadataStorageReportProto; |
| import org.apache.hadoop.util.Time; |
| |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.concurrent.locks.ReadWriteLock; |
| import java.util.concurrent.locks.ReentrantReadWriteLock; |
| |
| /** |
| * This class extends the primary identifier of a Datanode with ephemeral |
| * state, eg last reported time, usage information etc. |
| */ |
| public class DatanodeInfo extends DatanodeDetails { |
| |
| private final ReadWriteLock lock; |
| |
| private volatile long lastHeartbeatTime; |
| private long lastStatsUpdatedTime; |
| |
| private List<StorageReportProto> storageReports; |
| private List<MetadataStorageReportProto> metadataStorageReports; |
| private LayoutVersionProto lastKnownLayoutVersion; |
| |
| private NodeStatus nodeStatus; |
| |
| /** |
| * Constructs DatanodeInfo from DatanodeDetails. |
| * |
| * @param datanodeDetails Details about the datanode |
| * @param nodeStatus Node Status |
| * @param layoutInfo Details about the LayoutVersionProto |
| */ |
| public DatanodeInfo(DatanodeDetails datanodeDetails, NodeStatus nodeStatus, |
| LayoutVersionProto layoutInfo) { |
| super(datanodeDetails); |
| this.lock = new ReentrantReadWriteLock(); |
| this.lastHeartbeatTime = Time.monotonicNow(); |
| lastKnownLayoutVersion = |
| LayoutVersionProto.newBuilder() |
| .setMetadataLayoutVersion(layoutInfo != null ? |
| layoutInfo.getMetadataLayoutVersion() : 0) |
| .setSoftwareLayoutVersion(layoutInfo != null ? |
| layoutInfo.getSoftwareLayoutVersion() : 0) |
| .build(); |
| this.storageReports = Collections.emptyList(); |
| this.nodeStatus = nodeStatus; |
| this.metadataStorageReports = Collections.emptyList(); |
| } |
| |
| /** |
| * Updates the last heartbeat time with current time. |
| */ |
| public void updateLastHeartbeatTime() { |
| updateLastHeartbeatTime(Time.monotonicNow()); |
| } |
| |
| /** |
| * Sets the last heartbeat time to a given value. Intended to be used |
| * only for tests. |
| * |
| * @param milliSecondsSinceEpoch - ms since Epoch to set as the heartbeat time |
| */ |
| @VisibleForTesting |
| public void updateLastHeartbeatTime(long milliSecondsSinceEpoch) { |
| try { |
| lock.writeLock().lock(); |
| lastHeartbeatTime = milliSecondsSinceEpoch; |
| } finally { |
| lock.writeLock().unlock(); |
| } |
| } |
| |
| /** |
| * Updates the last LayoutVersion. |
| */ |
| public void updateLastKnownLayoutVersion(LayoutVersionProto version) { |
| if (version == null) { |
| return; |
| } |
| try { |
| lock.writeLock().lock(); |
| lastKnownLayoutVersion = LayoutVersionProto.newBuilder() |
| .setMetadataLayoutVersion(version.getMetadataLayoutVersion()) |
| .setSoftwareLayoutVersion(version.getSoftwareLayoutVersion()) |
| .build(); |
| } finally { |
| lock.writeLock().unlock(); |
| } |
| } |
| |
| /** |
| * Returns the last heartbeat time. |
| * |
| * @return last heartbeat time. |
| */ |
| public long getLastHeartbeatTime() { |
| try { |
| lock.readLock().lock(); |
| return lastHeartbeatTime; |
| } finally { |
| lock.readLock().unlock(); |
| } |
| } |
| |
| /** |
| * Returns the last known Layout Version . |
| * |
| * @return last Layout Version. |
| */ |
| public LayoutVersionProto getLastKnownLayoutVersion() { |
| try { |
| lock.readLock().lock(); |
| return lastKnownLayoutVersion; |
| } finally { |
| lock.readLock().unlock(); |
| } |
| } |
| |
| /** |
| * Updates the datanode storage reports. |
| * |
| * @param reports list of storage report |
| */ |
| public void updateStorageReports(List<StorageReportProto> reports) { |
| try { |
| lock.writeLock().lock(); |
| lastStatsUpdatedTime = Time.monotonicNow(); |
| storageReports = reports; |
| } finally { |
| lock.writeLock().unlock(); |
| } |
| } |
| |
| /** |
| * Updates the datanode metadata storage reports. |
| * |
| * @param reports list of metadata storage report |
| */ |
| public void updateMetaDataStorageReports( |
| List<MetadataStorageReportProto> reports) { |
| try { |
| lock.writeLock().lock(); |
| lastStatsUpdatedTime = Time.monotonicNow(); |
| metadataStorageReports = reports; |
| } finally { |
| lock.writeLock().unlock(); |
| } |
| } |
| |
| /** |
| * Returns the storage reports associated with this datanode. |
| * |
| * @return list of storage report |
| */ |
| public List<StorageReportProto> getStorageReports() { |
| try { |
| lock.readLock().lock(); |
| return storageReports; |
| } finally { |
| lock.readLock().unlock(); |
| } |
| } |
| |
| /** |
| * Returns count of healthy volumes reported from datanode. |
| * @return count of healthy volumes |
| */ |
| public int getHealthyVolumeCount() { |
| try { |
| lock.readLock().lock(); |
| return storageReports.size() - getFailedVolumeCount(); |
| } finally { |
| lock.readLock().unlock(); |
| } |
| } |
| |
| /** |
| * Returns count of healthy metadata volumes reported from datanode. |
| * @return count of healthy metdata log volumes |
| */ |
| public int getMetaDataVolumeCount() { |
| try { |
| lock.readLock().lock(); |
| return metadataStorageReports.size(); |
| } finally { |
| lock.readLock().unlock(); |
| } |
| } |
| |
| /** |
| * Returns count of failed volumes reported from datanode. |
| * @return count of failed volumes |
| */ |
| private int getFailedVolumeCount() { |
| return (int) storageReports.stream(). |
| filter(e -> e.hasFailed() ? e.getFailed() : false).count(); |
| } |
| |
| /** |
| * Returns the last updated time of datanode info. |
| * @return the last updated time of datanode info. |
| */ |
| public long getLastStatsUpdatedTime() { |
| return lastStatsUpdatedTime; |
| } |
| |
| /** |
| * Return the current NodeStatus for the datanode. |
| * |
| * @return NodeStatus - the current nodeStatus |
| */ |
| public NodeStatus getNodeStatus() { |
| try { |
| lock.readLock().lock(); |
| return nodeStatus; |
| } finally { |
| lock.readLock().unlock(); |
| } |
| } |
| |
| /** |
| * Update the NodeStatus for this datanode. When using this method |
| * be ware of the potential for lost updates if two threads read the |
| * current status, update one field and then write it back without |
| * locking enforced outside of this class. |
| * |
| * @param newNodeStatus - the new NodeStatus object |
| */ |
| public void setNodeStatus(NodeStatus newNodeStatus) { |
| try { |
| lock.writeLock().lock(); |
| this.nodeStatus = newNodeStatus; |
| } finally { |
| lock.writeLock().unlock(); |
| } |
| } |
| |
| @Override |
| public int hashCode() { |
| return super.hashCode(); |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| return super.equals(obj); |
| } |
| |
| } |