/*
* Copyright 2015 Apache Software Foundation.
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.hdfs.server.blockmanagement;
import io.hops.leader_election.node.ActiveNode;
import io.hops.leader_election.node.SortedActiveNodeList;
import java.io.IOException;
import java.util.*;
import io.hops.metadata.HdfsVariables;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.hdfs.server.datanode.BRLoadBalancingException;
/**
*
* @author salman
*/
public class BRTrackingService {
private class Work {
private final long startTime;
private final long noOfBlks;
private final long nnId;
public Work(final long startTime, final long noOfBlks, final long nnId) {
this.startTime = startTime;
this.noOfBlks = noOfBlks;
this.nnId = nnId;
}
public long getStartTime() {
return startTime;
}
public long getNoOfBlks() {
return noOfBlks;
}
public long getNNId() { return nnId; }
}
private List workHistory = new LinkedList<Work>();
public static final Log LOG = LogFactory.getLog(BRTrackingService.class);
private final long DB_VAR_UPDATE_THRESHOLD;
private final long BR_LB_TIME_WINDOW_SIZE;
private int rrIndex = 0; // for round robin allocation
public BRTrackingService(final long DB_VAR_UPDATE_THRESHOLD, final long BR_LB_TIME_WINDOW_SIZE) {
workHistory = new LinkedList<Work>();
this.DB_VAR_UPDATE_THRESHOLD = DB_VAR_UPDATE_THRESHOLD;
this.BR_LB_TIME_WINDOW_SIZE = BR_LB_TIME_WINDOW_SIZE;
}
private int getRRIndex(final SortedActiveNodeList nnList){
if(rrIndex < 0 || rrIndex >= nnList.size()){
rrIndex = 0;
}
return (rrIndex++)%nnList.size();
}
private boolean canProcessMoreBR(long noOfBlks) throws IOException {
//first remove the old history
long timePoint = (System.currentTimeMillis() - BR_LB_TIME_WINDOW_SIZE);
if (workHistory.size() > 0) {
for (int i = workHistory.size() - 1; i >= 0; i--) {
Work work = (Work) workHistory.get(i);
if (work.getStartTime() <= timePoint) {
workHistory.remove(i);
LOG.debug("Removing ("+work.getNoOfBlks()+" blks) from history. It was assigned to NN: "+work.getNNId());
}
}
}
long ongoingWork = 0;
if (workHistory.size() > 0) {
for (int i = workHistory.size() - 1; i >= 0; i--) {
Work work = (Work) workHistory.get(i);
ongoingWork += work.getNoOfBlks();
}
}
LOG.debug("Currently processing at "+ongoingWork+" blks /"+(BR_LB_TIME_WINDOW_SIZE/(double)1000)+" sec");
if ((ongoingWork + noOfBlks) > getBrLbMaxBlkPerTW(DB_VAR_UPDATE_THRESHOLD)) {
return false;
} else {
return true;
}
}
private static long lastChecked = 0;
private static long cachedBrLbMaxBlkPerTW = -1;
private static long getBrLbMaxBlkPerTW(long DB_VAR_UPDATE_THRESHOLD) throws IOException {
if ((System.currentTimeMillis() - lastChecked) > DB_VAR_UPDATE_THRESHOLD) {
cachedBrLbMaxBlkPerTW = HdfsVariables.getBrLbMaxBlkPerTW();
lastChecked = System.currentTimeMillis();
LOG.debug("BRTrackingService. Processing "+cachedBrLbMaxBlkPerTW+" per time window");
}
return cachedBrLbMaxBlkPerTW;
}
public synchronized ActiveNode assignWork(final SortedActiveNodeList nnList, long noOfBlks) throws IOException {
if(canProcessMoreBR(noOfBlks)){
int index = getRRIndex(nnList);
if(index >= 0 && index < nnList.size()){
ActiveNode an = nnList.getSortedActiveNodes().get(index);
Work work = new Work(System.currentTimeMillis(),noOfBlks,an.getId());
workHistory.add(work);
LOG.info("Work ("+noOfBlks+" blks) assigned to NN: "+an.getId());
return an;
}
}
LOG.info("Work ("+noOfBlks+" blks) could not be assigned");
throw new BRLoadBalancingException("Work ("+noOfBlks+" blks) could not be assigned. System is fully loaded now");
}
}