KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sleepycat > je > log > LogBufferPool


1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 2002,2006 Oracle. All rights reserved.
5  *
6  * $Id: LogBufferPool.java,v 1.72 2006/11/27 23:07:12 mark Exp $
7  */

8
9 package com.sleepycat.je.log;
10
11 import java.io.IOException JavaDoc;
12 import java.nio.ByteBuffer JavaDoc;
13 import java.util.Iterator JavaDoc;
14 import java.util.LinkedList JavaDoc;
15
16 import com.sleepycat.je.DatabaseException;
17 import com.sleepycat.je.EnvironmentStats;
18 import com.sleepycat.je.StatsConfig;
19 import com.sleepycat.je.config.EnvironmentParams;
20 import com.sleepycat.je.dbi.DbConfigManager;
21 import com.sleepycat.je.dbi.EnvironmentImpl;
22 import com.sleepycat.je.latch.Latch;
23 import com.sleepycat.je.latch.LatchSupport;
24
25 /**
26  * LogBufferPool keeps a set of log buffers.
27  */

28 class LogBufferPool {
29     private static final String JavaDoc DEBUG_NAME = LogBufferPool.class.getName();
30
31     private EnvironmentImpl envImpl = null;
32     private int logBufferSize; // size of each log buffer
33
private LinkedList JavaDoc bufferPool; // List of log buffers
34

35     /* Buffer that holds the current log end. All writes go to this buffer. */
36     private LogBuffer currentWriteBuffer;
37
38     private FileManager fileManager;
39
40     /* Stats */
41     private long nNotResident = 0; // had to be instantiated from an lsn
42
private long nCacheMiss = 0; // had to retrieve from disk
43
private boolean runInMemory;
44
45     /*
46      * bufferPoolLatch is synchronizes access and changes to the buffer pool.
47      * Related latches are the log write latch in LogManager and the read
48      * latches in each log buffer. The log write latch is always taken before
49      * the bufferPoolLatch. The bufferPoolLatch is always taken before any
50      * logBuffer read latch. When faulting in an object from the log, the order
51      * of latching is:
52      * bufferPoolLatch.acquire()
53      * LogBuffer read latch acquire();
54      * bufferPoolLatch.release();
55      * LogBuffer read latch release()
56      * bufferPoolLatch is also used to protect assignment to the
57      * currentWriteBuffer field.
58      */

59     private Latch bufferPoolLatch;
60
61     LogBufferPool(FileManager fileManager,
62                   EnvironmentImpl envImpl)
63         throws DatabaseException {
64         
65         this.fileManager = fileManager;
66         this.envImpl = envImpl;
67         bufferPoolLatch =
68         LatchSupport.makeLatch(DEBUG_NAME + "_FullLatch", envImpl);
69
70         /* Configure the pool. */
71         DbConfigManager configManager = envImpl.getConfigManager();
72         runInMemory = envImpl.isMemOnly();
73         reset(configManager);
74
75         /* Current buffer is the active buffer that writes go into. */
76         currentWriteBuffer = (LogBuffer) bufferPool.getFirst();
77     }
78
79     final int getLogBufferSize() {
80         return logBufferSize;
81     }
82
83     /**
84      * Initialize the pool at construction time and when the cache is resized.
85      * This method is called after the memory budget has been calculated.
86      */

87     void reset(DbConfigManager configManager)
88         throws DatabaseException {
89
90         /*
91          * When running in memory, we can't clear the existing pool and
92          * changing the buffer size is not very useful, so just return.
93          */

94         if (runInMemory && bufferPool != null) {
95             return;
96         }
97
98         /*
99          * Based on the log budget, figure the number and size of
100          * log buffers to use.
101          */

102         int numBuffers =
103         configManager.getInt(EnvironmentParams.NUM_LOG_BUFFERS);
104         long logBufferBudget = envImpl.getMemoryBudget().getLogBufferBudget();
105
106         /* Buffers must be int sized. */
107         int newBufferSize = (int) logBufferBudget / numBuffers;
108
109         /* list of buffers that are available for log writing */
110         LinkedList JavaDoc newPool = new LinkedList JavaDoc();
111
112         /*
113          * If we're running in memory only, don't pre-allocate all the buffers.
114          * This case only occurs when called from the constructor.
115          */

116         if (runInMemory) {
117             numBuffers = 1;
118         }
119
120         for (int i = 0; i < numBuffers; i++) {
121             newPool.add(new LogBuffer(newBufferSize, envImpl));
122         }
123
124         /*
125          * The following applies when this method is called to reset the pool
126          * when an existing pool is in use:
127          * - The old pool will no longer be referenced.
128          * - Buffers being read in the old pool will be no longer referenced
129          * after the read operation is complete.
130          * - The currentWriteBuffer field is not changed here; it will be no
131          * longer referenced after it is written to the file and a new
132          * currentWriteBuffer is assigned.
133          * - The logBufferSize can be changed now because it is only used for
134          * allocating new buffers; it is not used as the size of the
135          * currentWriteBuffer.
136          */

137         bufferPoolLatch.acquire();
138         bufferPool = newPool;
139         logBufferSize = newBufferSize;
140         bufferPoolLatch.release();
141     }
142
143     /**
144      * Get a log buffer for writing sizeNeeded bytes. If currentWriteBuffer is
145      * too small or too full, flush currentWriteBuffer and get a new one.
146      * Called within the log write latch.
147      *
148      * @return a buffer that can hold sizeNeeded bytes.
149      */

150     LogBuffer getWriteBuffer(int sizeNeeded, boolean flippedFile)
151         throws IOException JavaDoc, DatabaseException {
152         
153         /*
154          * We need a new log buffer either because this log buffer is full, or
155          * the LSN has marched along to the next file. Each log buffer only
156          * holds entries that belong to a single file. If we've flipped over
157          * into the next file, we'll need to get a new log buffer even if the
158          * current one has room.
159          */

160     if ((!currentWriteBuffer.hasRoom(sizeNeeded)) || flippedFile) {
161
162         /*
163          * Write the currentWriteBuffer to the file and reset
164          * currentWriteBuffer.
165          */

166         writeBufferToFile(sizeNeeded);
167     }
168
169     if (flippedFile) {
170         /* Now that the old buffer has been written to disk, fsync. */
171         if (!runInMemory) {
172         fileManager.syncLogEndAndFinishFile();
173         }
174     }
175
176         return currentWriteBuffer;
177     }
178
179     /**
180      * Write the contents of the currentWriteBuffer to disk. Leave this buffer
181      * in memory to be available to would be readers. Set up a new
182      * currentWriteBuffer. Assumes the log write latch is held.
183      *
184      * @param sizeNeeded is the size of the next object we need to write to
185      * the log. May be 0 if this is called on behalf of LogManager.flush().
186      */

187     void writeBufferToFile(int sizeNeeded)
188         throws IOException JavaDoc, DatabaseException {
189
190         int bufferSize =
191         ((logBufferSize > sizeNeeded) ? logBufferSize : sizeNeeded);
192
193         /* We're done with the buffer, flip to make it readable. */
194         currentWriteBuffer.latchForWrite();
195         LogBuffer latchedBuffer = currentWriteBuffer;
196         try {
197             ByteBuffer JavaDoc currentByteBuffer = currentWriteBuffer.getDataBuffer();
198             int savePosition = currentByteBuffer.position();
199             int saveLimit = currentByteBuffer.limit();
200             currentByteBuffer.flip();
201
202             /* Dispose of it and get a new buffer for writing. */
203             if (runInMemory) {
204                 /* We're done with the current buffer. */
205                 latchedBuffer.release();
206                 latchedBuffer = null;
207                 /* We're supposed to run in-memory, allocate another buffer. */
208                 bufferPoolLatch.acquire();
209                 currentWriteBuffer = new LogBuffer(bufferSize, envImpl);
210                 bufferPool.add(currentWriteBuffer);
211                 bufferPoolLatch.release();
212             } else {
213
214                 /*
215                  * If we're configured for writing (not memory-only situation),
216                  * write this buffer to disk and find a new buffer to use.
217                  */

218                 try {
219                     fileManager.writeLogBuffer(currentWriteBuffer);
220
221                     /* Rewind so readers can see this. */
222                     currentWriteBuffer.getDataBuffer().rewind();
223
224                     /* We're done with the current buffer. */
225                     latchedBuffer.release();
226                     latchedBuffer = null;
227
228                     /*
229                      * Now look in the linked list for a buffer of the right
230                      * size.
231                      */

232                     LogBuffer nextToUse = null;
233                     try {
234                         bufferPoolLatch.acquire();
235                         Iterator JavaDoc iter = bufferPool.iterator();
236                         nextToUse = (LogBuffer) iter.next();
237
238                         boolean done = bufferPool.remove(nextToUse);
239                         assert done;
240                         nextToUse.reinit();
241
242                         /* Put the nextToUse buffer at the end of the queue. */
243                         bufferPool.add(nextToUse);
244
245                         /* Assign currentWriteBuffer with the latch held. */
246                         currentWriteBuffer = nextToUse;
247                     } finally {
248                         bufferPoolLatch.releaseIfOwner();
249                     }
250                 } catch (DatabaseException DE) {
251                     currentByteBuffer.position(savePosition);
252                     currentByteBuffer.limit(saveLimit);
253                     throw DE;
254                 }
255             }
256         } finally {
257             if (latchedBuffer != null) {
258                 latchedBuffer.release();
259             }
260         }
261     }
262
263     /**
264      * A loggable object has been freshly marshalled into the write log buffer.
265      * 1. Update buffer so it knows what LSNs it contains.
266      * 2. If this object requires a flush, write this buffer out to the
267      * backing file.
268      * Assumes log write latch is held.
269      */

270     void writeCompleted(long lsn, boolean flushRequired)
271         throws DatabaseException, IOException JavaDoc {
272
273         currentWriteBuffer.registerLsn(lsn);
274         if (flushRequired) {
275             writeBufferToFile(0);
276         }
277     }
278
279     /**
280      * Find a buffer that holds this LSN.
281      * @return the buffer that contains this LSN, latched and ready to
282      * read, or return null.
283      */

284     LogBuffer getReadBuffer(long lsn)
285     throws DatabaseException {
286
287         LogBuffer foundBuffer = null;
288
289         bufferPoolLatch.acquire();
290     try {
291         nNotResident++;
292         Iterator JavaDoc iter = bufferPool.iterator();
293         while (iter.hasNext()) {
294         LogBuffer l = (LogBuffer) iter.next();
295         if (l.containsLsn(lsn)) {
296             foundBuffer = l;
297             break;
298         }
299         }
300
301         /*
302          * Check the currentWriteBuffer separately, since if the pool was
303          * recently reset it will not be in the pool.
304          */

305         if (foundBuffer == null &&
306         currentWriteBuffer.containsLsn(lsn)) {
307         foundBuffer = currentWriteBuffer;
308         }
309
310         if (foundBuffer == null) {
311         nCacheMiss++;
312         }
313
314     } finally {
315         bufferPoolLatch.releaseIfOwner();
316     }
317
318         if (foundBuffer == null) {
319             return null;
320         } else {
321             return foundBuffer;
322         }
323     }
324
325     void loadStats(StatsConfig config, EnvironmentStats stats)
326         throws DatabaseException {
327
328         stats.setNCacheMiss(nCacheMiss);
329         stats.setNNotResident(nNotResident);
330         if (config.getClear()) {
331             nCacheMiss = 0;
332             nNotResident = 0;
333         }
334
335         /* Also return buffer pool memory usage */
336         bufferPoolLatch.acquire();
337         long bufferBytes = 0;
338         int nLogBuffers = 0;
339         try {
340             Iterator JavaDoc iter = bufferPool.iterator();
341             while (iter.hasNext()) {
342                 LogBuffer l = (LogBuffer) iter.next();
343                 nLogBuffers++;
344                 bufferBytes += l.getCapacity();
345             }
346         } finally {
347             bufferPoolLatch.release();
348         }
349         stats.setNLogBuffers(nLogBuffers);
350         stats.setBufferBytes(bufferBytes);
351     }
352 }
353
Popular Tags