/**
* Copyright 2016 LinkedIn Corp. All rights reserved.
*
* 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.
*/
package com.github.ambry.clustermap;
import com.github.ambry.config.ClusterMapConfig;
import com.github.ambry.utils.Utils;
import java.io.File;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* An implementation of {@link DiskId} to be used within the {@link StaticClusterManager}.
*
* A Disk stores {@link Replica}s. Each Disk is hosted on one specific {@link DataNode}. Each Disk is uniquely
* identified by its DataNode and mount path (the path to this Disk's device on its DataNode).
*/
class Disk implements DiskId {
private final DataNode dataNode;
private final String mountPath;
private final ResourceStatePolicy diskStatePolicy;
private long capacityInBytes;
private final Logger logger = LoggerFactory.getLogger(getClass());
Disk(DataNode dataNode, JSONObject jsonObject, ClusterMapConfig clusterMapConfig) throws JSONException {
if (logger.isTraceEnabled()) {
logger.trace("Disk " + jsonObject.toString());
}
this.dataNode = dataNode;
this.mountPath = jsonObject.getString("mountPath");
try {
ResourceStatePolicyFactory resourceStatePolicyFactory =
Utils.getObj(clusterMapConfig.clusterMapResourceStatePolicyFactory, this,
HardwareState.valueOf(jsonObject.getString("hardwareState")), clusterMapConfig);
this.diskStatePolicy = resourceStatePolicyFactory.getResourceStatePolicy();
} catch (Exception e) {
logger.error("Error creating resource state policy when instantiating a disk " + e);
throw new IllegalStateException("Error creating resource state policy when instantiating a disk: " + mountPath,
e);
}
this.capacityInBytes = jsonObject.getLong("capacityInBytes");
validate();
}
@Override
public String getMountPath() {
return mountPath;
}
@Override
public HardwareState getState() {
// A Disk is unavailable if its DataNode is unavailable.
return dataNode.getState() == HardwareState.AVAILABLE && !diskStatePolicy.isDown() ? HardwareState.AVAILABLE
: HardwareState.UNAVAILABLE;
}
boolean isDown() {
return diskStatePolicy.isDown();
}
@Override
public long getRawCapacityInBytes() {
return capacityInBytes;
}
DataNode getDataNode() {
return dataNode;
}
HardwareState getHardState() {
return diskStatePolicy.isHardDown() ? HardwareState.UNAVAILABLE : HardwareState.AVAILABLE;
}
protected void validateDataNode() {
if (dataNode == null) {
throw new IllegalStateException("DataNode cannot be null.");
}
}
private void validateMountPath() {
if (mountPath == null) {
throw new IllegalStateException("Mount path cannot be null.");
}
if (mountPath.length() == 0) {
throw new IllegalStateException("Mount path cannot be zero-length string.");
}
File mountPathFile = new File(mountPath);
if (!mountPathFile.isAbsolute()) {
throw new IllegalStateException("Mount path has to be an absolute path.");
}
}
protected void validate() {
logger.trace("begin validate.");
validateDataNode();
validateMountPath();
ClusterMapUtils.validateDiskCapacity(capacityInBytes);
logger.trace("complete validate.");
}
JSONObject toJSONObject() throws JSONException {
return new JSONObject().put("mountPath", mountPath)
.put("hardwareState", getHardState())
.put("capacityInBytes", capacityInBytes);
}
@Override
public String toString() {
String dataNodeStr = dataNode == null ? "" : dataNode.getHostname() + ":" + dataNode.getPort() + ":";
return "Disk[" + dataNodeStr + getMountPath() + "]";
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Disk disk = (Disk) o;
if (!dataNode.equals(disk.dataNode)) {
return false;
}
return mountPath.equals(disk.mountPath);
}
@Override
public int hashCode() {
int result = dataNode.hashCode();
result = 31 * result + mountPath.hashCode();
return result;
}
void onDiskError() {
diskStatePolicy.onError();
}
void onDiskOk() {
diskStatePolicy.onSuccess();
}
}