/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.jini.outrigger.snaplogstore;
import com.sun.jini.outrigger.OutriggerServerImpl;
import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.jini.space.InternalSpaceException;
/**
*
* @author Sun Microsystems, Inc.
*/
class SnapshotFile extends LogFile {
private RandomAccessFile snapshotFile = null;// current snapshot file
private String fileName = null; // current snapshot file name
private String previousFilename = null; // previous snapshot
private ObjectOutputStream out; // current snapshot stream
private int suffix; // the current suffix number
/** Logger for logging persistent store related information */
private static final Logger logger =
Logger.getLogger(OutriggerServerImpl.storeLoggerName);
/**
*/
SnapshotFile(String basePath, File[] recover) throws IOException {
super(basePath);
ArrayList snapshots = new ArrayList();
suffix = existingLogs(snapshots);
// Make sure there are at most two snapshots
//
if (snapshots.size() > 2)
throw new InternalSpaceException("More than two snapshot files "+
"are present");
// If there are two snapshots, delete the second (newest) one
//
if (snapshots.size() == 2) {
File file = (File)snapshots.get(1);
file.delete();
// if there are two files and suffix==1 then we restarted while
// writing the first (real) snapshot file. So report back null
// (snapshot.0 is a dummy file) and restart the file numbers.
//
if (suffix == 1) {
suffix = 0;
recover[0] = null;
} else {
recover[0] = (File)(snapshots.get(0));
previousFilename = recover[0].getName();
}
} else if (snapshots.size() == 1) {
File file = (File)(snapshots.get(0));
previousFilename = file.getName();
// If there is one file, and the suffix==0 then we restarted
// sometime after the "file.delete()" line above and all that
// is left is the dummy .0 snapshot file.
//
if (suffix == 0)
recover[0] = null;
else
recover[0] = file;
} else { // (snapshot.size() == 0) also (suffix == -1)
// first time, so create a dummy .0 file
next();
commit();
recover[0] = null;
}
}
/**
* Switch this over to the next path in the list
*/
ObjectOutputStream next() throws IOException {
suffix++; // go to next suffix
fileName = baseFile + suffix;
snapshotFile = new RandomAccessFile(baseDir.getPath() + File.separator +
fileName, "rw");
out = new ObjectOutputStream(new LogOutputStream(snapshotFile));
return out;
}
void commit() throws IOException {
if (snapshotFile != null) {
try {
close(); // close the stream and the file
} catch (IOException ignore) { } // assume this is okay
}
// delete previous snapshot file if there was one
if (previousFilename != null) {
File file = new File(baseDir, previousFilename);
file.delete();
}
previousFilename = fileName;
}
/**
* Close the log, but don't remove it.
*/
synchronized void close() throws IOException {
if (snapshotFile != null) {
try {
out.close();
snapshotFile.close();
} finally {
snapshotFile = null;
}
}
}
/**
* Override destroy so we can try to close snapshotFile before calling
* super tries to delete all the files.
*/
void destroy() {
try {
close();
} catch (Throwable t) {
// Don't let failure keep us from deleting the files we can
}
super.destroy();
}
}