/* 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.FileFilter;
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.VoltDB;
import org.voltdb.catalog.Host;
import org.voltdb.catalog.Site;
import org.voltdb.catalog.Table;
import org.voltdb.VoltSystemProcedure;
import org.voltdb.VoltTable;
import org.voltdb.VoltTable.ColumnInfo;
import org.voltdb.VoltType;
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 SnapshotDelete extends VoltSystemProcedure {
private static final Logger LOG = Logger.getLogger(SnapshotDelete.class);
private static final int DEP_snapshotDelete = (int)
SysProcFragmentId.PF_snapshotDelete | HStoreConstants.MULTIPARTITION_DEPENDENCY;
private static final int DEP_snapshotDeleteResults = (int)
SysProcFragmentId.PF_snapshotDeleteResults;
@Override
public void initImpl() {
executor.registerPlanFragment(SysProcFragmentId.PF_snapshotDelete, this);
executor.registerPlanFragment(SysProcFragmentId.PF_snapshotDeleteResults, this);
}
private String errorString = null;
@Override
public DependencySet
executePlanFragment(Long txn_id,
Map<Integer, List<VoltTable>> dependencies,
int fragmentId,
ParameterSet params,
final SystemProcedureExecutionContext context)
{
String hostname = null; // XXX ConnectionUtil.getHostnameOrAddress();
errorString = null;
VoltTable result = constructFragmentResultsTable();
if (fragmentId == SysProcFragmentId.PF_snapshotDelete)
{
// Choose the lowest site ID on this host to do the deletion.
// All other sites should just return empty results tables.
Host catalog_host = context.getHost();
Site catalog_site = CollectionUtil.first(CatalogUtil.getSitesForHost(catalog_host));
Integer lowest_site_id = catalog_site.getId();
LOG.trace("Site id :"+context.getPartitionExecutor().getSiteId());
int partition_id = context.getPartitionExecutor().getPartitionId();
LOG.trace("Partition Id : " + partition_id);
if (context.getPartitionExecutor().getSiteId() == lowest_site_id)
{
assert(params.toArray()[0] != null);
assert(params.toArray()[0] instanceof String[]);
assert(((String[])params.toArray()[0]).length > 0);
assert(params.toArray()[1] != null);
assert(params.toArray()[1] instanceof String[]);
assert(((String[])params.toArray()[1]).length > 0);
assert(((String[])params.toArray()[0]).length == ((String[])params.toArray()[1]).length);
final String paths[] = (String[])params.toArray()[0];
final String nonces[] = (String[])params.toArray()[1];
for (int ii = 0; ii < paths.length; ii++) {
List<File> relevantFiles = retrieveRelevantFiles(paths[ii], nonces[ii]);
if (relevantFiles == null) {
result.addRow(
Integer.parseInt(context.getSite().getHost().getTypeName().replaceAll("[\\D]", "")),
hostname,
paths[ii],
nonces[ii],
"",
0,
"FALSE",
"FAILURE",
errorString);
} else {
for (final File f : relevantFiles) {
long size = f.length();
boolean deleted = f.delete();
result.addRow(
Integer.parseInt(context.getSite().getHost().getTypeName().replaceAll("[\\D]", "")),
hostname,
paths[ii],
nonces[ii],
f.getName(),
size,
deleted ? "TRUE": "FALSE",
"SUCESS",
"");
}
}
}
}
return new DependencySet( DEP_snapshotDelete, result);
} else if (fragmentId == SysProcFragmentId.PF_snapshotDeleteResults) {
final VoltTable results = constructFragmentResultsTable();
LOG.trace("Aggregating Snapshot Delete results");
assert (dependencies.size() > 0);
List<VoltTable> dep = dependencies.get(DEP_snapshotDelete);
for (VoltTable table : dep)
{
while (table.advanceRow())
{
// this will add the active row of table
results.add(table);
}
}
return new DependencySet( DEP_snapshotDeleteResults, results);
}
assert (false);
return null;
}
private VoltTable constructFragmentResultsTable() {
ColumnInfo[] result_columns = new ColumnInfo[9];
int ii = 0;
result_columns[ii++] = new ColumnInfo(CNAME_HOST_ID, 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);
}
public VoltTable[] run(String paths[], String nonces[]) throws VoltAbortException
{
final long startTime = System.currentTimeMillis();
VoltTable results[] = new VoltTable[1];
ColumnInfo[] result_columns = new ColumnInfo[1];
int ii = 0;
result_columns[ii++] = new ColumnInfo("ERR_MSG", VoltType.STRING);
results[0] = new VoltTable(result_columns);
if (paths == null || paths.length == 0) {
results[0].addRow("No paths supplied");
return results;
}
for (String path : paths) {
if (path == null || path.equals("")) {
results[0].addRow("A path was null or the empty string");
return results;
}
}
if (nonces == null || nonces.length == 0) {
results[0].addRow("No nonces supplied");
return results;
}
for (String nonce : nonces) {
if (nonce == null || nonce.equals("")) {
results[0].addRow("A nonce was null or the empty string");
return results;
}
}
if (paths.length != nonces.length) {
results[0].addRow("A path must be provided for every nonce");
return results;
}
results = performSnapshotDeleteWork( paths, nonces);
final long endTime = System.currentTimeMillis();
final long duration = endTime -startTime;
LOG.info("Finished deleting snapshots. Took " + duration + " milliseconds");
return results;
}
private final List<File> retrieveRelevantFiles(String filePath, String nonce) {
final File path = new File(filePath);
if (!path.exists()) {
errorString = "Provided search path does not exist: " + filePath;
return null;
}
if (!path.isDirectory()) {
errorString = "Provided path exists but is not a directory: " + filePath;
return null;
}
if (!path.canRead()) {
if (!path.setReadable(true)) {
errorString = "Provided path exists but is not readable: " + filePath;
return null;
}
}
if (!path.canWrite()) {
if (!path.setWritable(true)) {
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());
final String digestName =
SnapshotUtil.constructDigestFilenameForNonce(nonce.substring(0, nonce.lastIndexOf('-')));
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")) {
return false;
}
if (pathname.getName().startsWith(nonce) || pathname.getName().equals(digestName)) {
return true;
}
return false;
}
}));
}
private final VoltTable[] performSnapshotDeleteWork(String paths[], String nonces[])
{
String nonceWithSeparators[] = new String[nonces.length];
for (int ii = 0; ii < nonces.length; ii++) {
nonceWithSeparators[ii] = nonces[ii] + "-";
}
SynthesizedPlanFragment[] pfs = new SynthesizedPlanFragment[2];
pfs[0] = new SynthesizedPlanFragment();
pfs[0].fragmentId = SysProcFragmentId.PF_snapshotDelete;
pfs[0].outputDependencyIds = new int[]{ DEP_snapshotDelete };
pfs[0].multipartition = true;
ParameterSet params = new ParameterSet();
params.setParameters(paths, nonceWithSeparators);
pfs[0].parameters = params;
pfs[1] = new SynthesizedPlanFragment();
pfs[1].fragmentId = SysProcFragmentId.PF_snapshotDeleteResults;
pfs[1].outputDependencyIds = new int[]{ DEP_snapshotDeleteResults };
pfs[1].inputDependencyIds = new int[] { DEP_snapshotDelete };
pfs[1].multipartition = false;
pfs[1].parameters = new ParameterSet();
VoltTable[] results;
results = executeSysProcPlanFragments(pfs, DEP_snapshotDeleteResults);
return results;
}
}