All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.objectweb.howl.log.LogBuffer Maven / Gradle / Ivy

There is a newer version: 10.0.0-M2
Show newest version
/*
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2004 Bull S.A.
 * All rights reserved.
 * 
 * Contact: [email protected]
 * 
 * This software is licensed under the BSD license.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *     
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *     
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * ------------------------------------------------------------------------------
 * $Id: LogBuffer.java,v 1.10 2005/11/15 22:43:54 girouxm Exp $
 * ------------------------------------------------------------------------------
 */
package org.objectweb.howl.log;

import java.io.IOException;
import java.nio.ByteBuffer;

import java.util.zip.Adler32;


/**
 * Classes used as buffers in LogBufferManager must implement this interface.
 * 
 * 

This abstract class implements methods common to all LogBuffer sub-classes. */ abstract class LogBuffer extends LogObject { /** * */ final ByteBuffer buffer; /** * buffer number used by owner (LogBufferManager) to workerID into an array of buffers. * *

Actual use of workerID is determined by the buffer manager implementation. */ int index = -1; /** * currentTimeMillis that buffer was initialized. * *

Implementations of LogBuffer should provide some means * to persist tod to the file to allow recovery * operations to determine when a buffer was written. * *

Used during replay situations to validate block integrity. * The TOD field from the block header is compared with the TOD field * of the block footer to verify that an entire block was written. */ long tod = 0; /** * number of waiting threads. *

Always synchronized on (waitingThreadsLock). * * Design Note:
* Originally this field was volatile. It was changed * at the suggestion of David Jencks to protected. *

We tried using (this) to protect access, * but this caused some additional lock contention * and performance fell off about 10%. * */ protected int waitingThreads = 0; /** * mutex for synchronizing access to waitingThreads */ final Object waitingThreadsLock = new Object(); /** * results of last write. *

Value must be one of the constants defined in LogBuffer interface. */ int iostatus = 0; /** * buffer sequence number. *

LogBufferManager maintains a sequence number * of buffers written. The sequence number is stored * in the block header of each log block. *

Initialized to zero. *

Set to -1 by read() if bytes read is -1 (end of file) */ int bsn = 0; /** * set true if this LogBuffer should issue a rewind on the FileChannel before * writing ByteBuffer. */ boolean rewind = false; /** * set true by LogFileManager if the buffer must be forced * due to file switch. * *

BUG: 300505 */ boolean forceNow = false; /** * IOException from last write */ IOException ioexception = null; /** * name of this buffer object. */ String name = null; /** * LogFile associated with the current LogBuffer. * *

The LogBufferManager will have a pool of LogBuffers. If the containing * Logger is managing a pool of files, then it is possible * that some period of time, some buffers will be written to one file, while other * buffers are written to another file. To allow writes and forces to separate * files to be performed in parallel, each LogBuffer must keep track of its own * LogFile. * * @see org.objectweb.howl.log.LogFileManager#getLogFileForWrite(LogBuffer) */ LogFile lf = null; /** * switch to enable computation of checksum. * *

Since it takes some CPU to compute checksums over a buffer, * it might be useful to disable the checksum, at least for performance * measurements. *

When doChecksum is true then an implementation class * should compute a checksum and store the value in the buffer during * the write() method. *

Use of checksums is optional and depends on the actual implementation * class. */ boolean doChecksum = true; /** * Number of used data bytes in the buffer. * *

This is different than buffer capacity(). The bytes used is the * number of bytes of usable data in a buffer. Bytes between the * bytes used count and the buffer footer are undefined, possibly * uninitialized or residue. * *

set by operations that read data from files into the * buffer such as read(). *

checked by operations that retrieve logical records * from the buffer get(). */ int bytesUsed = 0; /** * Local buffer used to compute checksums. * * The initial implementation of HOWL used the ByteBuffer.hashCode() * method to compute a checksum. Since each vendor's implementation * of the JVM is not guaranteed to generate the same value for hashCode, * this approach is not portable, and could result in journal files * that appear to be invalid if restarted using a JVM by a vendor * that is different than the JVM that was used to write the journal * initially. * * The problem is solved by implementing our own checksum method. * The checksumBuffer member is used to obtain a local copy of * the ByteBuffer contents for purposses of computing the checksum. * Instead of obtaining each byte individually, the entire buffer * is retrieved into checksumBuffer for computing the checksum. * */ byte[] checksumBuffer = null; // BUG 304291 final Adler32 checksum; // BUG 304291 /** * default constructor. *

after creating a new instance of LogBuffer the caller must * invoke config(). */ LogBuffer(Configuration config) { super(config); // LogObject name = this.getClass().getName(); doChecksum = config.isChecksumEnabled(); buffer = ByteBuffer.allocateDirect(config.getBufferSize() * 1024); // BUG 300957 checksum = (doChecksum && config.isAdler32ChecksumEnabled()) ? new Adler32(): null; } /** * decrements count of waiting threads and returns updated value. * * @return number of threads still waiting after the release. */ final int release() { synchronized(waitingThreadsLock) { return --waitingThreads; } } /** * returns the number of threads currently waiting for * the buffer to be forced to disk. * * @return current value of waitingThreads */ final int getWaitingThreads() { synchronized (waitingThreadsLock) { return waitingThreads; } } /** * park threads that are waiting for the ByteBuffer to * be forced to disk. *

The count of waiting threads ( waitingThreads ) * has been incremented in put() . */ final void sync() throws IOException, InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); synchronized(this) { while (iostatus != LogBufferStatus.COMPLETE) { if (iostatus == LogBufferStatus.ERROR) { // BUG 303907 add a message to the IOException throw new IOException("LogBuffer.sync(): LogBufferStatus.ERROR"); } wait(); } } } /** * Computes a checksum over the the entire byte buffer * backing this LogBuffer object. * * @return the computed checksum. */ int checksum() { int result = 0; buffer.clear(); if (checksum == null) { result = buffer.hashCode(); } else { byte[] checksumBuffer; if (buffer.hasArray()) checksumBuffer = buffer.array(); else { // allocate a local buffer once to avoid excessive garbage collection if (this.checksumBuffer == null) this.checksumBuffer = new byte[buffer.capacity()]; checksumBuffer = this.checksumBuffer; buffer.get(checksumBuffer); } checksum.reset(); checksum.update(checksumBuffer, 0, checksumBuffer.length); result = (int) (checksum.getValue() & 0xFFFFFFFF); } return result; } /** * May be used in traces or other purposes for debugging. * * @return name of LogBuffer object. */ String getName() { return "(" + name + ")"; } /** * initialize members for LogBuffer implementation class for reuse. *

LogBufferManager maintains a pool of LogBuffer objects. Each * time a LogBuffer is allocated from the pool for use as the current * collection buffer, the init() routine is called. After performing necessary * initialization, the LogBuffer invokes the LogFileManager to obtain * a LogFile for use when writing and forcing the buffer. If a file * switch occurrs, the LogFileManager will store a file header record * into this newly initialized buffer. * * @param bsn Logical Block Sequence Number of the buffer. * LogBufferManager maintains a block sequence number * to ensure correct order of writes to disk. Some implementations * of LogBuffer may include the BSN as part of a record or * block header. * * @param lfm LogFileMaager to call to obtain a LogFile. * * @return this LogBuffer * */ abstract LogBuffer init(int bsn, LogFileManager lfm) throws LogFileOverflowException; /** * read a block of data from the LogFile object provided * in the lf parameter starting at the position * specified in the postiion parameter. * *

Used by LogFileManager implementations to read * blocks of data that are formatted by a specific LogBuffer * implementation. * *

The LogFileManager uses LogBufferManager.getLogBuffer() method to obtain * a buffer that is used for reading log files. * * @param lf LogFile to read. * @param position within the LogFile to be read. * * @return this LogBuffer reference. * @throws IOException * @throws InvalidLogBufferException */ abstract LogBuffer read(LogFile lf, long position) throws IOException, InvalidLogBufferException; /** * returns true if the buffer should be forced to disk. *

The criteria for determining if a buffer should be * forced is implementation dependent. Typically, this * method will return true if there are one or more threads * waiting for the buffer to be forced and the amount * of time the threads has been waiting has been longer * than some implementation defined value. * * @return true if buffer should be forced immediately. */ abstract boolean shouldForce(); /** * puts a data record into the buffer and returns a token for record. * *

PRECONDITION: caller holds a bufferManager monitor. * *

The caller must set the sync parameter true if the thread * will ultimately call sync() after a successful put(). * This strategy allows the waitingThreads counter to be * incremented while the current thread holds the bufferManager * monitor. * *

Implementations should return a token that can be used * later for replay, and for debugging purposes. * *

The data record is passed as a byte[][] allowing * callers to construct data records from individual bits * of information. * The arrays are concatenated into a single log record whose size * is the sum of the individual array sizes. * Each array is preceded by the size of the individual array. * The entire record is preceded by the size of all arrays * including the individual array size fields. *

The record format is as follows: *

   * +------+------------+----------------+---------+       +----------------+---------+
   * | type | total size | data[0].length | data[0] | . . . | data[n].length | data[n] |
   * +------+------------+----------------+---------+       +----------------+---------+
   * 
*

During replay the entire record is returned as a single * byte[]. The ReplayListener is responsible for * decomposing the record into the original array of byte[]. * @param type short containing implementation defined record * type information. The type is stored as the first * field of the log record. * @param data byte[][] to be written to log. * @param sync true if thread will call sync following the put. * Causes count of waitingThreads to be incremented. * * @throws LogRecordSizeException * if the sum of all data[] array sizes is larger than * the maximum allowed record size for the configured buffer size. * * @return a long that contains the physical position of the record is returned. * The value returned by put() is an encoding of the physical * position. The format of the returned value is implementation * specific, and should be treated as opaque by the caller. * Returns 0 if there is no room for the record in the current buffer. */ abstract long put(short type, byte[][] data, boolean sync) throws LogRecordSizeException; /** * write ByteBuffer to the LogFile. * *

updates the buffer header with the number * of bytes used. Based on configuration, some implementations * may compute a hash code or other integrety value and * include the value in some implementation defined header * information. *

The buffer is written using the LogFile.write() method * to allow the LogFile to manage file position for circular * journals. *

forcing and notification of waiting threads is * the responsibility of the LogBufferManager that owns this LogBUffer. * * @throws IOException * rethrows any IOExceptions thrown by FileChannel methods. * *

QUESTION: should waiters be interupted if IO Error occurs? * @see #init(int, LogFileManager) * @see org.objectweb.howl.log.LogFile#write(LogBuffer) */ abstract void write() throws IOException; /** * returns statistics for this LogBuffer object. * *

information is returned in the form of an XML node that * can be included as a nested element in a larger document * containing stats for multiple LogBuffer objects, and any * containing objects. * * @return statistics for this buffer as XML */ abstract String getStats(); }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy