Package org.voltdb

Source Code of org.voltdb.SnapshotDeleteAgent

/* This file is part of VoltDB.
* Copyright (C) 2008-2014 VoltDB Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with VoltDB.  If not, see <http://www.gnu.org/licenses/>.
*/
package org.voltdb;

import java.io.File;
import java.io.FileFilter;
import java.nio.ByteBuffer;
import java.util.List;

import org.json_voltpatches.JSONException;
import org.json_voltpatches.JSONObject;
import org.voltcore.logging.VoltLogger;
import org.voltcore.network.Connection;
import org.voltdb.VoltTable.ColumnInfo;
import org.voltdb.client.ClientResponse;
import org.voltdb.sysprocs.saverestore.SnapshotUtil;
import org.voltdb.utils.VoltFile;

/**
* Agent responsible for collecting SnapshotDelete info on this host.
*
*/
public class SnapshotDeleteAgent extends OpsAgent
{
    private static final VoltLogger SNAP_LOG = new VoltLogger("SNAPSHOT");

    public SnapshotDeleteAgent() {
        super("SnapshotDeleteAgent");
    }

    @Override
    protected void collectStatsImpl(Connection c, long clientHandle, OpsSelector selector,
            ParameterSet params) throws Exception
    {
        JSONObject obj = new JSONObject();
        obj.put("selector", "SNAPSHOTDELETE");
        String err = null;
        if (selector == OpsSelector.SNAPSHOTDELETE) {
            err = parseParams(params, obj);
        }
        else {
            err = "SnapshotDeleteAgent received non-SNAPSHOTDELETE selector: " + selector.name();
        }
        if (err != null) {
            // Maintain old @SnapshotDelete behavior.
            ColumnInfo[] result_columns = new ColumnInfo[1];
            result_columns[0] = new ColumnInfo("ERR_MSG", VoltType.STRING);
            VoltTable results[] = new VoltTable[] { new VoltTable(result_columns) };
            results[0].addRow(err);
            ClientResponseImpl errorResponse = new ClientResponseImpl(ClientResponse.SUCCESS,
                    ClientResponse.UNINITIALIZED_APP_STATUS_CODE, null, results, err);
            errorResponse.setClientHandle(clientHandle);
            ByteBuffer buf = ByteBuffer.allocate(errorResponse.getSerializedSize() + 4);
            buf.putInt(buf.capacity() - 4);
            errorResponse.flattenToBuffer(buf).flip();
            c.writeStream().enqueue(buf);
            return;
        }
        String subselector = obj.getString("subselector");

        PendingOpsRequest psr =
            new PendingOpsRequest(
                    selector,
                    subselector,
                    c,
                    clientHandle,
                    System.currentTimeMillis(),
                    obj);
        distributeOpsWork(psr, obj);
    }

    // Parse the provided parameter set object and fill in subselector and interval into
    // the provided JSONObject.  If there's an error, return that in the String, otherwise
    // return null.  Yes, ugly.  Bang it out, then refactor later.
    private String parseParams(ParameterSet params, JSONObject obj) throws Exception
    {
        if (params.size() != 2) {
            return "@SnapshotDelete expects 2 arguments, received " + params.size();
        }
        String[] paths = null;
        try {
            paths = (String[])(ParameterConverter.tryToMakeCompatible(
                        String[].class,
                        params.toArray()[0]));
        }
        catch (Exception e) {
            return e.getMessage();
        }

        if (paths == null || paths.length == 0) {
            return "No paths supplied";
        }

        for (String path : paths) {
            if (path == null || path.trim().isEmpty()) {
                return "A path was null or the empty string";
            }
        }

        String[] nonces = null;
        try {
            nonces = (String[])(ParameterConverter.tryToMakeCompatible(
                        String[].class,
                        params.toArray()[1]));
        }
        catch (Exception e) {
            return e.getMessage();
        }

        if (nonces == null || nonces.length == 0) {
            return "No nonces supplied";
        }

        for (String nonce : nonces) {
            if (nonce == null || nonce.trim().isEmpty()) {
                return "A nonce was null or the empty string";
            }
        }

        if (paths.length != nonces.length) {
            return "A path must be provided for every nonce";
        }

        // Dupe SNAPSHOTSCAN as the subselector in case we consolidate later
        obj.put("subselector", "SNAPSHOTDELETE");
        obj.put("interval", false);
        obj.put("paths", paths);
        obj.put("nonces", nonces);

        return null;
    }

    @Override
    protected void handleJSONMessage(JSONObject obj) throws Exception {
        VoltTable[] results = null;

        OpsSelector selector = OpsSelector.valueOf(obj.getString("selector").toUpperCase());
        if (selector == OpsSelector.SNAPSHOTDELETE) {
            results = dispatchSnapshotDelete(obj);
        }
        else {
            hostLog.warn("SnapshotDeleteAgent received a non-SNAPSHOTSCAN OPS selector: " + selector);
        }
        sendOpsResponse(results, obj);
    }

    private VoltTable[] dispatchSnapshotDelete(JSONObject obj) throws JSONException
    {
        VoltTable result = constructFragmentResultsTable();

        int length = obj.getJSONArray("paths").length();
        final String[] paths = new String[length];
        for (int i = 0; i < length; i++) {
            paths[i] = obj.getJSONArray("paths").getString(i);
        }
        length = obj.getJSONArray("nonces").length();
        final String[] nonces = new String[length];
        for (int i = 0; i < length; i++) {
            nonces[i] = obj.getJSONArray("nonces").getString(i);
        }

        new Thread("Async snapshot deletion thread") {
            @Override
            public void run() {
                StringBuilder sb = new StringBuilder();
                sb.append("Deleting files: ");
                for (int ii = 0; ii < paths.length; ii++) {
                    List<File> relevantFiles = retrieveRelevantFiles(paths[ii], nonces[ii]);
                    if (relevantFiles != null) {
                        for (final File f : relevantFiles) {
                            sb.append(f.getPath());
                            sb.append(',');
                            //long size = f.length();
                            f.delete();
                        }
                    }
                }
                SNAP_LOG.info(sb.toString());
            }
        }.start();

        return new VoltTable[] {result};
    }

    private final List<File> retrieveRelevantFiles(String filePath, String nonce) {
        final File path = new VoltFile(filePath);

        if (!path.exists()) {
            //m_errorString = "Provided search path does not exist: " + filePath;
            return null;
        }

        if (!path.isDirectory()) {
            //m_errorString = "Provided path exists but is not a directory: " + filePath;
            return null;
        }

        if (!path.canRead()) {
            if (!path.setReadable(true)) {
                //m_errorString = "Provided path exists but is not readable: " + filePath;
                return null;
            }
        }

        if (!path.canWrite()) {
            if (!path.setWritable(true)) {
                //m_errorString = "Provided path exists but is not writable: " + filePath;
                return null;
            }
        }

        return retrieveRelevantFiles(path, nonce);
    }

    private final List<File> retrieveRelevantFiles(File f, final String nonce) {
        assert(f.isDirectory());
        assert(f.canRead());
        assert(f.canWrite());
        return java.util.Arrays.asList(f.listFiles(new FileFilter() {

            @Override
            public boolean accept(File pathname) {
                if (pathname.isDirectory()) {
                    return false;
                }

                if (!pathname.getName().endsWith(".vpt") &&
                    !pathname.getName().endsWith(".digest") &&
                    !pathname.getName().endsWith(".jar") &&
                    !pathname.getName().endsWith(SnapshotUtil.HASH_EXTENSION) &&
                    !pathname.getName().endsWith(SnapshotUtil.COMPLETION_EXTENSION)) {
                    return false;
                }

                if (pathname.getName().startsWith(nonce)) {
                    return true;
                }
                return false;
            }
        }));
    }

    private VoltTable constructFragmentResultsTable() {
        ColumnInfo[] result_columns = new ColumnInfo[9];
        int ii = 0;
        result_columns[ii++] = new ColumnInfo(VoltSystemProcedure.CNAME_HOST_ID, VoltSystemProcedure.CTYPE_ID);
        result_columns[ii++] = new ColumnInfo("HOSTNAME", VoltType.STRING);
        result_columns[ii++] = new ColumnInfo("PATH", VoltType.STRING);
        result_columns[ii++] = new ColumnInfo("NONCE", VoltType.STRING);
        result_columns[ii++] = new ColumnInfo("NAME", VoltType.STRING);
        result_columns[ii++] = new ColumnInfo("SIZE", VoltType.BIGINT);
        result_columns[ii++] = new ColumnInfo("DELETED", VoltType.STRING);
        result_columns[ii++] = new ColumnInfo("RESULT", VoltType.STRING);
        result_columns[ii++] = new ColumnInfo("ERR_MSG", VoltType.STRING);
        return new VoltTable(result_columns);
    }
}
TOP

Related Classes of org.voltdb.SnapshotDeleteAgent

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.