Package voldemort.server.storage

Source Code of voldemort.server.storage.DataMaintenanceJob

/*
* 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;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;

import org.apache.log4j.Logger;

import voldemort.annotations.jmx.JmxGetter;
import voldemort.server.StoreRepository;
import voldemort.store.StoreDefinition;
import voldemort.store.metadata.MetadataStore;
import voldemort.store.readonly.ReadOnlyStorageConfiguration;
import voldemort.utils.ByteArray;
import voldemort.utils.ClosableIterator;
import voldemort.utils.EventThrottler;
import voldemort.utils.Utils;

/**
* Base class for jobs that do some maintenance on the data stored in the server
*
*
*/
public abstract class DataMaintenanceJob implements Runnable {

    public final static List<String> BLACKLISTED_STORAGE_TYPES = Arrays.asList(ReadOnlyStorageConfiguration.TYPE_NAME);

    protected final static int STAT_RECORDS_INTERVAL = 10000;
    protected final ScanPermitWrapper scanPermits;
    protected final StoreRepository storeRepo;
    protected final MetadataStore metadataStore;
    protected ClosableIterator<ByteArray> iterator = null;
    protected AtomicLong numKeysScannedThisRun;
    protected AtomicLong numKeysUpdatedThisRun;
    protected long totalKeysScanned = 0;
    protected long totalKeysUpdated = 0;
    protected AtomicBoolean isRunning;
    protected final EventThrottler throttler;

    public DataMaintenanceJob(StoreRepository storeRepo,
                              MetadataStore metadataStore,
                              ScanPermitWrapper scanPermits,
                              int maxRatePerSecond) {
        this.storeRepo = storeRepo;
        this.metadataStore = metadataStore;
        this.scanPermits = Utils.notNull(scanPermits);
        this.numKeysScannedThisRun = new AtomicLong(0);
        this.numKeysUpdatedThisRun = new AtomicLong(0);
        this.isRunning = new AtomicBoolean(false);
        this.throttler = new EventThrottler(maxRatePerSecond);
    }

    public DataMaintenanceJob(StoreRepository storeRepo,
                              MetadataStore metadataStore,
                              ScanPermitWrapper scanPermits) {
        this(storeRepo, metadataStore, scanPermits, Integer.MAX_VALUE);
    }

    @Override
    public void run() {
        // don't do maintenance when the server is already neither normal nor
        // offline
        if(!isServerNormal() && !isServerOffline()) {
            getLogger().error("Cannot run "
                              + getJobName()
                              + " since Voldemort server is neither in normal state nor in offline state");
            return;
        }

        isRunning.set(true);
        Date startTime = new Date();
        getLogger().info("Started " + getJobName() + " at " + startTime);

        if(!acquireScanPermit()) {
            isRunning.set(false);
            return;
        }

        // actually operate the job
        try {
            operate();
        } catch(Exception e) {
            getLogger().error("Error running " + getJobName(), e);
        } finally {
            closeIterator(iterator);
            this.scanPermits.release(this.getClass().getCanonicalName());
            resetStats();
            getLogger().info("Completed " + getJobName() + " started at " + startTime);
            isRunning.set(false);
        }
    }

    abstract public void operate() throws Exception;

    abstract protected Logger getLogger();

    abstract protected String getJobName();

    private boolean isServerNormal() {
        return metadataStore.getServerStateUnlocked()
                            .equals(MetadataStore.VoldemortState.NORMAL_SERVER);
    }

    private boolean isServerOffline() {
        return metadataStore.getServerStateUnlocked()
                            .equals(MetadataStore.VoldemortState.OFFLINE_SERVER);
    }

    protected boolean isWritableStore(StoreDefinition storeDef) {
        if(!storeDef.isView() && !BLACKLISTED_STORAGE_TYPES.contains(storeDef.getType())) {
            return true;
        } else {
            return false;
        }
    }

    private boolean acquireScanPermit() {
        getLogger().info("Acquiring lock to perform " + getJobName());
        if(this.scanPermits.tryAcquire(this.numKeysScannedThisRun,
                                       this.numKeysUpdatedThisRun,
                                       this.getClass().getCanonicalName())) {
            getLogger().info("Acquired lock to perform " + getJobName());
            return true;
        } else {
            getLogger().error("Aborting " + getJobName()
                              + " since another instance is already running! ");
            return false;
        }
    }

    protected void closeIterator(ClosableIterator<ByteArray> iterator) {
        try {
            if(iterator != null) {
                iterator.close();
                iterator = null;
            }
        } catch(Exception e) {
            getLogger().error("Error in closing iterator", e);
        }
    }

    /**
     * Determines whether this job is already runnning.. Note that this only
     * protects against scheduling the same job twice by mistake from Admin tool
     * (most practical use case)
     *
     * Note: There can still be a race when two threads find this value to be
     * false and both attempt to execute the job
     *
     * @return
     */
    public AtomicBoolean getIsRunning() {
        return isRunning;
    }

    @JmxGetter(name = "numKeysScanned", description = "Returns number of keys scanned")
    public synchronized long getKeysScanned() {
        return totalKeysScanned + numKeysScannedThisRun.get();
    }

    protected synchronized void resetStats() {
        totalKeysScanned += numKeysScannedThisRun.get();
        numKeysScannedThisRun.set(0);
        totalKeysUpdated += numKeysUpdatedThisRun.get();
        numKeysUpdatedThisRun.set(0);
    }
}
TOP

Related Classes of voldemort.server.storage.DataMaintenanceJob

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.