/* This file is part of VoltDB.
* Copyright (C) 2008-2017 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.sysprocs;
import java.util.HashMap;
import java.util.TreeSet;
import java.util.Iterator;
import org.voltdb.SnapshotFormat;
import org.voltdb.sysprocs.saverestore.SnapshotUtil;
/**
* The snapshot registry contains information about snapshots that executed
* while the system was running.
*
*/
public class SnapshotRegistry {
private static final int m_maxStatusHistory = 10;
private static final TreeSet<Snapshot> m_snapshots = new TreeSet<Snapshot>(
new java.util.Comparator<Snapshot>() {
@Override
public int compare(Snapshot o1, Snapshot o2) {
return Long.valueOf(o1.txnId).compareTo(o2.txnId);
}
});
public static class Snapshot {
public final long txnId;
public final long timeStarted;
public final long timeFinished;
public final String path;
public final String nonce;
public final boolean result; //true success, false failure
public final long bytesWritten;
public final SnapshotFormat format;
private final HashMap< String, Table> tables = new HashMap< String, Table>();
private Snapshot(long txnId, long timeStarted, int hostId, String path, String nonce,
SnapshotFormat format,
org.voltdb.catalog.Table tables[]) {
this.txnId = txnId;
this.timeStarted = timeStarted;
this.path = path;
this.nonce = nonce;
this.format = format;
timeFinished = 0;
synchronized (this.tables) {
for (org.voltdb.catalog.Table table : tables) {
String filename =
SnapshotUtil.constructFilenameForTable(
table,
nonce,
format,
hostId);
this.tables.put(table.getTypeName(), new Table(table.getTypeName(), filename));
}
}
result = false;
bytesWritten = 0;
}
private Snapshot(Snapshot incomplete, long timeFinished) {
txnId = incomplete.txnId;
timeStarted = incomplete.timeStarted;
path = incomplete.path;
nonce = incomplete.nonce;
format = incomplete.format;
this.timeFinished = timeFinished;
synchronized (tables) {
tables.putAll(incomplete.tables);
}
long bytesWritten = 0;
boolean result = true;
for (Table t : tables.values()) {
bytesWritten += t.size;
if (t.error != null) {
result = false;
}
}
this.bytesWritten = bytesWritten;
this.result = result;
}
public interface TableUpdater {
public Table update(Table t);
}
public interface TableIterator {
public void next(Table t);
}
public void iterateTables(TableIterator ti) {
synchronized (tables) {
for (Table t : tables.values()) {
ti.next(t);
}
}
}
public void updateTable(String name, TableUpdater tu) {
synchronized (tables) {
assert(tables.get(name) != null);
tables.put(name, tu.update(tables.get(name)));
}
}
public Table removeTable(String name) {
synchronized (tables) {
return tables.remove(name);
}
}
public class Table {
public final String name;
public final String filename;
public final long size;
public final Throwable error;
private Table(String name, String filename) {
this.name = name;
this.filename = filename;
size = 0;
error = null;
}
public Table(Table t, long size, Throwable error) {
this.name = t.name;
this.filename = t.filename;
this.size = size;
this.error = error;
}
}
}
public static synchronized Snapshot startSnapshot(
long txnId,
int hostId,
String path,
String nonce,
SnapshotFormat format,
org.voltdb.catalog.Table tables[]) {
final Snapshot s = new Snapshot(txnId, System.currentTimeMillis(),
hostId, path, nonce, format, tables);
m_snapshots.add(s);
if (m_snapshots.size() > m_maxStatusHistory) {
Iterator<Snapshot> iter = m_snapshots.iterator();
iter.next();
iter.remove();
}
return s;
}
public static synchronized void discardSnapshot(Snapshot s) {
m_snapshots.remove(s);
}
public static synchronized Snapshot finishSnapshot(Snapshot incomplete) {
boolean removed = m_snapshots.remove(incomplete);
assert(removed);
final Snapshot completed = new Snapshot(incomplete, System.currentTimeMillis());
m_snapshots.add(completed);
return completed;
}
public static synchronized TreeSet<Snapshot> getSnapshotHistory() {
return new TreeSet<Snapshot>(m_snapshots);
}
public static synchronized void clear() {
m_snapshots.clear();
}
}