/**
* 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 java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* An implementation of {@link ReplicaId} to be used within the {@link StaticClusterManager}.
*
* A Replica is one constituent piece of a {@link Partition}. A Replica is uniquely identifiable by its Partition and
* its {@link Disk}. Note that this induces a constraint that a Partition can never have more than one Replica on a
* given Disk. This ensures that a Partition does not have Replicas that share fates.
*/
class Replica implements ReplicaId {
private final Partition partition;
private Disk disk;
private Logger logger = LoggerFactory.getLogger(getClass());
Replica(Partition partition, Disk disk) {
if (logger.isTraceEnabled()) {
logger.trace("Replica " + partition + ", " + disk);
}
this.partition = partition;
this.disk = disk;
validate();
}
Replica(HardwareLayout hardwareLayout, Partition partition, JSONObject jsonObject) throws JSONException {
this.partition = partition;
this.disk = hardwareLayout.findDisk(jsonObject.getString("hostname"), jsonObject.getInt("port"),
jsonObject.getString("mountPath"));
validate();
}
@Override
public PartitionId getPartitionId() {
return getPartition();
}
@Override
public DataNodeId getDataNodeId() {
return disk.getDataNode();
}
@Override
public String getMountPath() {
return disk.getMountPath();
}
@Override
public String getReplicaPath() {
return getMountPath() + File.separator + partition.toPathString();
}
@Override
public List<ReplicaId> getPeerReplicaIds() {
List<Replica> peerReplicas = getPeerReplicas();
return new ArrayList<ReplicaId>(peerReplicas);
}
@Override
public long getCapacityInBytes() {
return partition.getReplicaCapacityInBytes();
}
@Override
public DiskId getDiskId() {
return disk;
}
@Override
public boolean isDown() {
return getDataNodeId().getState() == HardwareState.UNAVAILABLE
|| getDiskId().getState() == HardwareState.UNAVAILABLE;
}
Partition getPartition() {
return partition;
}
List<Replica> getPeerReplicas() {
List<Replica> peers = new ArrayList<Replica>(partition.getReplicas().size());
for (Replica peer : partition.getReplicas()) {
if (!peer.equals(this)) {
peers.add(peer);
}
}
return peers;
}
protected void validatePartition() {
if (partition == null) {
throw new IllegalStateException("Partition cannot be null.");
}
}
private void validateDisk() {
if (disk == null) {
throw new IllegalStateException("Disk cannot be null.");
}
}
private void validate() {
logger.trace("begin validate.");
validatePartition();
validateDisk();
logger.trace("complete validate.");
}
JSONObject toJSONObject() throws JSONException {
// Effectively serializes the "foreign key" into hardwareLayout to find Disk.
return new JSONObject().put("hostname", disk.getDataNode().getHostname())
.put("port", disk.getDataNode().getPort())
.put("mountPath", disk.getMountPath());
}
@Override
public String toString() {
return "Replica[" + getDataNodeId().getHostname() + ":" + getDataNodeId().getPort() + ":" + getReplicaPath() + "]";
}
}