feat(jdk8): move files to new folder to avoid resources compiled.
This commit is contained in:
140
jdkSrc/jdk8/sun/rmi/log/LogHandler.java
Normal file
140
jdkSrc/jdk8/sun/rmi/log/LogHandler.java
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.log;
|
||||
|
||||
import java.io.*;
|
||||
import sun.rmi.server.MarshalOutputStream;
|
||||
import sun.rmi.server.MarshalInputStream;
|
||||
|
||||
/**
|
||||
* A LogHandler represents snapshots and update records as serializable
|
||||
* objects.
|
||||
*
|
||||
* This implementation does not know how to create an initial snaphot or
|
||||
* apply an update to a snapshot. The client must specifiy these methods
|
||||
* via a subclass.
|
||||
*
|
||||
* @see ReliableLog
|
||||
*
|
||||
* @author Ann Wollrath
|
||||
*/
|
||||
public abstract
|
||||
class LogHandler {
|
||||
|
||||
/**
|
||||
* Creates a LogHandler for a ReliableLog.
|
||||
*/
|
||||
public LogHandler() {}
|
||||
|
||||
/**
|
||||
* Creates and returns the initial state of data structure that needs
|
||||
* to be stably stored. This method is called when a ReliableLog is
|
||||
* created.
|
||||
* @return the initial state
|
||||
* @exception Exception can raise any exception
|
||||
*/
|
||||
public abstract
|
||||
Object initialSnapshot() throws Exception;
|
||||
|
||||
/**
|
||||
* Writes the snapshot object to a stream. This callback is
|
||||
* invoked when the client calls the snaphot method of ReliableLog.
|
||||
* @param out the output stream
|
||||
* @param value the snapshot
|
||||
* @exception Exception can raise any exception
|
||||
*/
|
||||
public
|
||||
void snapshot(OutputStream out, Object value) throws Exception {
|
||||
MarshalOutputStream s = new MarshalOutputStream(out);
|
||||
s.writeObject(value);
|
||||
s.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the snapshot object from a stream and returns the snapshot.
|
||||
* This callback is invoked when the client calls the recover method
|
||||
* of ReliableLog.
|
||||
* @param in the input stream
|
||||
* @return the state (snapshot)
|
||||
* @exception Exception can raise any exception
|
||||
*/
|
||||
|
||||
public
|
||||
Object recover(InputStream in) throws Exception {
|
||||
MarshalInputStream s = new MarshalInputStream(in);
|
||||
return s.readObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the representation (a serializable object) of an update
|
||||
* to a stream. This callback is invoked when the client calls the
|
||||
* update method of ReliableLog.
|
||||
* @param out the output stream
|
||||
* @param value the snapshot
|
||||
* @exception Exception can raise any exception
|
||||
*/
|
||||
public
|
||||
void writeUpdate(LogOutputStream out, Object value) throws Exception {
|
||||
|
||||
MarshalOutputStream s = new MarshalOutputStream(out);
|
||||
s.writeObject(value);
|
||||
s.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a stably logged update (a serializable object) from a
|
||||
* stream. This callback is invoked during recovery, once for
|
||||
* every record in the log. After reading the update, this method
|
||||
* invokes the applyUpdate (abstract) method in order to obtain
|
||||
* the new snapshot value. It then returns the new snapshot.
|
||||
*
|
||||
* @param in the input stream
|
||||
* @param state the current state
|
||||
* @return the new state
|
||||
* @exception Exception can raise any exception
|
||||
*/
|
||||
public
|
||||
Object readUpdate(LogInputStream in, Object state) throws Exception {
|
||||
MarshalInputStream s = new MarshalInputStream(in);
|
||||
return applyUpdate(s.readObject(), state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a stably logged update (a serializable object) from a stream.
|
||||
* This callback is invoked during recovery, once for every record in the
|
||||
* log. After reading the update, this method is invoked in order to
|
||||
* obtain the new snapshot value. The method should apply the update
|
||||
* object to the current state <code>state</code> and return the new
|
||||
* state (the new snapshot value).
|
||||
* @param update the update object
|
||||
* @param state the current state
|
||||
* @return the new state
|
||||
* @exception Exception can raise any exception
|
||||
*/
|
||||
public abstract
|
||||
Object applyUpdate(Object update, Object state) throws Exception;
|
||||
|
||||
}
|
||||
134
jdkSrc/jdk8/sun/rmi/log/LogInputStream.java
Normal file
134
jdkSrc/jdk8/sun/rmi/log/LogInputStream.java
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 1999, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.log;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public
|
||||
class LogInputStream extends InputStream {
|
||||
private InputStream in;
|
||||
private int length;
|
||||
|
||||
/**
|
||||
* Creates a log input file with the specified system dependent
|
||||
* file descriptor.
|
||||
* @param fd the system dependent file descriptor
|
||||
* @param length the total number of bytes allowed to be read
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
public LogInputStream(InputStream in, int length) throws IOException {
|
||||
this.in = in;
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a byte of data. This method will block if no input is
|
||||
* available.
|
||||
* @return the byte read, or -1 if the end of the log or end of the
|
||||
* stream is reached.
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
public int read() throws IOException {
|
||||
if (length == 0)
|
||||
return -1;
|
||||
int c = in.read();
|
||||
length = (c != -1) ? length - 1 : 0;
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads data into an array of bytes.
|
||||
* This method blocks until some input is available.
|
||||
* @param b the buffer into which the data is read
|
||||
* @return the actual number of bytes read, or -1 if the end of the log
|
||||
* or end of the stream is reached.
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
public int read(byte b[]) throws IOException {
|
||||
return read(b, 0, b.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads data into an array of bytes.
|
||||
* This method blocks until some input is available.
|
||||
* @param b the buffer into which the data is read
|
||||
* @param off the start offset of the data
|
||||
* @param len the maximum number of bytes read
|
||||
* @return the actual number of bytes read, or -1 if the end of the log or
|
||||
* end of the stream is reached.
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
public int read(byte b[], int off, int len) throws IOException {
|
||||
if (length == 0)
|
||||
return -1;
|
||||
len = (length < len) ? length : len;
|
||||
int n = in.read(b, off, len);
|
||||
length = (n != -1) ? length - n : 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips n bytes of input.
|
||||
* @param n the number of bytes to be skipped
|
||||
* @return the actual number of bytes skipped.
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
public long skip(long n) throws IOException {
|
||||
if (n > Integer.MAX_VALUE)
|
||||
throw new IOException("Too many bytes to skip - " + n);
|
||||
if (length == 0)
|
||||
return 0;
|
||||
n = (length < n) ? length : n;
|
||||
n = in.skip(n);
|
||||
length -= n;
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bytes that can be read without blocking.
|
||||
* @return the number of available bytes, which is initially
|
||||
* equal to the file size.
|
||||
*/
|
||||
public int available() throws IOException {
|
||||
int avail = in.available();
|
||||
return (length < avail) ? length : avail;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the input stream. No further input can be read.
|
||||
* the stream.
|
||||
*/
|
||||
public void close() {
|
||||
length = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the stream when garbage is collected.
|
||||
*/
|
||||
protected void finalize() throws IOException {
|
||||
close();
|
||||
}
|
||||
}
|
||||
83
jdkSrc/jdk8/sun/rmi/log/LogOutputStream.java
Normal file
83
jdkSrc/jdk8/sun/rmi/log/LogOutputStream.java
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 1997, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.log;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public
|
||||
class LogOutputStream extends OutputStream {
|
||||
|
||||
private RandomAccessFile raf;
|
||||
|
||||
/**
|
||||
* Creates an output file with the specified system dependent
|
||||
* file descriptor.
|
||||
* @param fd the system dependent file descriptor
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
public LogOutputStream(RandomAccessFile raf) throws IOException {
|
||||
this.raf = raf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a byte of data. This method will block until the byte is
|
||||
* actually written.
|
||||
* @param b the byte to be written
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
public void write(int b) throws IOException {
|
||||
raf.write(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an array of bytes. Will block until the bytes
|
||||
* are actually written.
|
||||
* @param b the data to be written
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
public void write(byte b[]) throws IOException {
|
||||
raf.write(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a sub array of bytes.
|
||||
* @param b the data to be written
|
||||
* @param off the start offset in the data
|
||||
* @param len the number of bytes that are written
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
public void write(byte b[], int off, int len) throws IOException {
|
||||
raf.write(b, off, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Can not close a LogOutputStream, so this does nothing.
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
public final void close() throws IOException {
|
||||
}
|
||||
|
||||
}
|
||||
824
jdkSrc/jdk8/sun/rmi/log/ReliableLog.java
Normal file
824
jdkSrc/jdk8/sun/rmi/log/ReliableLog.java
Normal file
@@ -0,0 +1,824 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.log;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.rmi.server.RMIClassLoader;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import sun.security.action.GetBooleanAction;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
/**
|
||||
* This class is a simple implementation of a reliable Log. The
|
||||
* client of a ReliableLog must provide a set of callbacks (via a
|
||||
* LogHandler) that enables a ReliableLog to read and write
|
||||
* checkpoints and log records. This implementation ensures that the
|
||||
* current value of the data stored (via a ReliableLog) is recoverable
|
||||
* after a system crash. <p>
|
||||
*
|
||||
* The secondary storage strategy is to record values in files using a
|
||||
* representation of the caller's choosing. Two sorts of files are
|
||||
* kept: snapshots and logs. At any instant, one snapshot is current.
|
||||
* The log consists of a sequence of updates that have occurred since
|
||||
* the current snapshot was taken. The current stable state is the
|
||||
* value of the snapshot, as modified by the sequence of updates in
|
||||
* the log. From time to time, the client of a ReliableLog instructs
|
||||
* the package to make a new snapshot and clear the log. A ReliableLog
|
||||
* arranges disk writes such that updates are stable (as long as the
|
||||
* changes are force-written to disk) and atomic : no update is lost,
|
||||
* and each update either is recorded completely in the log or not at
|
||||
* all. Making a new snapshot is also atomic. <p>
|
||||
*
|
||||
* Normal use for maintaining the recoverable store is as follows: The
|
||||
* client maintains the relevant data structure in virtual memory. As
|
||||
* updates happen to the structure, the client informs the ReliableLog
|
||||
* (all it "log") by calling log.update. Periodically, the client
|
||||
* calls log.snapshot to provide the current value of the data
|
||||
* structure. On restart, the client calls log.recover to obtain the
|
||||
* latest snapshot and the following sequences of updates; the client
|
||||
* applies the updates to the snapshot to obtain the state that
|
||||
* existed before the crash. <p>
|
||||
*
|
||||
* The current logfile format is: <ol>
|
||||
* <li> a format version number (two 4-octet integers, major and
|
||||
* minor), followed by
|
||||
* <li> a sequence of log records. Each log record contains, in
|
||||
* order, <ol>
|
||||
* <li> a 4-octet integer representing the length of the following log
|
||||
* data,
|
||||
* <li> the log data (variable length). </ol> </ol> <p>
|
||||
*
|
||||
* @see LogHandler
|
||||
*
|
||||
* @author Ann Wollrath
|
||||
*
|
||||
*/
|
||||
public class ReliableLog {
|
||||
|
||||
public final static int PreferredMajorVersion = 0;
|
||||
public final static int PreferredMinorVersion = 2;
|
||||
|
||||
// sun.rmi.log.debug=false
|
||||
private boolean Debug = false;
|
||||
|
||||
private static String snapshotPrefix = "Snapshot.";
|
||||
private static String logfilePrefix = "Logfile.";
|
||||
private static String versionFile = "Version_Number";
|
||||
private static String newVersionFile = "New_Version_Number";
|
||||
private static int intBytes = 4;
|
||||
private static long diskPageSize = 512;
|
||||
|
||||
private File dir; // base directory
|
||||
private int version = 0; // current snapshot and log version
|
||||
private String logName = null;
|
||||
private LogFile log = null;
|
||||
private long snapshotBytes = 0;
|
||||
private long logBytes = 0;
|
||||
private int logEntries = 0;
|
||||
private long lastSnapshot = 0;
|
||||
private long lastLog = 0;
|
||||
//private long padBoundary = intBytes;
|
||||
private LogHandler handler;
|
||||
private final byte[] intBuf = new byte[4];
|
||||
|
||||
// format version numbers read from/written to this.log
|
||||
private int majorFormatVersion = 0;
|
||||
private int minorFormatVersion = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for the log file. If the system property
|
||||
* sun.rmi.log.class is non-null and the class specified by this
|
||||
* property a) can be loaded, b) is a subclass of LogFile, and c) has a
|
||||
* public two-arg constructor (String, String), ReliableLog uses the
|
||||
* constructor to construct the LogFile.
|
||||
**/
|
||||
private static final Constructor<? extends LogFile>
|
||||
logClassConstructor = getLogClassConstructor();
|
||||
|
||||
/**
|
||||
* Creates a ReliableLog to handle checkpoints and logging in a
|
||||
* stable storage directory.
|
||||
*
|
||||
* @param dirPath path to the stable storage directory
|
||||
* @param logCl the closure object containing callbacks for logging and
|
||||
* recovery
|
||||
* @param pad ignored
|
||||
* @exception IOException If a directory creation error has
|
||||
* occurred or if initialSnapshot callback raises an exception or
|
||||
* if an exception occurs during invocation of the handler's
|
||||
* snapshot method or if other IOException occurs.
|
||||
*/
|
||||
public ReliableLog(String dirPath,
|
||||
LogHandler handler,
|
||||
boolean pad)
|
||||
throws IOException
|
||||
{
|
||||
super();
|
||||
this.Debug = AccessController.doPrivileged(
|
||||
new GetBooleanAction("sun.rmi.log.debug")).booleanValue();
|
||||
dir = new File(dirPath);
|
||||
if (!(dir.exists() && dir.isDirectory())) {
|
||||
// create directory
|
||||
if (!dir.mkdir()) {
|
||||
throw new IOException("could not create directory for log: " +
|
||||
dirPath);
|
||||
}
|
||||
}
|
||||
//padBoundary = (pad ? diskPageSize : intBytes);
|
||||
this.handler = handler;
|
||||
lastSnapshot = 0;
|
||||
lastLog = 0;
|
||||
getVersion();
|
||||
if (version == 0) {
|
||||
try {
|
||||
snapshot(handler.initialSnapshot());
|
||||
} catch (IOException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new IOException("initial snapshot failed with " +
|
||||
"exception: " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ReliableLog to handle checkpoints and logging in a
|
||||
* stable storage directory.
|
||||
*
|
||||
* @param dirPath path to the stable storage directory
|
||||
* @param logCl the closure object containing callbacks for logging and
|
||||
* recovery
|
||||
* @exception IOException If a directory creation error has
|
||||
* occurred or if initialSnapshot callback raises an exception
|
||||
*/
|
||||
public ReliableLog(String dirPath,
|
||||
LogHandler handler)
|
||||
throws IOException
|
||||
{
|
||||
this(dirPath, handler, false);
|
||||
}
|
||||
|
||||
/* public methods */
|
||||
|
||||
/**
|
||||
* Returns an object which is the value recorded in the current
|
||||
* snapshot. This snapshot is recovered by calling the client
|
||||
* supplied callback "recover" and then subsequently invoking
|
||||
* the "readUpdate" callback to apply any logged updates to the state.
|
||||
*
|
||||
* @exception IOException If recovery fails due to serious log
|
||||
* corruption, read update failure, or if an exception occurs
|
||||
* during the recover callback
|
||||
*/
|
||||
public synchronized Object recover()
|
||||
throws IOException
|
||||
{
|
||||
if (Debug)
|
||||
System.err.println("log.debug: recover()");
|
||||
|
||||
if (version == 0)
|
||||
return null;
|
||||
|
||||
Object snapshot;
|
||||
String fname = versionName(snapshotPrefix);
|
||||
File snapshotFile = new File(fname);
|
||||
InputStream in =
|
||||
new BufferedInputStream(new FileInputStream(snapshotFile));
|
||||
|
||||
if (Debug)
|
||||
System.err.println("log.debug: recovering from " + fname);
|
||||
|
||||
try {
|
||||
try {
|
||||
snapshot = handler.recover(in);
|
||||
|
||||
} catch (IOException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
if (Debug)
|
||||
System.err.println("log.debug: recovery failed: " + e);
|
||||
throw new IOException("log recover failed with " +
|
||||
"exception: " + e);
|
||||
}
|
||||
snapshotBytes = snapshotFile.length();
|
||||
} finally {
|
||||
in.close();
|
||||
}
|
||||
|
||||
return recoverUpdates(snapshot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Records this update in the log file (does not force update to disk).
|
||||
* The update is recorded by calling the client's "writeUpdate" callback.
|
||||
* This method must not be called until this log's recover method has
|
||||
* been invoked (and completed).
|
||||
*
|
||||
* @param value the object representing the update
|
||||
* @exception IOException If an exception occurred during a
|
||||
* writeUpdate callback or if other I/O error has occurred.
|
||||
*/
|
||||
public synchronized void update(Object value) throws IOException {
|
||||
update(value, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Records this update in the log file. The update is recorded by
|
||||
* calling the client's writeUpdate callback. This method must not be
|
||||
* called until this log's recover method has been invoked
|
||||
* (and completed).
|
||||
*
|
||||
* @param value the object representing the update
|
||||
* @param forceToDisk ignored; changes are always forced to disk
|
||||
* @exception IOException If force-write to log failed or an
|
||||
* exception occurred during the writeUpdate callback or if other
|
||||
* I/O error occurs while updating the log.
|
||||
*/
|
||||
public synchronized void update(Object value, boolean forceToDisk)
|
||||
throws IOException
|
||||
{
|
||||
// avoid accessing a null log field.
|
||||
if (log == null) {
|
||||
throw new IOException("log is inaccessible, " +
|
||||
"it may have been corrupted or closed");
|
||||
}
|
||||
|
||||
/*
|
||||
* If the entry length field spans a sector boundary, write
|
||||
* the high order bit of the entry length, otherwise write zero for
|
||||
* the entry length.
|
||||
*/
|
||||
long entryStart = log.getFilePointer();
|
||||
boolean spansBoundary = log.checkSpansBoundary(entryStart);
|
||||
writeInt(log, spansBoundary? 1<<31 : 0);
|
||||
|
||||
/*
|
||||
* Write update, and sync.
|
||||
*/
|
||||
try {
|
||||
handler.writeUpdate(new LogOutputStream(log), value);
|
||||
} catch (IOException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw (IOException)
|
||||
new IOException("write update failed").initCause(e);
|
||||
}
|
||||
log.sync();
|
||||
|
||||
long entryEnd = log.getFilePointer();
|
||||
int updateLen = (int) ((entryEnd - entryStart) - intBytes);
|
||||
log.seek(entryStart);
|
||||
|
||||
if (spansBoundary) {
|
||||
/*
|
||||
* If length field spans a sector boundary, then
|
||||
* the next two steps are required (see 4652922):
|
||||
*
|
||||
* 1) Write actual length with high order bit set; sync.
|
||||
* 2) Then clear high order bit of length; sync.
|
||||
*/
|
||||
writeInt(log, updateLen | 1<<31);
|
||||
log.sync();
|
||||
|
||||
log.seek(entryStart);
|
||||
log.writeByte(updateLen >> 24);
|
||||
log.sync();
|
||||
|
||||
} else {
|
||||
/*
|
||||
* Write actual length; sync.
|
||||
*/
|
||||
writeInt(log, updateLen);
|
||||
log.sync();
|
||||
}
|
||||
|
||||
log.seek(entryEnd);
|
||||
logBytes = entryEnd;
|
||||
lastLog = System.currentTimeMillis();
|
||||
logEntries++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the constructor for the log file if the system property
|
||||
* sun.rmi.log.class is non-null and the class specified by the
|
||||
* property a) can be loaded, b) is a subclass of LogFile, and c) has a
|
||||
* public two-arg constructor (String, String); otherwise returns null.
|
||||
**/
|
||||
private static Constructor<? extends LogFile>
|
||||
getLogClassConstructor() {
|
||||
|
||||
String logClassName = AccessController.doPrivileged(
|
||||
new GetPropertyAction("sun.rmi.log.class"));
|
||||
if (logClassName != null) {
|
||||
try {
|
||||
ClassLoader loader =
|
||||
AccessController.doPrivileged(
|
||||
new PrivilegedAction<ClassLoader>() {
|
||||
public ClassLoader run() {
|
||||
return ClassLoader.getSystemClassLoader();
|
||||
}
|
||||
});
|
||||
Class<? extends LogFile> cl =
|
||||
loader.loadClass(logClassName).asSubclass(LogFile.class);
|
||||
return cl.getConstructor(String.class, String.class);
|
||||
} catch (Exception e) {
|
||||
System.err.println("Exception occurred:");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Records this value as the current snapshot by invoking the client
|
||||
* supplied "snapshot" callback and then empties the log.
|
||||
*
|
||||
* @param value the object representing the new snapshot
|
||||
* @exception IOException If an exception occurred during the
|
||||
* snapshot callback or if other I/O error has occurred during the
|
||||
* snapshot process
|
||||
*/
|
||||
public synchronized void snapshot(Object value)
|
||||
throws IOException
|
||||
{
|
||||
int oldVersion = version;
|
||||
incrVersion();
|
||||
|
||||
String fname = versionName(snapshotPrefix);
|
||||
File snapshotFile = new File(fname);
|
||||
FileOutputStream out = new FileOutputStream(snapshotFile);
|
||||
try {
|
||||
try {
|
||||
handler.snapshot(out, value);
|
||||
} catch (IOException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new IOException("snapshot failed", e);
|
||||
}
|
||||
lastSnapshot = System.currentTimeMillis();
|
||||
} finally {
|
||||
out.close();
|
||||
snapshotBytes = snapshotFile.length();
|
||||
}
|
||||
|
||||
openLogFile(true);
|
||||
writeVersionFile(true);
|
||||
commitToNewVersion();
|
||||
deleteSnapshot(oldVersion);
|
||||
deleteLogFile(oldVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the stable storage directory in an orderly manner.
|
||||
*
|
||||
* @exception IOException If an I/O error occurs when the log is
|
||||
* closed
|
||||
*/
|
||||
public synchronized void close() throws IOException {
|
||||
if (log == null) return;
|
||||
try {
|
||||
log.close();
|
||||
} finally {
|
||||
log = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the snapshot file in bytes;
|
||||
*/
|
||||
public long snapshotSize() {
|
||||
return snapshotBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the log file in bytes;
|
||||
*/
|
||||
public long logSize() {
|
||||
return logBytes;
|
||||
}
|
||||
|
||||
/* private methods */
|
||||
|
||||
/**
|
||||
* Write an int value in single write operation. This method
|
||||
* assumes that the caller is synchronized on the log file.
|
||||
*
|
||||
* @param out output stream
|
||||
* @param val int value
|
||||
* @throws IOException if any other I/O error occurs
|
||||
*/
|
||||
private void writeInt(DataOutput out, int val)
|
||||
throws IOException
|
||||
{
|
||||
intBuf[0] = (byte) (val >> 24);
|
||||
intBuf[1] = (byte) (val >> 16);
|
||||
intBuf[2] = (byte) (val >> 8);
|
||||
intBuf[3] = (byte) val;
|
||||
out.write(intBuf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a filename prepended with the stable storage directory path.
|
||||
*
|
||||
* @param name the leaf name of the file
|
||||
*/
|
||||
private String fName(String name) {
|
||||
return dir.getPath() + File.separator + name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a version 0 filename prepended with the stable storage
|
||||
* directory path
|
||||
*
|
||||
* @param name version file name
|
||||
*/
|
||||
private String versionName(String name) {
|
||||
return versionName(name, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a version filename prepended with the stable storage
|
||||
* directory path with the version number as a suffix.
|
||||
*
|
||||
* @param name version file name
|
||||
* @thisversion a version number
|
||||
*/
|
||||
private String versionName(String prefix, int ver) {
|
||||
ver = (ver == 0) ? version : ver;
|
||||
return fName(prefix) + String.valueOf(ver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the directory version number.
|
||||
*/
|
||||
private void incrVersion() {
|
||||
do { version++; } while (version==0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a file.
|
||||
*
|
||||
* @param name the name of the file
|
||||
* @exception IOException If new version file couldn't be removed
|
||||
*/
|
||||
private void deleteFile(String name) throws IOException {
|
||||
|
||||
File f = new File(name);
|
||||
if (!f.delete())
|
||||
throw new IOException("couldn't remove file: " + name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the new version number file.
|
||||
*
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
private void deleteNewVersionFile() throws IOException {
|
||||
deleteFile(fName(newVersionFile));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the snapshot file.
|
||||
*
|
||||
* @param ver the version to remove
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
private void deleteSnapshot(int ver) throws IOException {
|
||||
if (ver == 0) return;
|
||||
deleteFile(versionName(snapshotPrefix, ver));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the log file.
|
||||
*
|
||||
* @param ver the version to remove
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
private void deleteLogFile(int ver) throws IOException {
|
||||
if (ver == 0) return;
|
||||
deleteFile(versionName(logfilePrefix, ver));
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the log file in read/write mode. If file does not exist, it is
|
||||
* created.
|
||||
*
|
||||
* @param truncate if true and file exists, file is truncated to zero
|
||||
* length
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
private void openLogFile(boolean truncate) throws IOException {
|
||||
try {
|
||||
close();
|
||||
} catch (IOException e) { /* assume this is okay */
|
||||
}
|
||||
|
||||
logName = versionName(logfilePrefix);
|
||||
|
||||
try {
|
||||
log = (logClassConstructor == null ?
|
||||
new LogFile(logName, "rw") :
|
||||
logClassConstructor.newInstance(logName, "rw"));
|
||||
} catch (Exception e) {
|
||||
throw (IOException) new IOException(
|
||||
"unable to construct LogFile instance").initCause(e);
|
||||
}
|
||||
|
||||
if (truncate) {
|
||||
initializeLogFile();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new log file, truncated and initialized with the format
|
||||
* version number preferred by this implementation.
|
||||
* <p>Environment: inited, synchronized
|
||||
* <p>Precondition: valid: log, log contains nothing useful
|
||||
* <p>Postcondition: if successful, log is initialised with the format
|
||||
* version number (Preferred{Major,Minor}Version), and logBytes is
|
||||
* set to the resulting size of the updatelog, and logEntries is set to
|
||||
* zero. Otherwise, log is in an indeterminate state, and logBytes
|
||||
* is unchanged, and logEntries is unchanged.
|
||||
*
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
private void initializeLogFile()
|
||||
throws IOException
|
||||
{
|
||||
log.setLength(0);
|
||||
majorFormatVersion = PreferredMajorVersion;
|
||||
writeInt(log, PreferredMajorVersion);
|
||||
minorFormatVersion = PreferredMinorVersion;
|
||||
writeInt(log, PreferredMinorVersion);
|
||||
logBytes = intBytes * 2;
|
||||
logEntries = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes out version number to file.
|
||||
*
|
||||
* @param newVersion if true, writes to a new version file
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
private void writeVersionFile(boolean newVersion) throws IOException {
|
||||
String name;
|
||||
if (newVersion) {
|
||||
name = newVersionFile;
|
||||
} else {
|
||||
name = versionFile;
|
||||
}
|
||||
try (FileOutputStream fos = new FileOutputStream(fName(name));
|
||||
DataOutputStream out = new DataOutputStream(fos)) {
|
||||
writeInt(out, version);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the initial version file
|
||||
*
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
private void createFirstVersion() throws IOException {
|
||||
version = 0;
|
||||
writeVersionFile(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Commits (atomically) the new version.
|
||||
*
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
private void commitToNewVersion() throws IOException {
|
||||
writeVersionFile(false);
|
||||
deleteNewVersionFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads version number from a file.
|
||||
*
|
||||
* @param name the name of the version file
|
||||
* @return the version
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
private int readVersion(String name) throws IOException {
|
||||
try (DataInputStream in = new DataInputStream
|
||||
(new FileInputStream(name))) {
|
||||
return in.readInt();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the version. If version file does not exist, the initial
|
||||
* version file is created.
|
||||
*
|
||||
* @exception IOException If an I/O error has occurred.
|
||||
*/
|
||||
private void getVersion() throws IOException {
|
||||
try {
|
||||
version = readVersion(fName(newVersionFile));
|
||||
commitToNewVersion();
|
||||
} catch (IOException e) {
|
||||
try {
|
||||
deleteNewVersionFile();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
}
|
||||
|
||||
try {
|
||||
version = readVersion(fName(versionFile));
|
||||
}
|
||||
catch (IOException ex) {
|
||||
createFirstVersion();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies outstanding updates to the snapshot.
|
||||
*
|
||||
* @param state the most recent snapshot
|
||||
* @exception IOException If serious log corruption is detected or
|
||||
* if an exception occurred during a readUpdate callback or if
|
||||
* other I/O error has occurred.
|
||||
* @return the resulting state of the object after all updates
|
||||
*/
|
||||
private Object recoverUpdates(Object state)
|
||||
throws IOException
|
||||
{
|
||||
logBytes = 0;
|
||||
logEntries = 0;
|
||||
|
||||
if (version == 0) return state;
|
||||
|
||||
String fname = versionName(logfilePrefix);
|
||||
InputStream in =
|
||||
new BufferedInputStream(new FileInputStream(fname));
|
||||
DataInputStream dataIn = new DataInputStream(in);
|
||||
|
||||
if (Debug)
|
||||
System.err.println("log.debug: reading updates from " + fname);
|
||||
|
||||
try {
|
||||
majorFormatVersion = dataIn.readInt(); logBytes += intBytes;
|
||||
minorFormatVersion = dataIn.readInt(); logBytes += intBytes;
|
||||
} catch (EOFException e) {
|
||||
/* This is a log which was corrupted and/or cleared (by
|
||||
* fsck or equivalent). This is not an error.
|
||||
*/
|
||||
openLogFile(true); // create and truncate
|
||||
in = null;
|
||||
}
|
||||
/* A new major version number is a catastrophe (it means
|
||||
* that the file format is incompatible with older
|
||||
* clients, and we'll only be breaking things by trying to
|
||||
* use the log). A new minor version is no big deal for
|
||||
* upward compatibility.
|
||||
*/
|
||||
if (majorFormatVersion != PreferredMajorVersion) {
|
||||
if (Debug) {
|
||||
System.err.println("log.debug: major version mismatch: " +
|
||||
majorFormatVersion + "." + minorFormatVersion);
|
||||
}
|
||||
throw new IOException("Log file " + logName + " has a " +
|
||||
"version " + majorFormatVersion +
|
||||
"." + minorFormatVersion +
|
||||
" format, and this implementation " +
|
||||
" understands only version " +
|
||||
PreferredMajorVersion + "." +
|
||||
PreferredMinorVersion);
|
||||
}
|
||||
|
||||
try {
|
||||
while (in != null) {
|
||||
int updateLen = 0;
|
||||
|
||||
try {
|
||||
updateLen = dataIn.readInt();
|
||||
} catch (EOFException e) {
|
||||
if (Debug)
|
||||
System.err.println("log.debug: log was sync'd cleanly");
|
||||
break;
|
||||
}
|
||||
if (updateLen <= 0) {/* crashed while writing last log entry */
|
||||
if (Debug) {
|
||||
System.err.println(
|
||||
"log.debug: last update incomplete, " +
|
||||
"updateLen = 0x" +
|
||||
Integer.toHexString(updateLen));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// this is a fragile use of available() which relies on the
|
||||
// twin facts that BufferedInputStream correctly consults
|
||||
// the underlying stream, and that FileInputStream returns
|
||||
// the number of bytes remaining in the file (via FIONREAD).
|
||||
if (in.available() < updateLen) {
|
||||
/* corrupted record at end of log (can happen since we
|
||||
* do only one fsync)
|
||||
*/
|
||||
if (Debug)
|
||||
System.err.println("log.debug: log was truncated");
|
||||
break;
|
||||
}
|
||||
|
||||
if (Debug)
|
||||
System.err.println("log.debug: rdUpdate size " + updateLen);
|
||||
try {
|
||||
state = handler.readUpdate(new LogInputStream(in, updateLen),
|
||||
state);
|
||||
} catch (IOException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new IOException("read update failed with " +
|
||||
"exception: " + e);
|
||||
}
|
||||
logBytes += (intBytes + updateLen);
|
||||
logEntries++;
|
||||
} /* while */
|
||||
} finally {
|
||||
if (in != null)
|
||||
in.close();
|
||||
}
|
||||
|
||||
if (Debug)
|
||||
System.err.println("log.debug: recovered updates: " + logEntries);
|
||||
|
||||
/* reopen log file at end */
|
||||
openLogFile(false);
|
||||
|
||||
// avoid accessing a null log field
|
||||
if (log == null) {
|
||||
throw new IOException("rmid's log is inaccessible, " +
|
||||
"it may have been corrupted or closed");
|
||||
}
|
||||
|
||||
log.seek(logBytes);
|
||||
log.setLength(logBytes);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* ReliableLog's log file implementation. This implementation
|
||||
* is subclassable for testing purposes.
|
||||
*/
|
||||
public static class LogFile extends RandomAccessFile {
|
||||
|
||||
private final FileDescriptor fd;
|
||||
|
||||
/**
|
||||
* Constructs a LogFile and initializes the file descriptor.
|
||||
**/
|
||||
public LogFile(String name, String mode)
|
||||
throws FileNotFoundException, IOException
|
||||
{
|
||||
super(name, mode);
|
||||
this.fd = getFD();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes sync on the file descriptor for this log file.
|
||||
*/
|
||||
protected void sync() throws IOException {
|
||||
fd.sync();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if writing 4 bytes starting at the specified file
|
||||
* position, would span a 512 byte sector boundary; otherwise returns
|
||||
* false.
|
||||
**/
|
||||
protected boolean checkSpansBoundary(long fp) {
|
||||
return fp % 512 > 508;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user