/*
* Copyright 2008-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.server.storage.repairjob;
import javax.management.MBeanOperationInfo;
import org.apache.log4j.Logger;
import voldemort.annotations.jmx.JmxGetter;
import voldemort.annotations.jmx.JmxOperation;
import voldemort.routing.StoreRoutingPlan;
import voldemort.server.StoreRepository;
import voldemort.server.storage.DataMaintenanceJob;
import voldemort.server.storage.ScanPermitWrapper;
import voldemort.store.StorageEngine;
import voldemort.store.StoreDefinition;
import voldemort.store.metadata.MetadataStore;
import voldemort.utils.ByteArray;
/**
* This is a background job that should be run after successful rebalancing. The
* job deletes all data that does not belong to the server.
*
* FIXME VC RepairJob is a non intuitive name. Need to rename this.
*/
public class RepairJob extends DataMaintenanceJob {
private final static Logger logger = Logger.getLogger(RepairJob.class.getName());
public RepairJob(StoreRepository storeRepo,
MetadataStore metadataStore,
ScanPermitWrapper repairPermits,
int maxKeysScannedPerSecond) {
super(storeRepo, metadataStore, repairPermits, maxKeysScannedPerSecond);
}
@JmxOperation(description = "Start the Repair Job thread", impact = MBeanOperationInfo.ACTION)
public void startRepairJob() {
run();
}
@Override
public void operate() throws Exception {
for(StoreDefinition storeDef: metadataStore.getStoreDefList()) {
if(isWritableStore(storeDef)) {
// Lets generate routing strategy for this storage engine
StoreRoutingPlan routingPlan = new StoreRoutingPlan(metadataStore.getCluster(),
storeDef);
logger.info("Repairing store " + storeDef.getName());
StorageEngine<ByteArray, byte[], byte[]> engine = storeRepo.getStorageEngine(storeDef.getName());
iterator = engine.keys();
long itemsScanned = 0;
long numDeletedKeys = 0;
while(iterator.hasNext()) {
ByteArray key = iterator.next();
if(!routingPlan.checkKeyBelongsToNode(key.get(), metadataStore.getNodeId())) {
/**
* Blow away the entire key with all its versions..
*/
engine.delete(key, null);
numDeletedKeys = this.numKeysUpdatedThisRun.incrementAndGet();
}
itemsScanned = this.numKeysScannedThisRun.incrementAndGet();
throttler.maybeThrottle(1);
if(itemsScanned % STAT_RECORDS_INTERVAL == 0) {
logger.info("#Scanned:" + itemsScanned + " #Deleted:" + numDeletedKeys);
}
}
closeIterator(iterator);
logger.info("Completed store " + storeDef.getName() + " #Scanned:" + itemsScanned
+ " #Deleted:" + numDeletedKeys);
}
}
}
@Override
protected Logger getLogger() {
return logger;
}
@Override
protected String getJobName() {
return "repair job";
}
@JmxGetter(name = "numKeysDeleted", description = "Returns number of keys deleted")
public synchronized long getKeysDeleted() {
return totalKeysUpdated + numKeysUpdatedThisRun.get();
}
}