Package org.voltdb.sysprocs

Source Code of org.voltdb.sysprocs.SnapshotSave

/* This file is part of VoltDB.
* Copyright (C) 2008-2010 VoltDB Inc.
*
* VoltDB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* VoltDB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with VoltDB.  If not, see <http://www.gnu.org/licenses/>.
*/

package org.voltdb.sysprocs;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.voltdb.DependencySet;
import org.voltdb.ParameterSet;
import org.voltdb.ProcInfo;
import org.voltdb.SnapshotSaveAPI;
import org.voltdb.SnapshotSiteProcessor;
import org.voltdb.VoltSystemProcedure;
import org.voltdb.VoltTable;
import org.voltdb.VoltTable.ColumnInfo;
import org.voltdb.VoltType;
import org.voltdb.catalog.CatalogMap;
import org.voltdb.catalog.Host;
import org.voltdb.catalog.Partition;
import org.voltdb.catalog.Site;
import org.voltdb.catalog.Table;
import org.voltdb.client.ConnectionUtil;
import org.voltdb.sysprocs.saverestore.SnapshotUtil;

import edu.brown.catalog.CatalogUtil;
import edu.brown.hstore.HStoreConstants;
import edu.brown.hstore.PartitionExecutor.SystemProcedureExecutionContext;
import edu.brown.utils.CollectionUtil;

@ProcInfo(singlePartition = false)
public class SnapshotSave extends VoltSystemProcedure {
    private static final Logger LOG = Logger.getLogger(SnapshotSave.class);

    private static final int DEP_saveTest = (int) SysProcFragmentId.PF_saveTest | HStoreConstants.MULTIPARTITION_DEPENDENCY;
    private static final int DEP_saveTestResults = (int) SysProcFragmentId.PF_saveTestResults;
    private static final int DEP_createSnapshotTargets = (int) SysProcFragmentId.PF_createSnapshotTargets | HStoreConstants.MULTIPARTITION_DEPENDENCY;
    private static final int DEP_createSnapshotTargetsResults = (int) SysProcFragmentId.PF_createSnapshotTargetsResults;

    public static final ColumnInfo nodeResultsColumns[] = new ColumnInfo[] {
            new ColumnInfo(CNAME_HOST_ID, CTYPE_ID),
            new ColumnInfo("HOSTNAME", VoltType.STRING),
            new ColumnInfo(CNAME_SITE_ID, CTYPE_ID),
            new ColumnInfo(CNAME_PARTITION_ID, CTYPE_ID),
            new ColumnInfo("TABLE", VoltType.STRING),
            new ColumnInfo("RESULT", VoltType.STRING),
            new ColumnInfo("ERR_MSG", VoltType.STRING) };

    public static final ColumnInfo partitionResultsColumns[] = new ColumnInfo[] {
            new ColumnInfo(CNAME_HOST_ID, CTYPE_ID),
            new ColumnInfo("HOSTNAME", VoltType.STRING),
            new ColumnInfo(CNAME_SITE_ID, CTYPE_ID),
            new ColumnInfo(CNAME_PARTITION_ID, CTYPE_ID),
            new ColumnInfo("TABLE", VoltType.STRING),            
            new ColumnInfo("RESULT", VoltType.STRING),
            new ColumnInfo("ERR_MSG", VoltType.STRING) };

    public static final VoltTable constructNodeResultsTable() {
        return new VoltTable(nodeResultsColumns);
    }

    public static final VoltTable constructPartitionResultsTable() {
        return new VoltTable(partitionResultsColumns);
    }

    @Override
    public void initImpl() {
        this.registerPlanFragment(SysProcFragmentId.PF_saveTest);
        this.registerPlanFragment(SysProcFragmentId.PF_saveTestResults);
        this.registerPlanFragment(SysProcFragmentId.PF_createSnapshotTargets);
        this.registerPlanFragment(SysProcFragmentId.PF_createSnapshotTargetsResults);
    }

    @Override
    public DependencySet executePlanFragment(Long txn_id, Map<Integer, List<VoltTable>> dependencies, int fragmentId, ParameterSet params, SystemProcedureExecutionContext context) {
        String hostname = ConnectionUtil.getHostnameOrAddress();
        if (fragmentId == SysProcFragmentId.PF_saveTest) {
            assert (params.toArray()[0] != null);
            assert (params.toArray()[1] != null);
            String file_path = (String) params.toArray()[0];
            String file_nonce = (String) params.toArray()[1];
            return saveTest(file_path, file_nonce, context, hostname);
        } else if (fragmentId == SysProcFragmentId.PF_saveTestResults) {
            return saveTestResults(dependencies);
        } else if (fragmentId == SysProcFragmentId.PF_createSnapshotTargets) {
            LOG.trace("createSnapshotTargets :: Starts at partition : " + context.getPartitionExecutor().getPartitionId());

            assert (params.toArray()[0] != null);
            assert (params.toArray()[1] != null);
            assert (params.toArray()[2] != null);
            assert (params.toArray()[3] != null);
            final String file_path = (String) params.toArray()[0];
            final String file_nonce = (String) params.toArray()[1];
            final long startTime = (Long) params.toArray()[2];
            byte block = (Byte) params.toArray()[3];
            SnapshotSaveAPI saveAPI = new SnapshotSaveAPI();
            VoltTable result = saveAPI.startSnapshotting(file_path, file_nonce, block, startTime, context, hostname);

            LOG.trace("createSnapshotTargets :: Ends at partition : " + context.getPartitionExecutor().getPartitionId() + "\n" + result);
            return new DependencySet(SnapshotSave.DEP_createSnapshotTargets, result);
        } else if (fragmentId == SysProcFragmentId.PF_createSnapshotTargetsResults) {
            return createSnapshotTargetsResults(dependencies);
        }
        assert (false);
        return null;
    }

    private DependencySet createSnapshotTargetsResults(Map<Integer, List<VoltTable>> dependencies) {
        {
            LOG.trace("Aggregating create snapshot target results");
            assert (dependencies.size() > 0);
            List<VoltTable> dep = dependencies.get(DEP_createSnapshotTargets);
            VoltTable result = null;
            for (VoltTable table : dep) {
                /**
                 * XXX Ning: There are two different tables here. We have to
                 * detect which table we are looking at in order to create the
                 * result table with the proper schema. Maybe we should make the
                 * result table consistent?
                 */
                if (result == null) {
                    if (table.getColumnType(2).equals(VoltType.INTEGER))
                        result = constructPartitionResultsTable();
                    else
                        result = constructNodeResultsTable();
                }

                while (table.advanceRow()) {
                    // this will add the active row of table
                    result.add(table);
                }
            }

            LOG.trace("createSnapshotTargetsResults : " + "\n" + result);
            return new DependencySet(DEP_createSnapshotTargetsResults, result);
        }
    }

    private DependencySet saveTest(String file_path, String file_nonce, SystemProcedureExecutionContext context, String hostname) {
        {
            VoltTable result = constructNodeResultsTable();
            // Choose the lowest site ID on this host to do the file scan
            // All other sites should just return empty results tables.
            Host catalog_host = context.getHost();
            Site site = context.getSite();

            CatalogMap<Partition> partition_map = site.getPartitions();
            Integer lowest_partition_id = Integer.MAX_VALUE, p_id;
            Integer lowest_site_id = Integer.MAX_VALUE, s_id;
           
            for(Site st : CatalogUtil.getAllSites(catalog_host)){
                s_id = st.getId();
                lowest_site_id = Math.min(s_id, lowest_site_id);
            }
           
            for(Partition pt : partition_map){
                p_id = pt.getId();
                lowest_partition_id = Math.min(p_id, lowest_partition_id);
            }
           
            assert(lowest_partition_id != Integer.MAX_VALUE);
           
            //LOG.trace("Partition id :" + context.getPartitionExecutor().getPartitionId());
            //LOG.trace("Lowest Partition id :" + lowest_partition_id);

            // Do it at partition with lowest partition id on site with lowest site id
            // as we can have multiple partitions per site in HStore
            if (context.getSite().getId() == lowest_site_id && context.getPartitionExecutor().getPartitionId() == lowest_partition_id) {

               LOG.trace("Checking feasibility of save with path and nonce: " + file_path + ", " + file_nonce);
               LOG.trace("ExecutionSitesCurrentlySnapshotting check : " + SnapshotSiteProcessor.ExecutionSitesCurrentlySnapshotting.get());

                // CHANGE : Only 1 Site doing this
                if (SnapshotSiteProcessor.ExecutionSitesCurrentlySnapshotting.get() != -1) {
                    result.addRow(Integer.parseInt(context.getSite().getHost().getTypeName().replaceAll("[\\D]", "")), hostname, "", "FAILURE", "SNAPSHOT IN PROGRESS");
                    return new DependencySet(DEP_saveTest, result);
                }

                for (Table table : SnapshotUtil.getTablesToSave(context.getDatabase())) {
                    File saveFilePath = SnapshotUtil.constructFileForTable(table, file_path, file_nonce,
                            String.valueOf(context.getHost().getId()),                                
                            String.valueOf(context.getHStoreSite().getSiteId()),
                            String.valueOf(context.getPartitionExecutor().getPartitionId())
                            );
                    LOG.trace("Host ID " + context.getSite().getHost().getTypeName() + " table: " + table.getTypeName() + " to path: " + saveFilePath);
                    String file_valid = "SUCCESS";
                    String err_msg = "";
                    if (saveFilePath.exists()) {
                        file_valid = "FAILURE";
                        err_msg = "SAVE FILE ALREADY EXISTS: " + saveFilePath;
                    } else if (!saveFilePath.getParentFile().canWrite()) {
                        file_valid = "FAILURE";
                        err_msg = "FILE LOCATION UNWRITABLE: " + saveFilePath;
                    } else {
                        try {
                            saveFilePath.createNewFile();
                        } catch (IOException ex) {
                            file_valid = "FAILURE";
                            err_msg = "FILE CREATION OF " + saveFilePath + "RESULTED IN IOException: " + ex.getMessage();
                        }
                    }
                    result.addRow(catalog_host.getId(), hostname, context.getHStoreSite().getSiteId(), context.getPartitionExecutor().getPartitionId(),  table.getTypeName(), file_valid, err_msg);
                }
            }
            //LOG.trace("Host ID " + context.getSite().getHost().getTypeName() + "\n" + new DependencySet(DEP_saveTest, result));
            return new DependencySet(DEP_saveTest, result);
        }
    }

    private DependencySet saveTestResults(Map<Integer, List<VoltTable>> dependencies) {
        {
            LOG.trace("Aggregating save feasiblity results");
            assert (dependencies.size() > 0);
            List<VoltTable> dep = dependencies.get(DEP_saveTest);
            VoltTable result = constructNodeResultsTable();
            for (VoltTable table : dep) {
                while (table.advanceRow()) {
                    // this will add the active row of table
                    result.add(table);
                }
            }
            return new DependencySet(DEP_saveTestResults, result);
        }
    }

    public VoltTable[] run(String path, String nonce, long block) throws VoltAbortException {
        final long startTime = System.currentTimeMillis();
        LOG.info("Saving database to path: " + path + ", ID: " + nonce + " at " + startTime);

        if (path == null || path.equals("")) {
            ColumnInfo[] result_columns = new ColumnInfo[1];
            int ii = 0;
            result_columns[ii++] = new ColumnInfo("ERR_MSG", VoltType.STRING);
            VoltTable results[] = new VoltTable[] { new VoltTable(result_columns) };
            results[0].addRow("Provided path was null or the empty string");
            return results;
        }

        if (nonce == null || nonce.equals("")) {
            ColumnInfo[] result_columns = new ColumnInfo[1];
            int ii = 0;
            result_columns[ii++] = new ColumnInfo("ERR_MSG", VoltType.STRING);
            VoltTable results[] = new VoltTable[] { new VoltTable(result_columns) };
            results[0].addRow("Provided nonce was null or the empty string");
            return results;
        }

        if (nonce.contains("-") || nonce.contains(",")) {
            ColumnInfo[] result_columns = new ColumnInfo[1];
            int ii = 0;
            result_columns[ii++] = new ColumnInfo("ERR_MSG", VoltType.STRING);
            VoltTable results[] = new VoltTable[] { new VoltTable(result_columns) };
            results[0].addRow("Provided nonce " + nonce + " contains a prohitibited character (- or ,)");
            return results;
        }

        // See if we think the save will succeed
        VoltTable[] results;
        results = performSaveFeasibilityWork(path, nonce);
        if (results.length >= 1)
            LOG.info("performSaveFeasibilityWork Results: " + results[0]);

        // Test feasibility results for fail
        while (results[0].advanceRow()) {
            if (results[0].getString("RESULT").equals("FAILURE")) {
                // Something lost, bomb out and just return the whole
                // table of results to the client for analysis
                LOG.info("Row : " + results[0].getString("RESULT"));
                return results;
            }
        }

        results = performSnapshotCreationWork(path, nonce, startTime, (byte) block);

        final long finishTime = System.currentTimeMillis();
        final long duration = finishTime - startTime;
        LOG.info("Snapshot initiation took " + duration + " milliseconds");
        return results;
    }

    private final VoltTable[] performSaveFeasibilityWork(String filePath, String fileNonce) {
        SynthesizedPlanFragment[] pfs = new SynthesizedPlanFragment[2];

        // This fragment causes each execution site to confirm the likely
        // success of writing tables to disk
        pfs[0] = new SynthesizedPlanFragment();
        pfs[0].fragmentId = SysProcFragmentId.PF_saveTest;
        pfs[0].outputDependencyIds = new int[] { DEP_saveTest };
        pfs[0].inputDependencyIds = new int[] {};
        pfs[0].multipartition = true;
        ParameterSet params = new ParameterSet();
        params.setParameters(filePath, fileNonce);
        pfs[0].parameters = params;

        // This fragment aggregates the save-to-disk sanity check results
        pfs[1] = new SynthesizedPlanFragment();
        pfs[1].fragmentId = SysProcFragmentId.PF_saveTestResults;
        pfs[1].outputDependencyIds = new int[] { DEP_saveTestResults };
        pfs[1].inputDependencyIds = new int[] { DEP_saveTest };
        pfs[1].multipartition = false;
        pfs[1].parameters = new ParameterSet();

        VoltTable[] results;
        results = executeSysProcPlanFragments(pfs, DEP_saveTestResults);
        return results;
    }

    private final VoltTable[] performSnapshotCreationWork(String filePath, String fileNonce, long startTime, byte block) {
        SynthesizedPlanFragment[] pfs = new SynthesizedPlanFragment[2];

        LOG.trace("performSnapshotCreationWork starting");

        // This fragment causes each execution site to confirm the likely
        // success of writing tables to disk
        pfs[0] = new SynthesizedPlanFragment();
        pfs[0].fragmentId = SysProcFragmentId.PF_createSnapshotTargets;
        pfs[0].outputDependencyIds = new int[] { DEP_createSnapshotTargets };
        pfs[0].inputDependencyIds = new int[] {};
        pfs[0].multipartition = true;
        ParameterSet params = new ParameterSet();
        params.setParameters(filePath, fileNonce, startTime, block);
        pfs[0].parameters = params;

        // This fragment aggregates the save-to-disk sanity check results
        pfs[1] = new SynthesizedPlanFragment();
        pfs[1].fragmentId = SysProcFragmentId.PF_createSnapshotTargetsResults;
        pfs[1].outputDependencyIds = new int[] { DEP_createSnapshotTargetsResults };
        pfs[1].inputDependencyIds = new int[] { DEP_createSnapshotTargets };
        pfs[1].multipartition = false;
        pfs[1].parameters = new ParameterSet();

        VoltTable[] results;
        results = executeSysProcPlanFragments(pfs, DEP_createSnapshotTargetsResults);
        return results;
    }
}
TOP

Related Classes of org.voltdb.sysprocs.SnapshotSave

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.