/*
* Copyright 2013 LinkedIn, Inc
*
* 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 voldemort.client.rebalance.task;
import java.util.List;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.log4j.Logger;
import voldemort.client.protocol.admin.AdminClient;
import voldemort.client.rebalance.RebalanceBatchPlanProgressBar;
import voldemort.client.rebalance.RebalanceTaskInfo;
import voldemort.utils.RebalanceUtils;
public abstract class RebalanceTask implements Runnable {
protected final int batchId;
protected final int taskId;
protected final List<RebalanceTaskInfo> stealInfos;
protected final Semaphore donorPermit;
protected final AdminClient adminClient;
protected final RebalanceBatchPlanProgressBar progressBar;
protected final Logger loggerToUse;
protected Exception exception;
protected final AtomicBoolean isComplete;
protected final int partitionStoreCount;
protected long permitAcquisitionTimeMs;
protected long taskCompletionTimeMs;
protected final static int INVALID_REBALANCE_ID = -1;
public RebalanceTask(final int batchId,
final int taskId,
final List<RebalanceTaskInfo> stealInfos,
final Semaphore donorPermit,
final AdminClient adminClient,
final RebalanceBatchPlanProgressBar progressBar,
final Logger logger) {
this.batchId = batchId;
this.taskId = taskId;
this.stealInfos = stealInfos;
this.donorPermit = donorPermit;
this.adminClient = adminClient;
this.progressBar = progressBar;
this.loggerToUse = logger;
this.exception = null;
this.isComplete = new AtomicBoolean(false);
this.partitionStoreCount = RebalanceUtils.countTaskStores(stealInfos);
this.permitAcquisitionTimeMs = -1;
this.taskCompletionTimeMs = -1;
}
public List<RebalanceTaskInfo> getStealInfos() {
return this.stealInfos;
}
public boolean isComplete() {
return this.isComplete.get();
}
public boolean hasException() {
return exception != null;
}
public Exception getError() {
return exception;
}
protected void acquirePermit(int nodeId) throws InterruptedException {
permitStart(nodeId);
boolean isPermitAcquired = false;
while(isPermitAcquired == false) {
isPermitAcquired = donorPermit.tryAcquire(5, TimeUnit.MINUTES);
if(isPermitAcquired == false) {
logPermitStatus(nodeId, "Waiting to acquire log ");
}
}
logPermitStatus(nodeId, "Acquired donor permit for node ");
}
@Override
public String toString() {
return "Rebalance task " + taskId + " from batch " + batchId + " : " + getStealInfos();
}
/**
* Helper method to log updates in uniform manner that includes batch & task
* ID.
*
* @param message
*/
protected void taskLog(String message) {
RebalanceUtils.printBatchTaskLog(batchId, taskId, loggerToUse, message);
}
/**
* Helper method to pretty print progress and timing info.
*
* @param nodeId node ID for which donor permit is required
*/
protected void permitStart(int nodeId) {
permitAcquisitionTimeMs = System.currentTimeMillis();
taskLog("Acquiring donor permit for node " + nodeId + ".");
}
/**
* Helper method to pretty print progress and timing info.
*
* @param nodeId node ID for which donor permit is required
*/
protected void logPermitStatus(int nodeId, String prefix) {
String durationString = "";
if(permitAcquisitionTimeMs >= 0) {
long durationMs = System.currentTimeMillis() - permitAcquisitionTimeMs;
permitAcquisitionTimeMs = -1;
durationString = " in " + TimeUnit.MILLISECONDS.toSeconds(durationMs) + " seconds.";
}
taskLog(prefix + nodeId + durationString);
}
/**
* Helper method to pretty print progress and timing info.
*
* @param rebalanceAsyncId ID of the async rebalancing task
*/
protected void taskStart(int taskId, int rebalanceAsyncId) {
taskCompletionTimeMs = System.currentTimeMillis();
taskLog("[TaskId : " + taskId + " ] Starting rebalance of " + partitionStoreCount
+ " partition-stores for async operation id " + rebalanceAsyncId + ".");
progressBar.beginTask(taskId);
}
/**
* Helper method to pretty print progress and timing info.
*
* @param rebalanceAsyncId ID of the async rebalancing task
*/
protected void taskDone(int taskId, int rebalanceAsyncId) {
String durationString = "";
if(taskCompletionTimeMs >= 0) {
long durationMs = System.currentTimeMillis() - taskCompletionTimeMs;
taskCompletionTimeMs = -1;
durationString = " in " + TimeUnit.MILLISECONDS.toSeconds(durationMs) + " seconds.";
}
taskLog("[TaskId : " + taskId + " ] Successfully finished rebalance of "
+ partitionStoreCount
+ " for async operation id " + rebalanceAsyncId + durationString);
progressBar.completeTask(taskId, partitionStoreCount);
}
}