KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > jofti > store > BlockBuffer


1 package com.jofti.store;
2
3 import java.io.IOException JavaDoc;
4 import java.nio.ByteBuffer JavaDoc;
5 import java.util.Arrays JavaDoc;
6
7 import org.apache.commons.logging.Log;
8 import org.apache.commons.logging.LogFactory;
9
10 import com.jofti.exception.JoftiException;
11
12 /**
13  *
14  * <p>Each block contains a header, zero or more entries,
15  * and a footer.
16  */

17 class BlockBuffer {
18
19     ByteBuffer JavaDoc buffer = null;
20
21     FileStore file = null;
22
23     // default size
24
int bufferSize = 4096;
25
26     int recordSize = 0;
27
28     int numberEntries=0;
29     /**
30      * Number of used data bytes in the buffer.
31      *
32      * <p>This is different than buffer capacity(). The bytes used is the
33      * number of bytes of usable data in a buffer.
34      *
35      * <p>set by operations that read data from files into the
36      * buffer such as read().
37      * <p>checked by operations that retrieve logical records
38      * from the buffer get().
39      */

40     int bytesUsed = 0;
41
42     FilePositionHolder positionHolder = null;
43
44     private static Log log = LogFactory.getLog(BlockBuffer.class);
45
46     /**
47      * number of times this buffer was used.
48      * <p>In general, should be about the same for all buffers in a pool.
49      */

50     int initCounter = 0;
51
52     /**
53      * size of a buffer header.
54      * <pre>
55      * <b>buffer Header format</b>
56      * byte[] HEADER_ID [1] "H"
57      * short size of bytes written [2]
58      * short total number of items [2]
59      * byte[] CRLF [2] to make it easier to read buffers in an editor
60      * </pre>
61      */

62     final static int bufferHeaderSize = 7;
63
64     final int bytesUsedOffSet = 1;
65
66     /**
67      * The number of bytes to reserve for block footer information.
68      */

69     final static int bufferFooterSize = 3;
70
71     /*
72      * byte FOOTER_ID [1] "F"
73      * byte CRLF [2] to make it easier to read buffers in an editor
74      */

75
76     /**
77      * Size of the header for each data record in the block.
78      *
79      * <p>Record header format:
80      * int record length of user data [4]
81      */

82     private int recordHeaderSize = 4;
83
84     // block header & footer fields
85
/**
86      * Carriage Return Line Feed sequence used for debugging purposes.
87      */

88     private byte[] CRLF = "\r\n".getBytes();
89
90     private byte[] crlf = new byte[CRLF.length];
91
92     /**
93      * Signature for each logical block header.
94      */

95     private byte[] HEADER_ID = "H".getBytes();
96
97     /**
98      * Signature for each logical block footer.
99      */

100     private byte[] FOOTER_ID = "F".getBytes();
101
102     /**
103      * maximum size of user data record.
104      *
105      * <p>Although this member is local to a LogBuffer instance,
106      * it is assumed to have the same value in all instances.
107      */

108     private int payloadSize;
109
110     /**
111      * default constructor calls super class constructor.
112      */

113     BlockBuffer() {
114
115     }
116
117     public int remaining() {
118         return buffer.remaining() - (bufferFooterSize);
119     }
120
121     /**
122      * initialize members for buffer reuse.
123      *
124      * @param bsn Logic Block Sequence Number of the buffer.
125      * BufferManager maintains a list of block sequence numbers
126      * to ensure correct order of writes to disk. Some implementations
127      * of LogBuffer may include the BSN as part of a record or
128      * block header.
129      */

130     public void init(int bufferSize) throws JoftiException {
131         // sun Bug ID: 4879883 - can't allocate more than 64mb without resetting
132
// in jdk earlier than 1.4.2_05 - workaround -XX:MaxDirectMemorySize=XXXM
133

134         buffer = ByteBuffer.allocateDirect(bufferSize);
135
136         ++initCounter;
137
138         buffer.clear();
139
140         payloadSize = ((bufferSize) - (bufferHeaderSize + bufferFooterSize));
141
142     }
143
144     public void reset() {
145         buffer.clear();
146         positionHolder = null;
147         file = null;
148         recordSize = 0;
149         bytesUsed = 0;
150
151     }
152
153     void writeFurniture(int numberRecords) {
154         buffer.put(HEADER_ID);
155
156         // placeholder for length of bytes in record
157
buffer.putShort((short) 0);
158         buffer.putShort((short)numberRecords);
159         buffer.put(CRLF);
160
161     }
162
163
164     int put(ByteBuffer JavaDoc buf, int offset) throws JoftiException {
165
166         int written = 0;
167
168         int remaining = buffer.remaining() - bufferFooterSize;
169
170         // write the length of the array element
171
// ensure that it is first element of array - or we do not write this
172
if (offset == 0 && recordHeaderSize <= remaining) {
173         // buffer.putInt(data.length);
174
remaining -= 4;
175         } else if (offset == 0 && recordHeaderSize > remaining) {
176             // we can ignore this as there is not enough space
177
// to write even the header
178
return written;
179         }
180         // we do this to make sure that we always have the size in front of the array
181

182         // try and write some bytes from the data - this could be partial for a large array
183
if (remaining > 0) {
184
185             int length = remaining;
186             // can we fit all the data element into the buffer
187
// if ((data.length - offset) < length) {
188
// length = data.length - offset;
189
// }
190
// buffer.put(data, offset, length);
191
// update how much we have written
192
written = length;
193             // update what we have remaining
194

195         }
196
197         bytesUsed = buffer.position();
198         return written;
199     }
200     
201     void put(ByteBuffer JavaDoc buf) throws JoftiException {
202
203         // write the length of the array element
204
// ensure that it is first element of array - or we do not write this
205
buffer.put(buf);
206             // update how much we have written
207

208         bytesUsed = buffer.position();
209     }
210
211
212
213     
214
215     void writeFooter() {
216         if (buffer.position() != payloadSize + bufferHeaderSize) {
217             buffer.position(payloadSize + bufferHeaderSize);
218         }
219
220         buffer.put(FOOTER_ID);
221         buffer.put(CRLF);
222
223     }
224
225     /**
226      * write ByteBuffer to the log file.
227      */

228     void write() throws IOException JavaDoc {
229         // assert lf != null: "FileStore lf is null";
230

231         //write bytesUsed
232
buffer.putShort(bytesUsedOffSet, (short) bytesUsed);
233
234         writeFooter();
235         try {
236
237             buffer.flip();
238             file.write(this);
239
240         } catch (IOException JavaDoc e) {
241             throw e;
242         }
243     }
244
245     /**
246      * Reads a block from FileStore <i> lf </i> and validates
247      * header and footer information.
248      *
249      * @see LogBuffer#read(FileStore, long)
250      * @throws IOException
251      * if anything goes wrong during the file read.
252      * @throws InvalidLogBufferException
253      * if any of the block header or footer fields are invalid.
254      */

255     BlockBuffer read(FileStore store) throws JoftiException {
256         long position = positionHolder.position;
257
258         try {
259             // fill our ByteBuffer with a block of data from the file
260
int bytesRead = -1;
261             if (store.channel.size() > position) // JRockit issue identified in HOWL
262
bytesRead = store.channel.read(buffer, position);
263             if (bytesRead == -1) {
264                 // end of file
265
return null;
266             }
267
268             if (bytesRead != buffer.capacity())
269                 throw new JoftiException("FILESIZE Error: bytesRead="
270                         + bytesRead);
271
272             // verify header
273
buffer.clear();
274             byte head = buffer.get();
275             if (head != HEADER_ID[0])
276                 throw new JoftiException(
277                         "HEADER_ID does not match for position " + position
278                                 + " in store " + store.fileId);
279
280             // get data used (short)
281
bytesUsed = buffer.getShort();
282             if (bytesUsed < 0)
283                 throw new JoftiException("data used: " + bytesUsed
284                         + " for position " + position + " in store "
285                         + store.fileId);
286             // get the number of records
287
numberEntries = buffer.getShort();
288             if (numberEntries < 0)
289                 throw new JoftiException("entries: " + numberEntries
290                         + " for position " + position + " in store "
291                         + store.fileId);
292             
293             // get CRLF
294
buffer.get(crlf);
295             if (!Arrays.equals(crlf, CRLF))
296                 throw new JoftiException(
297                         "HEADER_CRLF not present for position " + position
298                                 + " in store " + store.fileId);
299
300             // mark start of first data record
301
buffer.mark();
302
303             // get FOOTER_ID and compare
304
buffer.position(payloadSize + bufferHeaderSize);
305
306             byte footer = buffer.get();
307             if (footer != FOOTER_ID[0]) {
308                 throw new JoftiException("FOOTER_ID not present for position "
309                         + position + " in store " + store.fileId);
310             }
311
312             // get FOOTER_CRLF
313
buffer.get(crlf);
314             if (!Arrays.equals(crlf, CRLF))
315                 throw new JoftiException("FOOTER_CRLF not found for position "
316                         + position + " in store " + store.fileId);
317
318             //set the limit
319
buffer.limit(bytesUsed);
320             // reset position to first data record
321

322             buffer.reset();
323         } catch (Exception JavaDoc e) {
324             throw new JoftiException(e);
325         }
326         return this;
327     }
328
329     /**
330      * return statistics for this buffer.
331      *
332      * @return String containing statistics as an XML node
333      */

334     String JavaDoc getStats() {
335         String JavaDoc name = this.getClass().getName();
336
337         String JavaDoc result = "<LogBuffer class='"
338                 + name
339                 + "\n <timesUsed value='"
340                 + initCounter
341                 + "'>Number of times this buffer was initialized for use</timesUsed>"
342                 + "\n</LogBuffer>" + "\n";
343
344         return result;
345     }
346
347     public FileStore getFileStore() {
348         return file;
349     }
350
351     public void setFileStore(FileStore file) {
352         this.file = file;
353     }
354
355     public FilePositionHolder getPositionHolder() {
356         return positionHolder;
357     }
358
359     public void setPositionHolder(FilePositionHolder positionHolder) {
360         this.positionHolder = positionHolder;
361     }
362 }
Popular Tags