001: /*-
002: * See the file LICENSE for redistribution information.
003: *
004: * Copyright (c) 2002,2008 Oracle. All rights reserved.
005: *
006: * $Id: LogBuffer.java,v 1.42.2.3 2008/01/07 15:14:13 cwl Exp $
007: */
008:
009: package com.sleepycat.je.log;
010:
011: import java.nio.ByteBuffer;
012:
013: import com.sleepycat.je.DatabaseException;
014: import com.sleepycat.je.dbi.EnvironmentImpl;
015: import com.sleepycat.je.latch.Latch;
016: import com.sleepycat.je.latch.LatchSupport;
017: import com.sleepycat.je.utilint.DbLsn;
018:
019: /**
020: * DbLogBuffers hold outgoing, newly written log entries.
021: */
022: class LogBuffer implements LogSource {
023:
024: private static final String DEBUG_NAME = LogBuffer.class.getName();
025:
026: /* Storage */
027: private ByteBuffer buffer;
028:
029: /* Information about what log entries are held here. */
030: private long firstLsn;
031: private long lastLsn;
032:
033: /* The read latch serializes access to and modification of the LSN info. */
034: private Latch readLatch;
035:
036: /*
037: * Buffer may be rewritten because an IOException previously occurred.
038: */
039: private boolean rewriteAllowed;
040:
041: LogBuffer(int capacity, EnvironmentImpl env)
042: throws DatabaseException {
043:
044: if (env.useDirectNIO()) {
045: buffer = ByteBuffer.allocateDirect(capacity);
046: } else {
047: buffer = ByteBuffer.allocate(capacity);
048: }
049: readLatch = LatchSupport.makeLatch(DEBUG_NAME, env);
050: reinit();
051: }
052:
053: /*
054: * Used by LogManager for the case when we have a temporary buffer in hand
055: * and no LogBuffers in the LogBufferPool are large enough to hold the
056: * current entry being written. We just wrap the temporary ByteBuffer
057: * in a LogBuffer and pass it to FileManager. [#12674].
058: */
059: LogBuffer(ByteBuffer buffer, long firstLsn)
060: throws DatabaseException {
061:
062: this .buffer = buffer;
063: this .firstLsn = firstLsn;
064: this .lastLsn = firstLsn;
065: rewriteAllowed = false;
066: }
067:
068: void reinit() throws DatabaseException {
069:
070: readLatch.acquire();
071: buffer.clear();
072: firstLsn = DbLsn.NULL_LSN;
073: lastLsn = DbLsn.NULL_LSN;
074: rewriteAllowed = false;
075: readLatch.release();
076: }
077:
078: /*
079: * Write support
080: */
081:
082: /**
083: * Return first LSN held in this buffer. Assumes the log write latch is
084: * held.
085: */
086: long getFirstLsn() {
087: return firstLsn;
088: }
089:
090: /**
091: * This LSN has been written to the log.
092: */
093: void registerLsn(long lsn) throws DatabaseException {
094:
095: readLatch.acquire();
096: try {
097: if (lastLsn != DbLsn.NULL_LSN) {
098: assert (DbLsn.compareTo(lsn, lastLsn) > 0);
099: }
100: lastLsn = lsn;
101: if (firstLsn == DbLsn.NULL_LSN) {
102: firstLsn = lsn;
103: }
104: } finally {
105: readLatch.release();
106: }
107: }
108:
109: /**
110: * Check capacity of buffer. Assumes that the log write latch is held.
111: * @return true if this buffer can hold this many more bytes.
112: */
113: boolean hasRoom(int numBytes) {
114: return (numBytes <= (buffer.capacity() - buffer.position()));
115: }
116:
117: /**
118: * @return the actual data buffer.
119: */
120: ByteBuffer getDataBuffer() {
121: return buffer;
122: }
123:
124: /**
125: * @return capacity in bytes
126: */
127: int getCapacity() {
128: return buffer.capacity();
129: }
130:
131: /*
132: * Read support
133: */
134:
135: /**
136: * Support for reading a log entry out of a still-in-memory log
137: * @return true if this buffer holds the entry at this LSN. The
138: * buffer will be latched for read. Returns false if
139: * LSN is not here, and releases the read latch.
140: */
141: boolean containsLsn(long lsn) throws DatabaseException {
142:
143: /* Latch before we look at the LSNs. */
144: readLatch.acquire();
145: boolean found = false;
146: if ((firstLsn != DbLsn.NULL_LSN)
147: && ((DbLsn.compareTo(firstLsn, lsn) <= 0) && (DbLsn
148: .compareTo(lastLsn, lsn) >= 0))) {
149: found = true;
150: }
151:
152: if (found) {
153: return true;
154: } else {
155: readLatch.release();
156: return false;
157: }
158: }
159:
160: /**
161: * When modifying the buffer, acquire the readLatch. Call release() to
162: * release the latch. Note that containsLsn() acquires the latch for
163: * reading.
164: */
165: public void latchForWrite() throws DatabaseException {
166:
167: readLatch.acquire();
168: }
169:
170: /*
171: * LogSource support
172: */
173:
174: /**
175: * @see LogSource#release
176: */
177: public void release() throws DatabaseException {
178:
179: readLatch.releaseIfOwner();
180: }
181:
182: boolean getRewriteAllowed() {
183: return rewriteAllowed;
184: }
185:
186: void setRewriteAllowed() {
187: rewriteAllowed = true;
188: }
189:
190: /**
191: * @see LogSource#getBytes
192: */
193: public ByteBuffer getBytes(long fileOffset) {
194:
195: /*
196: * Make a copy of this buffer (doesn't copy data, only buffer state)
197: * and position it to read the requested data.
198: *
199: * Note that we catch Exception here because it is possible that
200: * another thread is modifying the state of buffer simultaneously.
201: * Specifically, this can happen if another thread is writing this log
202: * buffer out and it does (e.g.) a flip operation on it. The actual
203: * mark/pos of the buffer may be caught in an unpredictable state. We
204: * could add another latch to protect this buffer, but that's heavier
205: * weight than we need. So the easiest thing to do is to just retry
206: * the duplicate operation. See [#9822].
207: */
208: ByteBuffer copy = null;
209: while (true) {
210: try {
211: copy = buffer.duplicate();
212: copy.position((int) (fileOffset - DbLsn
213: .getFileOffset(firstLsn)));
214: break;
215: } catch (IllegalArgumentException IAE) {
216: continue;
217: }
218: }
219: return copy;
220: }
221:
222: /**
223: * @see LogSource#getBytes
224: */
225: public ByteBuffer getBytes(long fileOffset, int numBytes) {
226: ByteBuffer copy = getBytes(fileOffset);
227: /* Log Buffer should always hold a whole entry. */
228: assert (copy.remaining() >= numBytes) : "copy.remaining="
229: + copy.remaining() + " numBytes=" + numBytes;
230: return copy;
231: }
232: }
|