Package org.xtreemfs.babudb.lsmdb

Source Code of org.xtreemfs.babudb.lsmdb.DatabaseImpl

/*
* Copyright (c) 2009 - 2011, Jan Stender, Bjoern Kolbeck, Mikael Hoegqvist,
*                     Felix Hupfeld, Felix Langner, Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.babudb.lsmdb;

import java.io.File;
import java.io.IOException;
import java.nio.channels.ClosedByInterruptException;

import org.xtreemfs.babudb.BabuDBRequestResultImpl;
import org.xtreemfs.babudb.api.database.DatabaseInsertGroup;
import org.xtreemfs.babudb.api.database.DatabaseRequestResult;
import org.xtreemfs.babudb.api.database.ResultSet;
import org.xtreemfs.babudb.api.database.UserDefinedLookup;
import org.xtreemfs.babudb.api.dev.BabuDBInternal;
import org.xtreemfs.babudb.api.dev.DatabaseInternal;
import org.xtreemfs.babudb.api.exception.BabuDBException;
import org.xtreemfs.babudb.api.exception.BabuDBException.ErrorCode;
import org.xtreemfs.babudb.api.index.ByteRangeComparator;
import org.xtreemfs.babudb.log.DiskLogger.SyncMode;
import org.xtreemfs.babudb.snapshots.SnapshotConfig;
import org.xtreemfs.foundation.logging.Logging;

public class DatabaseImpl implements DatabaseInternal {
       
    private final BabuDBInternal        dbs;
   
    private LSMDatabase                 lsmDB;
   
/*
* constructors/destructors
*/

    /**
     * Creates a new Database.
     *
     * @param dbs
     * @param lsmDB - the underlying LSM database.
     */
    public DatabaseImpl(BabuDBInternal dbs, LSMDatabase lsmDB) {
        this.dbs = dbs;
        this.lsmDB = lsmDB;
    }
   
    /*
     * (non-Javadoc)
     *
     * @see org.xtreemfs.babudb.lsmdb.DatabaseRO#shutdown()
     */
    @Override
    public void shutdown() throws BabuDBException {
       
        try {
            for (int index = 0; index < lsmDB.getIndexCount(); index++)
                lsmDB.getIndex(index).destroy();
        } catch (IOException exc) {
            throw new BabuDBException(ErrorCode.IO_ERROR, exc.getMessage(), exc);
        }
    }
   
    /* (non-Javadoc)
     * @see org.xtreemfs.babudb.api.database.Database#createInsertGroup()
     */
    @Override
    public BabuDBInsertGroup createInsertGroup() {
       
        return new BabuDBInsertGroup(lsmDB);
    }
   
    /*
     * DB modification operations
     */

    /*
     * (non-Javadoc)
     *
     * @see org.xtreemfs.babudb.lsmdb.Database#singleInsert(int, byte[], byte[],
     * java.lang.Object)
     */
    @Override
    public DatabaseRequestResult<Object> singleInsert(int indexId, byte[] key,
            byte[] value, Object context) {
       
        BabuDBInsertGroup irg = new BabuDBInsertGroup(lsmDB);
        irg.addInsert(indexId, key, value);
       
        return insert(irg, context);
    }
   
    /*
     * (non-Javadoc)
     *
     * @seeorg.xtreemfs.babudb.lsmdb.Database#insert(org.xtreemfs.babudb.lsmdb.
     * BabuDBInsertGroup, java.lang.Object)
     */
    @Override
    public DatabaseRequestResult<Object> insert(BabuDBInsertGroup irg, Object context) {
       
        InsertRecordGroup ins = irg.getRecord();
        int dbId = ins.getDatabaseId();
       
        LSMDBWorker w = dbs.getWorker(dbId);
        if (w != null) {
            if (Logging.isDebug()) {
                Logging.logMessage(Logging.LEVEL_DEBUG, this, "insert request"
                        + " is sent to worker #" + dbId % dbs.getWorkerCount());
            }
           
            BabuDBRequestResultImpl<Object> result =
                new BabuDBRequestResultImpl<Object>(context, dbs.getResponseManager());
            try {
                w.addRequest(new LSMDBRequest<Object>(lsmDB, result, ins));
            } catch (InterruptedException ex) {
                result.failed(new BabuDBException(ErrorCode.INTERRUPTED,
                        "operation was interrupted", ex));
            }
           
            return result;
        } else {
            return directInsert(irg, context);
        }
    }
   
    /**
     * Insert an group of inserts in the context of the invoking thread.
     * Proper insertion is not guaranteed, since the result of the attempt to
     * make the insert persistent is ignored, if {@link SyncMode} is ASYNC.
     *
     * @param irg - the group of inserts.
     * @param context - the context object for this request.
     *
     * @return the request future.
     */
    private DatabaseRequestResult<Object> directInsert(BabuDBInsertGroup irg, Object context) {

        BabuDBRequestResultImpl<Object> result =
            new BabuDBRequestResultImpl<Object>(context, dbs.getResponseManager());
       
        try {
            dbs.getTransactionManager().makePersistent(
                    dbs.getDatabaseManager().createTransaction().insertRecordGroup(
                            getName(), irg.getRecord(), getLSMDB()), result);
        } catch (BabuDBException e) {
           
            // if an exception occurred while writing the log, respond with an
            // error message
            result.failed(e);
        }
       
        return result;
    }
   
/*
* DB lookup operations
*/

    /* (non-Javadoc)
     *
     * @see org.xtreemfs.babudb.lsmdb.DatabaseRO#lookup(int, byte[],
     * java.lang.Object)
     */
    @Override
    public DatabaseRequestResult<byte[]> lookup(int indexId, byte[] key,
            Object context) {
       
        BabuDBRequestResultImpl<byte[]> result =
            new BabuDBRequestResultImpl<byte[]>(context, dbs.getResponseManager());
        LSMDBWorker w = dbs.getWorker(lsmDB.getDatabaseId());
        if (w != null) {
            if (Logging.isDebug()) {
                Logging.logMessage(Logging.LEVEL_DEBUG, this, "lookup request"
                        + " is sent to worker #"
                        + lsmDB.getDatabaseId() % dbs.getWorkerCount());
            }
           
            try {
                w.addRequest(new LSMDBRequest<byte[]>(lsmDB, indexId, result,
                        key));
            } catch (InterruptedException ex) {
                result.failed(new BabuDBException(ErrorCode.INTERRUPTED,
                        "operation was interrupted", ex));
            }
        } else
            directLookup(indexId, key, result);
       
        return result;
    }
   
    /**
     * Looks up a key in the database, without using a worker thread.
     *
     * @param indexId
     * @param key
     * @param listener
     *            the result listener.
     */
    private void directLookup(int indexId, byte[] key,
            BabuDBRequestResultImpl<byte[]> listener) {
       
        if ((indexId >= lsmDB.getIndexCount()) || (indexId < 0)) {
            listener.failed(new BabuDBException(ErrorCode.NO_SUCH_INDEX,
                    "index does not exist"));
        } else
            listener.finished(lsmDB.getIndex(indexId).lookup(key));
    }
   
    /* (non-Javadoc)
     * @see org.xtreemfs.babudb.api.database.DatabaseRO#prefixLookup(int, byte[], java.lang.Object)
     */
    @Override
    public DatabaseRequestResult<ResultSet<byte[], byte[]>> prefixLookup(
            int indexId, byte[] key, Object context) {
        return prefixLookup(indexId, key, context, true);
    }
   
    /* (non-Javadoc)
     * @see org.xtreemfs.babudb.api.database.DatabaseRO#reversePrefixLookup(int, byte[], java.lang.Object)
     */
    @Override
    public DatabaseRequestResult<ResultSet<byte[], byte[]>>
            reversePrefixLookup(int indexId, byte[] key, Object context) {
        return prefixLookup(indexId, key, context, false);
    }
   
    /**
     * Performs a prefix lookup.
     *
     * @param indexId
     * @param key
     * @param context
     * @param ascending
     * @return the request result object.
     */
    private DatabaseRequestResult<ResultSet<byte[], byte[]>> prefixLookup(
            int indexId, byte[] key, Object context, boolean ascending) {
       
        final BabuDBRequestResultImpl<ResultSet<byte[], byte[]>> result =
            new BabuDBRequestResultImpl<ResultSet<byte[], byte[]>>(context,
                    dbs.getResponseManager());
       
        // if there are worker threads, delegate the prefix lookup to the
        // responsible worker thread
        LSMDBWorker w = dbs.getWorker(lsmDB.getDatabaseId());
        if (w != null) {
            if (Logging.isDebug() && w != null) {
                Logging.logMessage(Logging.LEVEL_DEBUG, this, "lookup request"
                        + " is sent to worker #"
                        + lsmDB.getDatabaseId() % dbs.getWorkerCount());
            }
           
            try {
                w.addRequest(new LSMDBRequest<ResultSet<byte[], byte[]>>(
                        lsmDB, indexId, result, key, ascending));
            } catch (InterruptedException ex) {
                result.failed(new BabuDBException(ErrorCode.INTERRUPTED,
                        "operation was interrupted", ex));
            }
        }

        // otherwise, perform a direct prefix lookup
        else {
           
            if ((indexId >= lsmDB.getIndexCount()) || (indexId < 0))
                result.failed(new BabuDBException(ErrorCode.NO_SUCH_INDEX,
                        "index does not exist"));
            else
                result.finished(lsmDB.getIndex(indexId).prefixLookup(key,
                        ascending));
        }
       
        return result;
    }
   
    /* (non-Javadoc)
     * @see org.xtreemfs.babudb.api.database.DatabaseRO#rangeLookup(int, byte[], byte[],
     *          java.lang.Object)
     */
    @Override
    public DatabaseRequestResult<ResultSet<byte[], byte[]>> rangeLookup(
            int indexId, byte[] from, byte[] to, Object context) {
        return rangeLookup(indexId, from, to, context, true);
    }
   
    /* (non-Javadoc)
     * @see org.xtreemfs.babudb.api.database.DatabaseRO#reverseRangeLookup(int, byte[], byte[],
     *          java.lang.Object)
     */
    @Override
    public DatabaseRequestResult<ResultSet<byte[], byte[]>>
            reverseRangeLookup(int indexId, byte[] from, byte[] to,
                    Object context) {
        return rangeLookup(indexId, from, to, context, false);
    }
   
    /**
     * Performs a range lookup.
     *
     * @param indexId
     * @param from
     * @param to
     * @param context
     * @param ascending
     * @return the request result object.
     */
    private DatabaseRequestResult<ResultSet<byte[], byte[]>> rangeLookup(
            int indexId, byte[] from, byte[] to, Object context,
            boolean ascending) {
       
        final BabuDBRequestResultImpl<ResultSet<byte[], byte[]>> result =
            new BabuDBRequestResultImpl<ResultSet<byte[], byte[]>>(context,
                    dbs.getResponseManager());
       
        // if there are worker threads, delegate the range lookup to the
        // responsible worker thread
        LSMDBWorker w = dbs.getWorker(lsmDB.getDatabaseId());
        if (w != null) {
            if (Logging.isDebug() && w != null) {
                Logging.logMessage(Logging.LEVEL_DEBUG, this, "lookup request"
                        + " is sent to worker #"
                        + lsmDB.getDatabaseId() % dbs.getWorkerCount());
            }
           
            try {
                w.addRequest(new LSMDBRequest<ResultSet<byte[], byte[]>>(
                        lsmDB, indexId, result, from, to, ascending));
            } catch (InterruptedException ex) {
                result.failed(new BabuDBException(ErrorCode.INTERRUPTED,
                        "operation was interrupted", ex));
            }
        }

        // otherwise, perform a direct range lookup
        else {
           
            if ((indexId >= lsmDB.getIndexCount()) || (indexId < 0))
                result.failed(new BabuDBException(ErrorCode.NO_SUCH_INDEX,
                        "index does not exist"));
            else
                result.finished(lsmDB.getIndex(indexId).rangeLookup(from, to,
                        ascending));
        }
       
        return result;
    }
   
    /*
     * (non-Javadoc)
     *
     * @see
     * org.xtreemfs.babudb.lsmdb.DatabaseRO#userDefinedLookup(org.xtreemfs.babudb
     * .UserDefinedLookup, java.lang.Object)
     */
    @Override
    public DatabaseRequestResult<Object> userDefinedLookup(
            UserDefinedLookup udl, Object context) {
       
        final BabuDBRequestResultImpl<Object> result =
            new BabuDBRequestResultImpl<Object>(context, dbs.getResponseManager());
       
        LSMDBWorker w = dbs.getWorker(lsmDB.getDatabaseId());
        if (w != null) {
            if (Logging.isNotice()) {
                Logging.logMessage(Logging.LEVEL_NOTICE, this, "udl request is"
                        + " sent to worker #"
                        + lsmDB.getDatabaseId() % dbs.getWorkerCount());
            }
           
            try {
                w.addRequest(new LSMDBRequest<Object>(lsmDB, result, udl));
            } catch (InterruptedException ex) {
                result.failed(new BabuDBException(ErrorCode.INTERRUPTED,
                        "operation was interrupted", ex));
            }
        } else
            directUserDefinedLookup(udl, result);
       
        return result;
    }
   
    /**
     * Performs a user-defined lookup, without using a worker thread.
     *
     * @param udl
     * @param listener
     */
    private void directUserDefinedLookup(UserDefinedLookup udl,
            BabuDBRequestResultImpl<Object> listener) {
        final LSMLookupInterface lif = new LSMLookupInterface(lsmDB);
        try {
            Object result = udl.execute(lif);
            listener.finished(result);
        } catch (BabuDBException e) {
            listener.failed(e);
        }
    }
   
    /* (non-Javadoc)
     * @see org.xtreemfs.babudb.api.dev.DatabaseInternal#directLookup(int, int, byte[])
     */
    @Override
    public byte[] directLookup(int indexId, int snapId, byte[] key)
        throws BabuDBException {
       
        if ((indexId >= lsmDB.getIndexCount()) || (indexId < 0)) {
            throw new BabuDBException(ErrorCode.NO_SUCH_INDEX,
                    "index does not exist");
        }
        return lsmDB.getIndex(indexId).lookup(key, snapId);
    }
   
    /* (non-Javadoc)
     * @see org.xtreemfs.babudb.api.dev.DatabaseInternal#directPrefixLookup(int, int, byte[],
     *          boolean)
     */
    @Override
    public ResultSet<byte[], byte[]> directPrefixLookup(int indexId,
            int snapId, byte[] key, boolean ascending) throws BabuDBException {
       
        if ((indexId >= lsmDB.getIndexCount()) || (indexId < 0)) {
            throw new BabuDBException(ErrorCode.NO_SUCH_INDEX,
                    "index does not exist");
        }
        return lsmDB.getIndex(indexId).prefixLookup(key, snapId, ascending);
    }

    /* (non-Javadoc)
     * @see org.xtreemfs.babudb.api.dev.DatabaseInternal#directRangeLookup(int, int, byte[], byte[],
     *          boolean)
     */
    @Override
    public ResultSet<byte[], byte[]> directRangeLookup(int indexId,
            int snapId, byte[] from, byte[] to, boolean ascending)
                throws BabuDBException {
       
        if ((indexId >= lsmDB.getIndexCount()) || (indexId < 0)) {
            throw new BabuDBException(ErrorCode.NO_SUCH_INDEX,
                    "index does not exist");
        }
        return lsmDB.getIndex(indexId).rangeLookup(from, to, snapId, ascending);
    }
   
    /* (non-Javadoc)
     * @see org.xtreemfs.babudb.api.dev.DatabaseInternal#proceedSnapshot(java.lang.String)
     */
    @Override
    public void proceedSnapshot(String destDB) throws BabuDBException, InterruptedException {
       
        int[] ids;
        try {
            // critical block...
            dbs.getTransactionManager().lockService();
            ids = lsmDB.createSnapshot();
        } finally {
            dbs.getTransactionManager().unlockService();
        }
       
        File dbDir = new File(dbs.getConfig().getBaseDir() + destDB);
        if (!dbDir.exists()) {
            dbDir.mkdirs();
        }
       
        try {
            LSN lsn = lsmDB.getOndiskLSN();
            lsmDB.writeSnapshot(dbs.getConfig().getBaseDir() + destDB +
                    File.separatorChar, ids, lsn.getViewId(),
                    lsn.getSequenceNo());
        } catch (IOException ex) {
            throw new BabuDBException(ErrorCode.IO_ERROR,
                    "cannot write snapshot: " + ex, ex.getCause());
        }
    }
   
    /* (non-Javadoc)
     * @see org.xtreemfs.babudb.api.dev.DatabaseInternal#proceedCreateSnapshot()
     */
    @Override
    public int[] proceedCreateSnapshot() {
        return lsmDB.createSnapshot();
    }
   
    /* (non-Javadoc)
     * @see org.xtreemfs.babudb.api.dev.DatabaseInternal#proceedWriteSnapshot(int[],
     *          java.lang.String, org.xtreemfs.babudb.snapshots.SnapshotConfig)
     */
    @Override
    public void proceedWriteSnapshot(int[] snapIds, String directory, SnapshotConfig cfg)
        throws BabuDBException {
        try {
            lsmDB.writeSnapshot(directory, snapIds, cfg);
        } catch (IOException ex) {
            throw new BabuDBException(ErrorCode.IO_ERROR, "cannot write snapshot: " + ex, ex);
        }
    }
   
    /**
     * Writes the snapshots to disk.
     *
     * @param viewId
     *            current viewId (i.e. of the last write)
     * @param sequenceNo
     *            current sequenceNo (i.e. of the last write)
     * @param snapIds
     *            the snapshot Ids (obtained via createSnapshot).
     * @throws BabuDBException
     *             if a snapshot cannot be written
     */
    public void writeSnapshot(int viewId, long sequenceNo, int[] snapIds) throws BabuDBException {
       
        proceedWriteSnapshot(viewId, sequenceNo, snapIds);
    }
   
    /* (non-Javadoc)
     * @see org.xtreemfs.babudb.api.dev.DatabaseInternal#proceedWriteSnapshot(int, long, int[])
     */
    @Override
    public void proceedWriteSnapshot(int viewId, long sequenceNo, int[] snapIds)
            throws BabuDBException {
        try {
            lsmDB.writeSnapshot(viewId, sequenceNo, snapIds);
        } catch (IOException ex) {
            throw new BabuDBException(ErrorCode.IO_ERROR, "cannot write snapshot: " + ex, ex);
        }
       
    }
   
    /* (non-Javadoc)
     * @see org.xtreemfs.babudb.api.dev.DatabaseInternal#proceedCleanupSnapshot(int, long)
     */
    @Override
    public void proceedCleanupSnapshot(final int viewId, final long sequenceNo)
            throws BabuDBException {
        try {
            lsmDB.cleanupSnapshot(viewId, sequenceNo);
        } catch (ClosedByInterruptException ex) {
            Logging.logError(Logging.LEVEL_DEBUG, this, ex);
        } catch (IOException ex) {
            throw new BabuDBException(ErrorCode.IO_ERROR, "cannot clean up: " + ex, ex);
        }
    }
   
    /* (non-Javadoc)
     * @see org.xtreemfs.babudb.api.dev.DatabaseInternal#dumpSnapshot(java.lang.String)
     */
    @Override
    public void dumpSnapshot(String baseDir) throws BabuDBException {
        // destination directory of this
        baseDir = baseDir.endsWith(File.separator) ? baseDir : baseDir + File.separator;
        String destDir = baseDir + lsmDB.getDatabaseName();
       
        try {
            int ids[] = lsmDB.createSnapshot();
            LSN lsn = lsmDB.getOndiskLSN();
            lsmDB.writeSnapshot(destDir, ids, lsn.getViewId(), lsn.getSequenceNo());
        } catch (IOException ex) {
            throw new BabuDBException(ErrorCode.IO_ERROR, "cannot write snapshot: " + ex, ex);
        }
    }

    /* (non-Javadoc)
     * @see org.xtreemfs.babudb.api.dev.DatabaseInternal#setLSMDB(
     *          org.xtreemfs.babudb.lsmdb.LSMDatabase)
     */
    @Override
    public void setLSMDB(LSMDatabase lsmDatabase) {
        this.lsmDB = lsmDatabase;
    }
   
    /* (non-Javadoc)
     * @see org.xtreemfs.babudb.api.dev.DatabaseInternal#getLSMDB()
     */
    @Override
    public LSMDatabase getLSMDB() {
        return lsmDB;
    }
   
    /*
     * (non-Javadoc)
     *
     * @see org.xtreemfs.babudb.lsmdb.Database#getComparators()
     */
    @Override
    public ByteRangeComparator[] getComparators() {
        return lsmDB.getComparators();
    }
   
    /*
     * (non-Javadoc)
     *
     * @see org.xtreemfs.babudb.lsmdb.Database#getName()
     */
    @Override
    public String getName() {
        return lsmDB.getDatabaseName();
    }

    /* (non-Javadoc)
     * @see org.xtreemfs.babudb.api.database.Database#insert(org.xtreemfs.babudb.api.database.DatabaseInsertGroup, java.lang.Object)
     */
    @Override
    public DatabaseRequestResult<Object> insert(DatabaseInsertGroup irg, Object context) {
        return insert((BabuDBInsertGroup) irg, context);
    }
   
}
TOP

Related Classes of org.xtreemfs.babudb.lsmdb.DatabaseImpl

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.