Package org.xtreemfs.babudb.snapshots

Source Code of org.xtreemfs.babudb.snapshots.SnapshotManagerImpl

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

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import org.xtreemfs.babudb.BabuDBRequestResultImpl;
import org.xtreemfs.babudb.api.database.DatabaseRO;
import org.xtreemfs.babudb.api.dev.BabuDBInternal;
import org.xtreemfs.babudb.api.dev.DatabaseInternal;
import org.xtreemfs.babudb.api.dev.SnapshotManagerInternal;
import org.xtreemfs.babudb.api.dev.transaction.InMemoryProcessing;
import org.xtreemfs.babudb.api.dev.transaction.OperationInternal;
import org.xtreemfs.babudb.api.exception.BabuDBException;
import org.xtreemfs.babudb.api.exception.BabuDBException.ErrorCode;
import org.xtreemfs.babudb.api.transaction.Operation;
import org.xtreemfs.babudb.lsmdb.BabuDBTransaction;
import org.xtreemfs.babudb.lsmdb.InsertRecordGroup;
import org.xtreemfs.foundation.buffer.ReusableBuffer;
import org.xtreemfs.foundation.logging.Logging;
import org.xtreemfs.foundation.util.FSUtils;

public class SnapshotManagerImpl implements SnapshotManagerInternal {
   
    public static final String                       SNAP_DIR = "snapshots";
   
    private final BabuDBInternal                     dbs;
   
    private final Map<String, Map<String, Snapshot>> snapshotDBs;
   
    public SnapshotManagerImpl(BabuDBInternal dbs) {
        this.dbs = dbs;
        this.snapshotDBs = Collections.synchronizedMap(new HashMap<String, Map<String, Snapshot>>());
       
        initializeTransactionManager();
    }
   
    public void init() throws BabuDBException {
       
        // load persisted snapshots from disk
        for (Entry<String, DatabaseInternal> entry : dbs.getDatabaseManager().getDatabasesInternal()
                .entrySet()) {
           
            final File snapDir = new File(dbs.getConfig().getBaseDir(), entry.getKey() + "/snapshots");
            if (snapDir.exists()) {
               
                Map<String, Snapshot> snapMap = new HashMap<String, Snapshot>();
                snapshotDBs.put(entry.getKey(), snapMap);
               
                boolean compressed = entry.getValue().getLSMDB().getIndex(0).isCompressed();
                boolean mmaped = entry.getValue().getLSMDB().getIndex(0).isMMapEnabled();
               
                String[] snapshots = snapDir.list();
                for (String snapName : snapshots) {
                    BabuDBView view = new DiskIndexView(snapDir + "/" + snapName, entry.getValue()
                            .getComparators(), compressed, mmaped);
                    snapMap.put(snapName, new Snapshot(view, dbs));
                }
            }
        }
    }
   
    /* (non-Javadoc)
     * @see org.xtreemfs.babudb.api.dev.SnapshotManagerInternal#shutdown()
     */
    @Override
    public void shutdown() throws BabuDBException {
        for (Map<String, Snapshot> snapshots : snapshotDBs.values())
            for (Snapshot snapshot : snapshots.values())
                snapshot.shutdown();
        Logging.logMessage(Logging.LEVEL_DEBUG, this, "snapshot manager shut down successfully");
    }
   
    @Override
    public DatabaseRO getSnapshotDB(String dbName, String snapshotName) throws BabuDBException {
       
        Map<String, Snapshot> snapMap = snapshotDBs.get(dbName);
        if (snapMap == null)
            throw new BabuDBException(ErrorCode.NO_SUCH_SNAPSHOT, "no snapshots exist for database '"
                + dbName + "'");
       
        Snapshot snap = snapMap.get(snapshotName);
        if (snap == null)
            throw new BabuDBException(ErrorCode.NO_SUCH_SNAPSHOT, "no snapshot '" + snapshotName
                + "' exists for database '" + dbName + "'");
       
        return snap;
    }
   
    /* (non-Javadoc)
     * @see org.xtreemfs.babudb.api.SnapshotManager#createPersistentSnapshot(java.lang.String, org.xtreemfs.babudb.snapshots.SnapshotConfig)
     */
    @Override
    public void createPersistentSnapshot(String dbName, SnapshotConfig snap)
        throws BabuDBException {
       
        // synchronously executing the request
        BabuDBRequestResultImpl<Object> result =
            new BabuDBRequestResultImpl<Object>(dbs.getResponseManager());
        dbs.getTransactionManager().makePersistent(
                dbs.getDatabaseManager().createTransaction().createSnapshot(dbName, snap), result);
        result.get();
    }
   
    /* (non-Javadoc)
     * @see org.xtreemfs.babudb.api.dev.SnapshotManagerInternal#snapshotComplete(java.lang.String,
     *          org.xtreemfs.babudb.snapshots.SnapshotConfig)
     */
    @Override
    public void snapshotComplete(String dbName, SnapshotConfig snap) throws BabuDBException {
       
        // as soon as the snapshot has been completed, replace the entry in the
        // snapshot DB map with a disk index-based BabuDB instance if necessary
        synchronized (snapshotDBs) {
         
          DatabaseInternal db = dbs.getDatabaseManager().getDatabase(dbName);
          boolean compressed = db.getLSMDB().getIndex(0).isCompressed();
          boolean mmaped = db.getLSMDB().getIndex(0).isMMapEnabled();
         
            Snapshot s = snapshotDBs.get(dbName).get(snap.getName());
            s.setView(new DiskIndexView(getSnapshotDir(dbName, snap.getName()), dbs.getDatabaseManager()
                    .getDatabase(dbName).getComparators(), compressed, mmaped));
        }
    }
   
    @Override
    public void deletePersistentSnapshot(String dbName, String snapshotName) throws BabuDBException {
       
        BabuDBRequestResultImpl<Object> result =
            new BabuDBRequestResultImpl<Object>(dbs.getResponseManager());
        dbs.getTransactionManager().makePersistent(
                dbs.getDatabaseManager().createTransaction().deleteSnapshot(
                        dbName, snapshotName), result);
        result.get();
    }
   
    @Override
    public String[] getAllSnapshots(String dbName) {
       
        final Map<String, Snapshot> snapMap = snapshotDBs.get(dbName);
        if (snapMap != null) {
            Set<String> names = snapMap.keySet();
            return names.toArray(new String[names.size()]);
        }

        else
            return new String[0];
    }
   
    /* (non-Javadoc)
     * @see org.xtreemfs.babudb.api.dev.SnapshotManagerInternal#deleteAllSnapshots(java.lang.String)
     */
    @Override
    public void deleteAllSnapshots(String dbName) throws BabuDBException {
       
        final Map<String, Snapshot> snapMap = snapshotDBs.get(dbName);
        if (snapMap != null) {
           
            for (Entry<String, Snapshot> snap : snapMap.entrySet()) {
               
                // shut down the view
                snap.getValue().shutdown();
               
                // if a snapshot materialization request is currently in the
                // checkpointer queue, remove it
                dbs.getCheckpointer().removeSnapshotMaterializationRequest(dbName, snap.getKey());
               
            }
           
            // remove the map entry
            snapshotDBs.remove(dbName);
        }
        FSUtils.delTree(new File(getSnapshotDir(dbName, null)));
       
        // no delete log entries for the snapshots are needed here, since the
        // method will only be invoked when the database itself is deleted
    }
   
    /* (non-Javadoc)
     * @see org.xtreemfs.babudb.api.dev.SnapshotManagerInternal#getSnapshotDir(java.lang.String,
     *          java.lang.String)
     */
    @Override
    public String getSnapshotDir(String dbName, String snapshotName) {
        return dbs.getConfig().getBaseDir() + dbName + "/" + SnapshotManagerImpl.SNAP_DIR + "/"
            + (snapshotName == null ? "" : snapshotName);
    }
   
    /**
     * Feed the transactionManager with the knowledge on how to handle snapshot related requests.
     */
    private void initializeTransactionManager() {
       
        dbs.getTransactionManager().registerInMemoryProcessing(Operation.TYPE_CREATE_SNAP,
                new InMemoryProcessing() {
           
            @Override
            public Object[] deserializeRequest(ReusableBuffer serialized) throws BabuDBException {
                ObjectInputStream oin = null;
                try {
                    oin = new ObjectInputStream(new ByteArrayInputStream(serialized.array()));
                    int dbId = oin.readInt();
                    SnapshotConfig snap = (SnapshotConfig) oin.readObject();
                   
                    return new Object[] { dbId, snap };
                } catch (Exception e) {
                    throw new BabuDBException(ErrorCode.IO_ERROR,
                            "Could not deserialize operation of type " + Operation.TYPE_CREATE_SNAP +
                                ", because: "+e.getMessage(), e);
                } finally {
                    try {
                        serialized.flip();
                        if (oin != null) oin.close();
                    } catch (IOException ioe) {
                        /* who cares? */
                    }
                }
            }
           
            @Override
            public OperationInternal convertToOperation(Object[] args) {
                return new BabuDBTransaction.BabuDBOperation(Operation.TYPE_CREATE_SNAP, (String) null,
                        new Object[] { args[0], args[1] });
            }
           
            @Override
            public Object process(OperationInternal operation) throws BabuDBException {
               
                Object[] args = operation.getParams();
               
                // parse args
                int dbId = (Integer) args[0];
                SnapshotConfig snap = (SnapshotConfig) args[1];
               
                // complete arguments
                if (dbId == InsertRecordGroup.DB_ID_UNKNOWN &&
                    operation.getDatabaseName() != null) {
                    dbId = dbs.getDatabaseManager().getDatabase(
                            operation.getDatabaseName()).getLSMDB().getDatabaseId();
                    operation.updateParams(new Object[] { dbId, snap });                 
                } else if (operation.getDatabaseName() == null) {
                    operation.updateDatabaseName(
                            dbs.getDatabaseManager().getDatabase(dbId).getName());
                }
               
                Map<String, Snapshot> snapMap = snapshotDBs.get(operation.getDatabaseName());
                if (snapMap == null) {
                    snapMap = new HashMap<String, Snapshot>();
                    snapshotDBs.put(operation.getDatabaseName(), snapMap);
                }
               
                // if the snapshot already exists ...
                if (snapMap.containsKey(snap.getName())) {
                   
                    throw new BabuDBException(ErrorCode.SNAP_EXISTS, "snapshot '" + snap.getName()
                        + "' already exists");
                }
               
                snapMap.put(snap.getName(), new Snapshot(null, dbs));
               
                // first, create new in-memory snapshots of all indices
                int[] snapIds = null;
                try {
                    dbs.getTransactionManager().lockService();
                   
                    // create the snapshot
                    snapIds = dbs.getDatabaseManager().getDatabase(dbId).getLSMDB().createSnapshot(
                            snap.getIndices());
                } catch (InterruptedException e) {
                    throw new BabuDBException(ErrorCode.INTERRUPTED, e.getMessage());
                } finally {
                    dbs.getTransactionManager().unlockService();
                }
               
                // then, enqueue a snapshot materialization request in the
                // checkpointer's queue
                dbs.getCheckpointer().addSnapshotMaterializationRequest(operation.getDatabaseName(),
                        snapIds, snap);
               
                // as long as the snapshot has not been persisted yet, add a view on
                // the current snapshot in the original database to the snapshot DB map
                synchronized (snapshotDBs) {
                   
                    Snapshot s = snapMap.get(snap.getName());
                    if (s.getView() == null) {
                        s.setView(new InMemoryView(dbs, operation.getDatabaseName(), snap,
                                snapIds));
                    }
                }
               
                return null;
            }
        });

        dbs.getTransactionManager().registerInMemoryProcessing(Operation.TYPE_DELETE_SNAP,
                new InMemoryProcessing() {
                       
            @Override
            public Object[] deserializeRequest(ReusableBuffer serialized) throws BabuDBException {
               
                byte[] payload = serialized.array();
                int offs = payload[0];
                String dbName = new String(payload, 1, offs);
                String snapName = new String(payload, offs + 1, payload.length - offs - 1);
                serialized.flip();
               
                return new Object[] { dbName, snapName };
            }
           
            @Override
            public OperationInternal convertToOperation(Object[] args) {
                return new BabuDBTransaction.BabuDBOperation(Operation.TYPE_DELETE_SNAP, (String) args[0],
                        new Object[] { args[1] });
            }

            @Override
            public Object process(OperationInternal operation) throws BabuDBException {

                // parse args
                String snapshotName = (String) operation.getParams()[0];
               
                final Map<String, Snapshot> snapMap = snapshotDBs.get(operation.getDatabaseName());
                if(snapMap == null) {
                    throw new BabuDBException(ErrorCode.NO_SUCH_SNAPSHOT,
                            "snapshot '" + snapshotName +
                            "' does not exist");
                }
               
                final Snapshot snap = snapMap.get(snapshotName);
               
                // if the snapshot does not exist ...
                if (snap == null) {
                    throw new BabuDBException(ErrorCode.NO_SUCH_SNAPSHOT,
                            "snapshot '" + snapshotName +
                            "' does not exist");
                }
               
                // shut down and remove the view
                snap.getView().shutdown();
                snapMap.remove(snapshotName);
               
                // if a snapshot materialization request is currently in the
                // checkpointer queue, remove it
                dbs.getCheckpointer().removeSnapshotMaterializationRequest(
                        operation.getDatabaseName(), snapshotName);
               
                // delete the snapshot subdirectory on disk if available
                FSUtils.delTree(new File(getSnapshotDir(operation.getDatabaseName(),
                        snapshotName)));
               
                return null;
            }
        });
    }
}
TOP

Related Classes of org.xtreemfs.babudb.snapshots.SnapshotManagerImpl

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.