You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by ma...@apache.org on 2013/10/18 06:10:52 UTC
svn commit: r1533320 - in /db/derby/code/trunk:
java/engine/org/apache/derby/iapi/reference/
java/engine/org/apache/derby/impl/services/stream/
java/engine/org/apache/derby/impl/store/raw/data/
java/testing/org/apache/derbyTesting/functionTests/tests/e...
Author: mamta
Date: Fri Oct 18 04:10:51 2013
New Revision: 1533320
URL: http://svn.apache.org/r1533320
Log:
DERBY-6350 (Provide a rolling file implementation of derby.log)
Committing patch submitted by Brett Bergquist
Added:
db/derby/code/trunk/java/engine/org/apache/derby/impl/services/stream/RollingFileStream.java (with props)
db/derby/code/trunk/java/engine/org/apache/derby/impl/services/stream/RollingFileStreamProvider.java (with props)
Modified:
db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/Property.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/services/stream/SingleStream.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/data/BaseDataFileFactory.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/engine/ErrorStreamTest.java
db/derby/code/trunk/tools/jar/extraDBMSclasses.properties
Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/Property.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/Property.java?rev=1533320&r1=1533319&r2=1533320&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/Property.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/Property.java Fri Oct 18 04:10:51 2013
@@ -95,6 +95,16 @@ public interface Property {
*/
String LOG_BOOT_TRACE = "derby.stream.error.logBootTrace";
+
+ /**
+ derby.stream.error.style=<b>The error stream error style.</b>
+ <b>rollingFile<b> is the only file currently supported.
+ Takes precendence over derby.stream.error.file.
+ Takes precendence over derby.stream.error.method.
+ Takes precendence over derby.stream.error.field
+ */
+ String ERRORLOG_STYLE_PROPERTY = "derby.stream.error.style";
+
/**
derby.stream.error.file=<b>absolute or relative error log filename</b>
Takes precendence over derby.stream.error.method.
@@ -118,6 +128,66 @@ public interface Property {
String ERRORLOG_FIELD_PROPERTY = "derby.stream.error.field";
+ /**
+ derby.stream.error.rollingfile.pattern=<b>the pattern</b>
+ A pattern consists of a string that includes the following special
+ components that will be replaced at runtime:
+ <UL>
+ <LI> "/" the local pathname separator
+ <LI> "%t" the system temporary directory
+ <LI> "%h" the value of the "user.home" system property
+ <LI> "%d" the value of the "derby.system.home" system property
+ <LI> "%g" the generation number to distinguish rotated logs
+ <LI> "%u" a unique number to resolve conflicts
+ <LI> "%%" translates to a single percent sign "%"
+ </UL>
+ If no "%g" field has been specified and the file count is greater
+ than one, then the generation number will be added to the end of
+ the generated filename, after a dot.
+ <P>
+ Thus for example a pattern of "%t/java%g.log" with a count of 2
+ would typically cause files to be written on Solaris to
+ /var/tmp/java0.log and /var/tmp/java1.log whereas on Windows 95 they
+ would be typically written to C:\TEMP\java0.log and C:\TEMP\java1.log
+ <P>
+ Generation numbers follow the sequence 0, 1, 2, etc.
+ <P>
+ Normally the "%u" unique field is set to 0. However, if the <tt>FileHandler</tt>
+ tries to open the filename and finds the file is currently in use by
+ another process it will increment the unique number field and try
+ again. This will be repeated until <tt>FileHandler</tt> finds a file name that
+ is not currently in use. If there is a conflict and no "%u" field has
+ been specified, it will be added at the end of the filename after a dot.
+ (This will be after any automatically added generation number.)
+ <P>
+ Thus if three processes were all trying to output to fred%u.%g.txt then
+ they might end up using fred0.0.txt, fred1.0.txt, fred2.0.txt as
+ the first file in their rotating sequences.
+ <P>
+ Note that the use of unique ids to avoid conflicts is only guaranteed
+ to work reliably when using a local disk file system.
+ <P>
+ The default pattern is "%d/derby-%g.log"
+ */
+ String ERRORLOG_ROLLINGFILE_PATTERN_PROPERTY = "derby.stream.error.rollingFile.pattern";
+
+ /**
+ derby.stream.error.rollingfile.limit=<b>the rolling file size limit</b>
+ <P>
+ The default limit is 1024000
+ */
+
+ String ERRORLOG_ROLLINGFILE_LIMIT_PROPERTY = "derby.stream.error.rollingFile.limit";
+
+ /**
+ derby.stream.error.rollingfile.count=<b>the rolling file count</b>
+ <P>
+ The default count is 10
+ */
+
+ String ERRORLOG_ROLLINGFILE_COUNT_PROPERTY = "derby.stream.error.rollingFile.count";
+
+
/**
derby.infolog.append={true,false}
<BR>
Added: db/derby/code/trunk/java/engine/org/apache/derby/impl/services/stream/RollingFileStream.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/services/stream/RollingFileStream.java?rev=1533320&view=auto
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/services/stream/RollingFileStream.java (added)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/services/stream/RollingFileStream.java Fri Oct 18 04:10:51 2013
@@ -0,0 +1,586 @@
+/*
+
+ Derby - Class org.apache.derby.impl.services.stream.RollingFileStream
+
+ 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 org.apache.derby.impl.services.stream;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileLock;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * This class provides rolling file OutputStream. The file pattern, file size,
+ * and number of files can be customized.
+ * <p>
+ * This class borrows extensively from the java.util.logger.FileHandler class for its
+ * file handling ability and instead of handling logger messages it extends
+ * java.io.OutputStream.
+ * <p>
+ * A pattern consists of a string that includes the following special
+ * components that will be replaced at runtime:
+ * <ul>
+ * <li> "/" the local pathname separator
+ * <li> "%t" the system temporary directory
+ * <li> "%h" the value of the "user.home" system property
+ * <li> "%d" the value of the "derby.system.home" system property
+ * <li> "%g" the generation number to distinguish rotated logs
+ * <li> "%u" a unique number to resolve conflicts
+ * <li> "%%" translates to a single percent sign "%"
+ * </ul>
+ * If no "%g" field has been specified and the file count is greater
+ * than one, then the generation number will be added to the end of
+ * the generated filename, after a dot.
+ * <p>
+ * Thus for example a pattern of "%t/java%g.log" with a count of 2
+ * would typically cause files to be written on Solaris to
+ * /var/tmp/java0.log and /var/tmp/java1.log whereas on Windows 95 they
+ * would be typically written to C:\TEMP\java0.log and C:\TEMP\java1.log
+ * <p>
+ * Generation numbers follow the sequence 0, 1, 2, etc.
+ * <p>
+ * Normally the "%u" unique field is set to 0. However, if the <tt>FileHandler</tt>
+ * tries to open the filename and finds the file is currently in use by
+ * another process it will increment the unique number field and try
+ * again. This will be repeated until <tt>FileHandler</tt> finds a file name that
+ * is not currently in use. If there is a conflict and no "%u" field has
+ * been specified, it will be added at the end of the filename after a dot.
+ * (This will be after any automatically added generation number.)
+ * <p>
+ * Thus if three processes were all trying to output to fred%u.%g.txt then
+ * they might end up using fred0.0.txt, fred1.0.txt, fred2.0.txt as
+ * the first file in their rotating sequences.
+ * <p>
+ * Note that the use of unique ids to avoid conflicts is only guaranteed
+ * to work reliably when using a local disk file system.
+ *
+ */
+public class RollingFileStream extends OutputStream {
+
+ /**
+ * The underlying stream being written to that keeps track of how much
+ * has been written
+ */
+ private MeteredStream meter;
+
+ /**
+ * The append flag which indicates at creation time to append to an existing
+ * file or to always create a new one
+ */
+ private boolean append;
+
+ /*
+ * The file limit. The value of 0 indicates no limit.
+ */
+ private int limit;
+
+ /**
+ * The rolling file count. This many files will be created before the
+ * oldest is removed and the files rolled.
+ */
+ private int count;
+
+ /**
+ * The filename pattern.
+ */
+ private String pattern;
+
+ /**
+ * The lockfile name
+ */
+ private String lockFileName;
+
+ /**
+ * The output stream that is used as a lock
+ */
+ private FileOutputStream lockStream;
+
+ /**
+ * The array of File instance representing the rolling files
+ */
+ private File files[];
+
+ private static final int MAX_LOCKS = 100;
+
+ private static java.util.HashMap<String,String> locks = new java.util.HashMap<String,String>();
+
+ /**
+ * Construct a default <tt>RollingFileStream</tt>. This will be configured entirely with default values:
+ * <ul>
+ * <li>pattern - %d/derby-%g.log (DERBY_HOME/derby-0.log)</li>
+ * <li>limit - 0 (unlimited)</li>
+ * <li>count - 1 (one file)</li>
+ * <li>append - false (overwrite and not append)</li>
+ * </ul>
+ *
+ * @exception IOException if there are IO problems opening the files.
+ * @exception SecurityException if a security manager exists and if the caller does not have
+ * <tt>LoggingPermission("control"))</tt>.
+ * @exception NullPointerException if pattern property is an empty String.
+ */
+ public RollingFileStream() throws IOException, SecurityException {
+ this("%d/derby-%g.log", 0, 1, false);
+ }
+
+ /**
+ * Initialize a <tt>RollingFileStream</tt> to write to a set of files with optional append. When (approximately) the
+ * given limit has been written to one file, another file will be opened. The output will cycle through a set of
+ * count files.
+ *
+ * @param pattern the pattern for naming the output file
+ * @param limit the maximum number of bytes to write to any one file
+ * @param count the number of files to use
+ * @param append specifies append mode
+ * @exception IOException if there are IO problems opening the files.
+ * @exception SecurityException if a security manager exists and if the caller does not have
+ * <tt>LoggingPermission("control")</tt>.
+ * @exception IllegalArgumentException if limit < 0, or count < 1.
+ * @exception IllegalArgumentException if pattern is an empty string
+ *
+ */
+ public RollingFileStream(String pattern, int limit, int count, boolean append)
+ throws IOException, SecurityException {
+ if (limit < 0 || count < 1 || pattern.length() < 1) {
+ throw new IllegalArgumentException();
+ }
+ this.pattern = pattern;
+ this.limit = limit;
+ this.count = count;
+ this.append = append;
+ openFiles();
+ }
+
+ /**
+ * Implements the write method of the OutputStream. This writes the value
+ * to the metered stream.
+ * @param b The value to write
+ * @throws IOException
+ */
+ public void write(int b) throws IOException {
+ this.meter.write(b);
+ checkMeter();
+ }
+
+ /**
+ * Opens the output files files based on the configured pattern, limit, count,
+ * and append mode.
+ * @throws IOException
+ */
+ private void openFiles() throws IOException {
+ if (count < 1) {
+ throw new IllegalArgumentException("file count = " + count);
+ }
+ if (limit < 0) {
+ limit = 0;
+ }
+
+ // Create a lock file. This grants us exclusive access
+ // to our set of output files, as long as we are alive.
+ int unique = -1;
+ for (;;) {
+ unique++;
+ if (unique > MAX_LOCKS) {
+ throw new IOException("Couldn't get lock for " + pattern);
+ }
+ // Generate a lock file name from the "unique" int.
+ lockFileName = generate(pattern, 0, unique).toString() + ".lck";
+ // Now try to lock that filename.
+ // Because some systems (e.g. Solaris) can only do file locks
+ // between processes (and not within a process), we first check
+ // if we ourself already have the file locked.
+ synchronized (locks) {
+ if (locks.get(lockFileName) != null) {
+ // We already own this lock, for a different RollingFileStream
+ // object. Try again.
+ continue;
+ }
+ FileChannel fc;
+ try {
+ lockStream = openFile(lockFileName, false);
+ fc = lockStream.getChannel();
+ } catch (IOException ix) {
+ // We got an IOException while trying to open the file.
+ // Try the next file.
+ continue;
+ }
+ try {
+ FileLock fl = fc.tryLock();
+ if (fl == null) {
+ // We failed to get the lock. Try next file.
+ continue;
+ }
+ // We got the lock OK.
+ } catch (IOException ix) {
+ // We got an IOException while trying to get the lock.
+ // This normally indicates that locking is not supported
+ // on the target directory. We have to proceed without
+ // getting a lock. Drop through.
+ }
+ // We got the lock. Remember it.
+ locks.put(lockFileName, lockFileName);
+ break;
+ }
+ }
+
+ files = new File[count];
+ for (int i = 0; i < count; i++) {
+ files[i] = generate(pattern, i, unique);
+ }
+
+ // Create the initial log file.
+ if (append) {
+ open(files[0], true);
+ } else {
+ rotate();
+ }
+ }
+
+ /**
+ * Generates and returns File from a pattern
+ * @param pattern The filename pattern
+ * @param generation The generation number used if there is a conflict
+ * @param unique The unique number to append to the filename
+ * @return The File
+ * @throws IOException
+ */
+ private File generate(String pattern, int generation, int unique) throws IOException {
+ File file = null;
+ String word = "";
+ int ix = 0;
+ boolean sawg = false;
+ boolean sawu = false;
+ while (ix < pattern.length()) {
+ char ch = pattern.charAt(ix);
+ ix++;
+ char ch2 = 0;
+ if (ix < pattern.length()) {
+ ch2 = Character.toLowerCase(pattern.charAt(ix));
+ }
+ if (ch == '/') {
+ if (file == null) {
+ file = new File(word);
+ } else {
+ file = new File(file, word);
+ }
+ word = "";
+ continue;
+ } else if (ch == '%') {
+ if (ch2 == 't') {
+ String tmpDir = getSystemProperty("java.io.tmpdir");
+ if (tmpDir == null) {
+ tmpDir = getSystemProperty("user.home");
+ }
+ file = new File(tmpDir);
+ ix++;
+ word = "";
+ continue;
+ } else if (ch2 == 'h') {
+ file = new File(getSystemProperty("user.home"));
+ ix++;
+ word = "";
+ continue;
+ } else if (ch2 == 'd') {
+ String derbyHome = getSystemProperty("derby.system.home");
+ if (derbyHome == null) {
+ derbyHome = getSystemProperty("user.dir");
+ }
+ file = new File(derbyHome);
+ ix++;
+ word = "";
+ continue;
+ } else if (ch2 == 'g') {
+ word = word + generation;
+ sawg = true;
+ ix++;
+ continue;
+ } else if (ch2 == 'u') {
+ word = word + unique;
+ sawu = true;
+ ix++;
+ continue;
+ } else if (ch2 == '%') {
+ word = word + "%";
+ ix++;
+ continue;
+ }
+ }
+ word = word + ch;
+ }
+ if (count > 1 && !sawg) {
+ word = word + "." + generation;
+ }
+ if (unique > 0 && !sawu) {
+ word = word + "." + unique;
+ }
+ if (word.length() > 0) {
+ if (file == null) {
+ file = new File(word);
+ } else {
+ file = new File(file, word);
+ }
+ }
+ return file;
+ }
+
+ /**
+ * Rotates the log files. The metered OutputStream is closed,the log files
+ * are rotated and then a new metered OutputStream is created.
+ * @throws IOException
+ */
+ private synchronized void rotate() throws IOException {
+
+ if (null != meter) {
+ meter.close();
+ }
+ for (int i = count - 2; i >= 0; i--) {
+ File f1 = files[i];
+ File f2 = files[i + 1];
+ if (fileExists(f1)) {
+ if (fileExists(f2)) {
+ fileDelete(f2);
+ }
+ fileRename(f1, f2);
+ }
+ }
+ try {
+ open(files[0], false);
+ } catch (IOException ix) {
+ }
+ }
+
+ /**
+ * Close all the files.
+ *
+ * @exception SecurityException if a security manager exists and if the caller does not have
+ * <tt>LoggingPermission("control")</tt>.
+ */
+ public synchronized void close() throws SecurityException {
+ // Close the underlying file
+ if (null != meter) {
+ try {
+ meter.close();
+ } catch (IOException ex) {
+ // Problems closing the stream. Punt.S
+ }
+ }
+ // Unlock any lock file.
+ if (lockFileName == null) {
+ return;
+ }
+ try {
+ // Closing the lock file's FileOutputStream will close
+ // the underlying channel and free any locks.
+ lockStream.close();
+ } catch (Exception ex) {
+ // Problems closing the stream. Punt.S
+ }
+ synchronized (locks) {
+ locks.remove(lockFileName);
+ }
+ fileDelete(new File(lockFileName));
+ lockFileName = null;
+ lockStream = null;
+ }
+
+ /**
+ * Gets a system property in a privileged block
+ * @param property The propety to get
+ * @return The property value
+ */
+ private String getSystemProperty(final String property) {
+ // Try to get the derby.system.home property. This requires privileges if run with a security manager
+ String value = AccessController.doPrivileged(new PrivilegedAction<String>() {
+
+ public String run() {
+ return System.getProperty(property);
+ }
+
+ });
+
+ return value;
+ }
+
+ /**
+ * Opens a file in the privileged block
+ * @param filename The name of the file to open
+ * @param append if <code>true</code> open the file in append mode
+ * @return The FileOutputStream for the file
+ * @throws IOException
+ */
+ private FileOutputStream openFile(final String filename, final boolean append) throws IOException {
+ FileOutputStream fis = null;
+ try {
+ fis = AccessController.doPrivileged(new PrivilegedExceptionAction<FileOutputStream>() {
+
+ public FileOutputStream run() throws FileNotFoundException {
+ FileOutputStream res = new FileOutputStream(filename, append);
+ return res;
+ }
+
+ });
+ return fis;
+ } catch (PrivilegedActionException x) {
+ // An exception occurs, rethrow it
+ throw (IOException) x.getException();
+ }
+ }
+
+ /**
+ * Check to see if a file exists in a privilege block
+ * @param file The file to check
+ * @return <code>true</code> if the file exists or <code>false</code> otherwise
+ */
+ private boolean fileExists(final File file) {
+ // Try to get the derby.system.home property. This requires privileges if run with a security manager
+ Boolean value = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
+
+ public Boolean run() {
+ return new Boolean(file.exists());
+ }
+
+ });
+
+ return value.booleanValue();
+ }
+
+ /**
+ * Delete a file in a privilege block
+ * @param file The file to delete
+ */
+ private void fileDelete(final File file) {
+ // Try to get the derby.system.home property. This requires privileges if run with a security manager
+ AccessController.doPrivileged(new PrivilegedAction<Object>() {
+
+ public Object run() {
+ file.delete();
+ return null;
+ }
+ });
+ }
+
+ /**
+ * Rename a file in a privilege block
+ * @param file1 The file to rename
+ * @param file2 The file to rename it to
+ * @return <code>true</code> if the file was renamed or </code>false</code> otherwise
+ */
+ private boolean fileRename(final File file1, final File file2) {
+ // Try to get the derby.system.home property. This requires privileges if run with a security manager
+ Boolean value = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
+
+ public Boolean run() {
+ return new Boolean(file1.renameTo(file2));
+ }
+ });
+
+ return value.booleanValue();
+ }
+
+ /**
+ * Get the length of a file in a privilege block
+ * @param file The file to get the length of
+ * @return The length of the file
+ */
+ private long fileLength(final File file) {
+ // Try to get the derby.system.home property. This requires privileges if run with a security manager
+ Long value = AccessController.doPrivileged(new PrivilegedAction<Long>() {
+
+ public Long run() {
+ return new Long(file.length());
+ }
+ });
+
+ return value.longValue();
+ }
+
+ /**
+ * Opens a new file that and delegates it to a MeteredStream
+ * @param fname The name of the file
+ * @param append If <code>true</code> append to the existing file
+ * @throws IOException
+ */
+ private void open(File fname, boolean append) throws IOException {
+ int len = 0;
+ if (append) {
+ len = (int) fileLength(fname);
+ }
+ FileOutputStream fout = openFile(fname.toString(), append);
+ meter = new MeteredStream(fout, len);
+ }
+
+ /**
+ * Invoked by the metered OutputStream
+ * @throws IOException
+ */
+ private void checkMeter() throws IOException {
+ if (limit > 0 && meter.written >= limit) {
+ rotate();
+ }
+ }
+
+ // A metered stream is a subclass of OutputStream that
+ // (a) forwards all its output to a target stream
+ // (b) keeps track of how many bytes have been written
+ private class MeteredStream extends OutputStream {
+
+ /**
+ * The real OutputStream to delegate to
+ */
+ OutputStream out;
+
+ /**
+ * The number of bytes written so far to the OutputStream
+ */
+ int written;
+
+ /**
+ * Creates a new instance of MeteredStream
+ * @param out The OutputStream to delegate to
+ * @param written The number of bytes currently written to the OuptutStream
+ */
+ MeteredStream(OutputStream out, int written) {
+ this.out = out;
+ this.written = written;
+ }
+
+ public void write(int b) throws IOException {
+ out.write(b);
+ written++;
+ }
+
+ public int getWritten() {
+ return written;
+ }
+
+ @Override
+ public void close() throws IOException {
+ out.close();
+ }
+ }
+}
Propchange: db/derby/code/trunk/java/engine/org/apache/derby/impl/services/stream/RollingFileStream.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: db/derby/code/trunk/java/engine/org/apache/derby/impl/services/stream/RollingFileStreamProvider.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/services/stream/RollingFileStreamProvider.java?rev=1533320&view=auto
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/services/stream/RollingFileStreamProvider.java (added)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/services/stream/RollingFileStreamProvider.java Fri Oct 18 04:10:51 2013
@@ -0,0 +1,63 @@
+/*
+
+ Derby - Class org.apache.derby.iapi.services.stream.RollingFileStreamProvider
+
+ 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 org.apache.derby.impl.services.stream;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import org.apache.derby.iapi.reference.Property;
+import org.apache.derby.iapi.services.property.PropertyUtil;
+
+/**
+ * Creates and configures a RollingFileStream
+ *
+ * @author brett
+ */
+public class RollingFileStreamProvider {
+
+ /**
+ * Creates and returns the OutputStream for a RollingFileStream.
+ * The <tt>derbylog.properties</tt> file contains the configuration. If the
+ * file is not found, then hard coded default values are used to configure
+ * the RollingFileStream. <p>The following properties can be specified <dl>
+ * <dt>pattern</dt> <dd>The pattern to use, the default is
+ * <tt>%d/derby-%g.log</tt></dd> <dt>limit</dt> <dd>The file size limit, the
+ * default is <tt>1024000</tt></dd> <dt>count</dt> <dd>The file count, the
+ * default is <tt>10</tt></dd> <dt>append</dt> <dd>If true the last logfile
+ * is appended to, the default is <tt>true</tt></dd>
+ *
+ * @return The configured OutputStream
+ * @throws IOException
+ * @throws SecurityException
+ */
+ public static OutputStream getOutputStream() throws IOException, SecurityException {
+ OutputStream res = null;
+
+ String pattern = PropertyUtil.getSystemProperty(Property.ERRORLOG_ROLLINGFILE_PATTERN_PROPERTY, "%d/derby-%g.log");
+ int limit = Integer.parseInt(PropertyUtil.getSystemProperty(Property.ERRORLOG_ROLLINGFILE_LIMIT_PROPERTY, "1024000"));
+ int count = Integer.parseInt(PropertyUtil.getSystemProperty(Property.ERRORLOG_ROLLINGFILE_COUNT_PROPERTY, "10"));
+ boolean append = Boolean.parseBoolean(PropertyUtil.getSystemProperty(Property.LOG_FILE_APPEND, "true"));
+
+ RollingFileStream rfh = new RollingFileStream(pattern, limit, count, append);
+ res = rfh;
+
+ return res;
+ }
+}
Propchange: db/derby/code/trunk/java/engine/org/apache/derby/impl/services/stream/RollingFileStreamProvider.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/services/stream/SingleStream.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/services/stream/SingleStream.java?rev=1533320&r1=1533319&r2=1533320&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/services/stream/SingleStream.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/services/stream/SingleStream.java Fri Oct 18 04:10:51 2013
@@ -151,6 +151,12 @@ implements InfoStreams, ModuleControl, j
// to set it. choices are file, method, field, stream
String target = PropertyUtil.
+ getSystemProperty(Property.ERRORLOG_STYLE_PROPERTY);
+ if (target != null) {
+ return makeStyleHPW(target, header);
+ }
+
+ target = PropertyUtil.
getSystemProperty(Property.ERRORLOG_FILE_PROPERTY);
if (target!=null)
return makeFileHPW(target, header);
@@ -158,7 +164,7 @@ implements InfoStreams, ModuleControl, j
target = PropertyUtil.
getSystemProperty(Property.ERRORLOG_METHOD_PROPERTY);
if (target!=null)
- return makeMethodHPW(target, header);
+ return makeMethodHPW(target, header, false);
target = PropertyUtil.
getSystemProperty(Property.ERRORLOG_FIELD_PROPERTY);
@@ -208,7 +214,8 @@ implements InfoStreams, ModuleControl, j
}
private HeaderPrintWriter makeMethodHPW(String methodInvocation,
- PrintWriterGetHeader header) {
+ PrintWriterGetHeader header,
+ boolean canClose) {
int lastDot = methodInvocation.lastIndexOf('.');
String className = methodInvocation.substring(0, lastDot);
@@ -229,7 +236,7 @@ implements InfoStreams, ModuleControl, j
try {
return makeValueHPW(theMethod, theMethod.invoke((Object) null,
- new Object[0]), header, methodInvocation);
+ new Object[0]), header, methodInvocation, canClose);
} catch (IllegalAccessException iae) {
t = iae;
} catch (IllegalArgumentException iarge) {
@@ -251,6 +258,24 @@ implements InfoStreams, ModuleControl, j
}
+ private HeaderPrintWriter makeStyleHPW(String style,
+ PrintWriterGetHeader header) {
+ HeaderPrintWriter res = null;
+ if ("rollingFile".equals(style)) {
+ String className = "org.apache.derby.impl.services.stream.RollingFileStreamProvider.getOutputStream";
+ res = makeMethodHPW(className, header, true);
+ } else {
+ try {
+ IllegalArgumentException ex = new IllegalArgumentException("unknown derby.stream.error.style: " + style);
+ throw ex;
+ } catch (IllegalArgumentException t) {
+ res = useDefaultStream(header, t);
+ } catch (Exception t) {
+ res = useDefaultStream(header, t);
+ }
+ }
+ return res;
+ }
private HeaderPrintWriter makeFieldHPW(String fieldAccess,
PrintWriterGetHeader header) {
@@ -275,7 +300,7 @@ implements InfoStreams, ModuleControl, j
try {
return makeValueHPW(theField, theField.get((Object) null),
- header, fieldAccess);
+ header, fieldAccess, false);
} catch (IllegalAccessException iae) {
t = iae;
} catch (IllegalArgumentException iarge) {
@@ -306,12 +331,12 @@ implements InfoStreams, ModuleControl, j
}
private HeaderPrintWriter makeValueHPW(Member whereFrom, Object value,
- PrintWriterGetHeader header, String name) {
+ PrintWriterGetHeader header, String name, boolean canClose) {
if (value instanceof OutputStream)
- return new BasicHeaderPrintWriter((OutputStream) value, header, false, name);
+ return new BasicHeaderPrintWriter((OutputStream) value, header, canClose, name);
else if (value instanceof Writer)
- return new BasicHeaderPrintWriter((Writer) value, header, false, name);
+ return new BasicHeaderPrintWriter((Writer) value, header, canClose, name);
HeaderPrintWriter hpw = useDefaultStream(header);
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/data/BaseDataFileFactory.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/data/BaseDataFileFactory.java?rev=1533320&r1=1533319&r2=1533320&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/data/BaseDataFileFactory.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/data/BaseDataFileFactory.java Fri Oct 18 04:10:51 2013
@@ -378,6 +378,11 @@ public class BaseDataFileFactory
//Log properties related to redirection of derby.log
String target =
+ PropertyUtil.getSystemProperty(Property.ERRORLOG_STYLE_PROPERTY);
+ if (target != null)
+ logMsg(Property.ERRORLOG_STYLE_PROPERTY+"=" + target);
+
+ target =
PropertyUtil.getSystemProperty(Property.ERRORLOG_FILE_PROPERTY);
if (target != null)
logMsg(Property.ERRORLOG_FILE_PROPERTY+"=" + target);
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/engine/ErrorStreamTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/engine/ErrorStreamTest.java?rev=1533320&r1=1533319&r2=1533320&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/engine/ErrorStreamTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/engine/ErrorStreamTest.java Fri Oct 18 04:10:51 2013
@@ -47,11 +47,18 @@ import org.apache.derbyTesting.junit.Tes
* logStream.java, the other test* methods are from errorStream.java.
*/
public class ErrorStreamTest extends BaseJDBCTestCase {
-
private static final String FILE_PROP = "derby.stream.error.file";
private static final String METHOD_PROP = "derby.stream.error.method";
private static final String FIELD_PROP = "derby.stream.error.field";
+ private static final String STYLE_PROP = "derby.stream.error.style";
+ private static final String ROLLING_FILE_STYLE = "rollingFile";
+ private static final String ROLLING_FILE_COUNT_PROP = "derby.stream.error.rollingFile.count";
+ private static final String ROLLING_FILE_LIMIT_PROP = "derby.stream.error.rollingFile.limit";
+ private static final String ROLLING_FILE_PATTERN_PROP = "derby.stream.error.rollingFile.pattern";
+ private static final String DERBY_0_LOG = "derby-0.log";
+ private static final String DERBYLANGUAGELOG_QUERY_PLAN = "derby.language.logQueryPlan";
+
/**
* runNo keeps track of which run we are in to generate unique (within a
* JUnit run) names for files that are used in the test. Has to be static.
@@ -87,7 +94,7 @@ public class ErrorStreamTest extends Bas
*/
private OutputStream errStream;
private File errStreamFile;
-
+
public ErrorStreamTest(String name) {
super(name);
}
@@ -340,6 +347,237 @@ public class ErrorStreamTest extends Bas
}
/**
+ * Test the derby.stream.error.style=rollingFile property.
+ */
+ public void testStyleRollingFile() throws IOException, SQLException {
+ setSystemProperty(STYLE_PROP, ROLLING_FILE_STYLE);
+
+ File derby0log = new File(getSystemProperty("derby.system.home"), DERBY_0_LOG);
+
+ File derby0lck = new File(getSystemProperty("derby.system.home"),
+ "derby-0.log.lck");
+
+ bootDerby();
+
+ assertIsExisting(derby0log);
+ assertNotDirectory(derby0log);
+ assertNotEmpty(derby0log);
+
+ assertIsExisting(derby0lck);
+ assertNotDirectory(derby0lck);
+ assertIsEmpty(derby0lck);
+
+ println("Shutdown database");
+ getTestConfiguration().shutdownDatabase();
+
+ assertIsExisting(derby0log);
+ assertNotDirectory(derby0log);
+ assertNotEmpty(derby0log);
+
+ assertIsExisting(derby0lck);
+ assertNotDirectory(derby0lck);
+ assertIsEmpty(derby0lck);
+
+ println("Shutdown engine");
+ getTestConfiguration().shutdownEngine();
+
+ assertNotExisting(derby0lck);
+
+ boolean deleted = deleteFile(derby0log);
+ assertTrue("File " + derby0log + " could not be deleted", deleted);
+ }
+
+ /**
+ * Test the derby.stream.error.style property with wrong style.
+ */
+ public void testWrongStyle() throws IOException, SQLException {
+ setSystemProperty(STYLE_PROP, "unknownStyle");
+
+ File derby0log = new File(getSystemProperty("derby.system.home"), DERBY_0_LOG);
+
+ bootDerby();
+ getTestConfiguration().shutdownEngine();
+
+ closeStreams();
+
+ assertNotExisting(derby0log);
+ assertNotExisting(fileStreamFile);
+ assertIsEmpty(methodStreamFile);
+ assertIsEmpty(fieldStreamFile);
+ assertNotEmpty(errStreamFile);
+ }
+
+ /**
+ * Test the derby.stream.error.style=rollingFile property with default config
+ */
+ public void testDefaultRollingDefaultConfig() throws IOException, SQLException {
+ setSystemProperty(STYLE_PROP, ROLLING_FILE_STYLE);
+
+ // This is set so that we can get enough output into the log files
+ setSystemProperty(DERBYLANGUAGELOG_QUERY_PLAN, "true");
+
+ bootDerby();
+
+ // This will generate enough output to roll through all 10 log files
+ for (int i = 0; i < 3699; i++) {
+ checkAllConsistency(getConnection());
+ }
+ // Make sure we remove the system property that is logging the query plan
+ removeSystemProperty(DERBYLANGUAGELOG_QUERY_PLAN);
+ getTestConfiguration().shutdownEngine();
+
+ closeStreams();
+
+ // There should be derb-0.log .. derby-9.log files present
+ for (int i = 0; i < 10; i++) {
+ File derbyLog = new File(getSystemProperty("derby.system.home"),
+ "derby-" + i + ".log");
+ assertIsExisting(derbyLog);
+ assertNotDirectory(derbyLog);
+ assertNotEmpty(derbyLog);
+
+ // Check the last log file to make sure that it has the default
+ // limit
+ if (i == 9) {
+ assertFileSize(derbyLog, 1024000);
+ }
+
+ boolean deleted = deleteFile(derbyLog);
+ assertTrue("File " + derbyLog + " could not be deleted", deleted);
+ }
+
+ assertNotExisting(fileStreamFile);
+ assertIsEmpty(methodStreamFile);
+ assertIsEmpty(fieldStreamFile);
+ assertIsEmpty(errStreamFile);
+ }
+
+ /**
+ * Test the derby.stream.error.style=rollingFile property with user configuration.
+ */
+ public void testDefaultRollingUserConfig() throws IOException, SQLException {
+ setSystemProperty(STYLE_PROP, ROLLING_FILE_STYLE);
+ setSystemProperty(ROLLING_FILE_PATTERN_PROP, "%d/db-%g.log");
+ setSystemProperty(ROLLING_FILE_COUNT_PROP, "3");
+ setSystemProperty(ROLLING_FILE_LIMIT_PROP, "10000");
+
+ // This is set so that we can get enough output into the log files
+ setSystemProperty(DERBYLANGUAGELOG_QUERY_PLAN, "true");
+
+ bootDerby();
+
+ // This will generate enough output to roll through all 10 log files
+ for (int i = 0; i < 10; i++) {
+ checkAllConsistency(getConnection());
+ }
+ // Make sure we remove the system property that is logging the query plan
+ removeSystemProperty(DERBYLANGUAGELOG_QUERY_PLAN);
+ removeSystemProperty(ROLLING_FILE_PATTERN_PROP);
+ removeSystemProperty(ROLLING_FILE_COUNT_PROP);
+ removeSystemProperty(ROLLING_FILE_LIMIT_PROP);
+
+ getTestConfiguration().shutdownEngine();
+
+ closeStreams();
+
+ // There should be derb-0.log .. derby-3.log files present
+ for (int i = 0; i < 3; i++) {
+ File derbyLog = new File(getSystemProperty("derby.system.home"),
+ "db-" + i + ".log");
+ assertIsExisting(derbyLog);
+ assertNotDirectory(derbyLog);
+ assertNotEmpty(derbyLog);
+
+ // Check the last log file to make sure that it has the correct
+ // limit
+ if (i == 2) {
+ assertFileSize(derbyLog, 10000);
+ }
+
+ boolean deleted = deleteFile(derbyLog);
+ assertTrue("File " + derbyLog + " could not be deleted", deleted);
+ }
+
+ assertNotExisting(fileStreamFile);
+ assertIsEmpty(methodStreamFile);
+ assertIsEmpty(fieldStreamFile);
+ assertIsEmpty(errStreamFile);
+ }
+
+ /**
+ * Test that the derby.stream.error.style property overrides the
+ * derby.stream.error.file property.
+ */
+ public void testRollingFileStyleOverFile() throws IOException, SQLException {
+ setSystemProperty(STYLE_PROP, ROLLING_FILE_STYLE);
+
+ File derby0log = new File(getSystemProperty("derby.system.home"), DERBY_0_LOG);
+
+ setSystemProperty(FILE_PROP, getCanonicalPath(fileStreamFile));
+
+ bootDerby();
+ getTestConfiguration().shutdownEngine();
+
+ closeStreams();
+
+ assertNotEmpty(derby0log);
+ assertNotExisting(fileStreamFile);
+ assertIsEmpty(methodStreamFile);
+ assertIsEmpty(fieldStreamFile);
+ assertIsEmpty(errStreamFile);
+ }
+
+ /**
+ * Test that the derby.stream.error.style property overrides the
+ * derby.stream.error.method property.
+ */
+ public void testRollingFileStyleOverMethod() throws IOException, SQLException {
+ setSystemProperty(STYLE_PROP, ROLLING_FILE_STYLE);
+
+ File derby0log = new File(getSystemProperty("derby.system.home"), DERBY_0_LOG);
+
+ setSystemProperty(METHOD_PROP,
+ "org.apache.derbyTesting.functionTests.tests.engine."+
+ "ErrorStreamTest.getStream");
+
+ bootDerby();
+ getTestConfiguration().shutdownEngine();
+
+ closeStreams();
+
+ assertNotEmpty(derby0log);
+ assertNotExisting(fileStreamFile);
+ assertIsEmpty(methodStreamFile);
+ assertIsEmpty(fieldStreamFile);
+ assertIsEmpty(errStreamFile);
+ }
+
+ /**
+ * Test that the derby.stream.error.style property overrides the
+ * derby.stream.error.field property.
+ */
+ public void testRollingFileStyleOverField() throws IOException, SQLException {
+ setSystemProperty(STYLE_PROP, ROLLING_FILE_STYLE);
+
+ File derby0log = new File(getSystemProperty("derby.system.home"), DERBY_0_LOG);
+
+ setSystemProperty(FIELD_PROP,
+ "org.apache.derbyTesting.functionTests.tests.engine."+
+ "ErrorStreamTest.fieldStream");
+
+ bootDerby();
+ getTestConfiguration().shutdownEngine();
+
+ closeStreams();
+
+ assertNotEmpty(derby0log);
+ assertNotExisting(fileStreamFile);
+ assertIsEmpty(methodStreamFile);
+ assertIsEmpty(fieldStreamFile);
+ assertIsEmpty(errStreamFile);
+ }
+
+ /**
* Method getStream used by Derby when derby.stream.error.method
* is set. Maps to file <database>-method-<runNo>.log
* This method has to be static.
@@ -432,6 +670,21 @@ public class ErrorStreamTest extends Bas
}
}
+ private static void assertFileSize(final File f, final int size) throws IOException {
+ try {
+ AccessController.doPrivileged(
+ new PrivilegedExceptionAction<Void>() {
+ public Void run() throws IOException {
+ assertEquals("assertFileEize failed for file " + f.getName() + ": ", size, f.length());
+ return null;
+ }
+ });
+ } catch (PrivilegedActionException e) {
+ // e.getException() should be an instance of IOException.
+ throw (IOException) e.getException();
+ }
+ }
+
private static void assertIsExisting(final File f) throws IOException {
String path = getCanonicalPath(f);
assertTrue(path + " doesn't exist",
@@ -495,6 +748,7 @@ public class ErrorStreamTest extends Bas
removeSystemProperty(FILE_PROP);
removeSystemProperty(METHOD_PROP);
removeSystemProperty(FIELD_PROP);
+ removeSystemProperty(STYLE_PROP);
}
private void deleteStreamFiles() {
Modified: db/derby/code/trunk/tools/jar/extraDBMSclasses.properties
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/tools/jar/extraDBMSclasses.properties?rev=1533320&r1=1533319&r2=1533320&view=diff
==============================================================================
--- db/derby/code/trunk/tools/jar/extraDBMSclasses.properties (original)
+++ db/derby/code/trunk/tools/jar/extraDBMSclasses.properties Fri Oct 18 04:10:51 2013
@@ -107,6 +107,9 @@ derby.module.store.cpf=org.apache.derby.
derby.module.shared.threaddump=org.apache.derby.shared.common.sanity.ThreadDump
derby.module.engine.threaddump=org.apache.derby.iapi.error.ThreadDump
+derby.module.logging.provider=org.apache.derby.impl.services.stream.RollingFileStreamProvider
+derby.module.logging.stream=org.apache.derby.impl.services.stream.RollingFileStream
+
# optional tools
derby.module.opttrace=org.apache.derby.impl.sql.compile.OptimizerTracer
derby.module.opttraceviewer=org.apache.derby.impl.sql.compile.OptTraceViewer