KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sleepycat > je > tree > FileSummaryLN


1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 2002,2006 Oracle. All rights reserved.
5  *
6  * $Id: FileSummaryLN.java,v 1.21 2006/10/30 21:14:26 bostic Exp $
7  */

8
9 package com.sleepycat.je.tree;
10
11 import java.io.UnsupportedEncodingException JavaDoc;
12 import java.nio.ByteBuffer JavaDoc;
13
14 import com.sleepycat.je.DatabaseException;
15 import com.sleepycat.je.cleaner.FileSummary;
16 import com.sleepycat.je.cleaner.PackedOffsets;
17 import com.sleepycat.je.cleaner.TrackedFileSummary;
18 import com.sleepycat.je.dbi.DatabaseImpl;
19 import com.sleepycat.je.log.LogEntryType;
20 import com.sleepycat.je.log.LogException;
21 import com.sleepycat.je.log.LogUtils;
22 import com.sleepycat.je.log.LoggableObject;
23
24 /**
25  * A FileSummaryLN represents a Leaf Node in the UtilizationProfile database.
26  *
27  * <p>The contents of the FileSummaryLN are not fixed until the moment at which
28  * the LN is added to the log. A base summary object contains the summary last
29  * added to the log. A tracked summary object contains live summary info being
30  * updated in real time. The tracked summary is added to the base summary just
31  * before logging it, and then the tracked summary is reset. This ensures that
32  * the logged summary will accurately reflect the totals calculated at the
33  * point in the log where the LN is added.</p>
34  *
35  * <p>This is all done in the writeToLog method, which operates under the log
36  * write latch. All utilization tracking must be done under the log write
37  * latch.</p>
38  *
39  * <p>In record version 1, obsolete offset tracking was added and multiple
40  * records are stored for a single file rather than a single record. Each
41  * record contains the offsets that were tracked since the last record was
42  * written.
43  *
44  * <p>The key is 8 bytes: 4 bytes for the file number followed by 4 bytes for
45  * the sequence number. The lowest valued key for a given file contains the
46  * most recent summary information, while to get a complete list of obsolete
47  * offsets all records for the file must be read. A range search using just
48  * the first 4 bytes can be used to find the most recent record -- this is
49  * possible because the sequence number values are decreasing over time for a
50  * given file. Here are example keys for three summary records in file 1:</p>
51  *
52  * <pre>
53  * (file=1, sequence=Integer.MAX_VALUE - 300)
54  * (file=1, sequence=Integer.MAX_VALUE - 200)
55  * (file=1, sequence=Integer.MAX_VALUE - 100)
56  * </pre>
57  *
58  * <p>The sequence number is the number of obsolete entries counted so far,
59  * subtracted from Integer.MAX_VALUE to cause the latest written record to have
60  * the lowest key.</p>
61  *
62  * <h3>Log version information</h3>
63  * <p>Version 0: Keys are old format strings. No obsolete detail is
64  * present.</p>
65  * <p>Version 1: Keys are two 4 byte integers: {file, sequence}. Obsolete
66  * detail is present. Some offsets may be invalid if RMW was used.</p>
67  * <p>Version 2: The RMW problem with invalid offsets was corrected. There is
68  * no data format change; all versions of JE 2.0.x can read version 1.</p>
69  *
70  * @see com.sleepycat.je.cleaner.UtilizationProfile
71  */

72 public final class FileSummaryLN extends LN {
73
74     private static final String JavaDoc BEGIN_TAG = "<fileSummaryLN>";
75     private static final String JavaDoc END_TAG = "</fileSummaryLN>";
76
77     private FileSummary baseSummary;
78     private TrackedFileSummary trackedSummary;
79     private PackedOffsets obsoleteOffsets;
80     private boolean needOffsets;
81     private byte logVersion;
82
83     /**
84      * Creates a new LN with a given base summary.
85      */

86     public FileSummaryLN(FileSummary baseSummary) {
87         super(new byte[0]);
88         assert baseSummary != null;
89         this.baseSummary = baseSummary;
90         obsoleteOffsets = new PackedOffsets();
91         logVersion = -1;
92     }
93
94     /**
95      * Creates an empty LN to be filled in from the log.
96      */

97     public FileSummaryLN()
98         throws DatabaseException {
99         baseSummary = new FileSummary();
100         obsoleteOffsets = new PackedOffsets();
101     }
102
103     /**
104      * Sets the live summary object that will be added to the base summary at
105      * the time the LN is logged.
106      */

107     public void setTrackedSummary(TrackedFileSummary trackedSummary) {
108         this.trackedSummary = trackedSummary;
109         needOffsets = true;
110     }
111
112     /**
113      * Returns the tracked summary, or null if setTrackedSummary was not
114      * called.
115      */

116     public TrackedFileSummary getTrackedSummary() {
117         return trackedSummary;
118     }
119
120     /**
121      * Returns the base summary for the file that is stored in the LN.
122      */

123     public FileSummary getBaseSummary() {
124         return baseSummary;
125     }
126
127     /**
128      * Returns the obsolete offsets for the file.
129      */

130     public PackedOffsets getObsoleteOffsets() {
131         return obsoleteOffsets;
132     }
133
134     /**
135      * Returns true if the given key for this LN is a String file number key.
136      * For the old version of the LN there will be a single record per file.
137      *
138      * If this is a version 0 log entry, the key is a string. However, such an
139      * LN may be migrated by the cleaner, in which case the version will be 1
140      * or greater [#13061]. In the latter case, we can distinguish a string
141      * key by:
142      *
143      * 1) If the key is not 8 bytes long, it has to be a string key.
144      *
145      * 2) If the key is 8 bytes long, but bytes[4] is ascii "0" to "9", then it
146      * must be a string key. bytes[4] to bytes[7] are a sequence number that
147      * is the number of log entries counted. For this number to be greater
148      * than 0x30000000, the binary value of 4 digits starting with ascii "0",
149      * over 400 million log entries would have to occur in a single file; this
150      * should never happen.
151      *
152      * Note that having to rely on method (2) is unlikely. A string key will
153      * only be 8 bytes if the file number reach 8 decimal digits (10,000,000 to
154      * 99,999,999). This is a very large file number and unlikely to have
155      * occurred using JE 1.7.1 or earlier.
156      *
157      * In summary, the only time the algorithm here could fail is if there were
158      * more than 400 million log entries per file, and more than 10 million
159      * were written with JE 1.7.1 or earlier.
160      */

161     public boolean hasStringKey(byte[] bytes) {
162
163         if (logVersion == 0 || bytes.length != 8) {
164             return true;
165         } else {
166            return (bytes[4] >= '0' && bytes[4] <= '9');
167         }
168     }
169
170     /**
171      * Convert a FileSummaryLN key from a byte array to a long. The file
172      * number is the first 4 bytes of the key.
173      */

174     public long getFileNumber(byte[] bytes) {
175
176         if (hasStringKey(bytes)) {
177             try {
178                 return Long.valueOf(new String JavaDoc(bytes, "UTF-8")).longValue();
179             } catch (UnsupportedEncodingException JavaDoc shouldNeverHappen) {
180                 assert false: shouldNeverHappen;
181                 return 0;
182             }
183         } else {
184             ByteBuffer JavaDoc buf = ByteBuffer.wrap(bytes);
185             return LogUtils.readIntMSB(buf) & 0xFFFFFFFFL;
186         }
187     }
188
189     /**
190      * Returns the first 4 bytes of the key for the given file number. This
191      * can be used to do a range search to find the first LN for the file.
192      */

193     public static byte[] makePartialKey(long fileNum) {
194
195         byte[] bytes = new byte[4];
196         ByteBuffer JavaDoc buf = ByteBuffer.wrap(bytes);
197
198         LogUtils.writeIntMSB(buf, (int) fileNum);
199
200         return bytes;
201     }
202
203     /**
204      * Returns the full two-part key for a given file number and unique
205      * sequence. This can be used to insert a new LN.
206      *
207      * @param sequence is a unique identifier for the LN for the given file,
208      * and must be greater than the last sequence.
209      */

210     public static byte[] makeFullKey(long fileNum, int sequence) {
211
212         assert sequence >= 0;
213
214         byte[] bytes = new byte[8];
215         ByteBuffer JavaDoc buf = ByteBuffer.wrap(bytes);
216
217         /*
218          * The sequence is subtracted from MAX_VALUE so that increasing values
219          * will be sorted first. This allows a simple range search to find the
220          * most recent value.
221          */

222         LogUtils.writeIntMSB(buf, (int) fileNum);
223         LogUtils.writeIntMSB(buf, Integer.MAX_VALUE - sequence);
224
225         return bytes;
226     }
227
228     /**
229      * Initialize a node that has been faulted in from the log. If this FSLN
230      * contains version 1 offsets that can be incorrect when RMW was used, and
231      * if je.cleaner.rmwFix is enabled, discard the offsets. [#13158]
232      */

233     public void postFetchInit(DatabaseImpl db, long sourceLsn)
234         throws DatabaseException {
235
236         super.postFetchInit(db, sourceLsn);
237
238         if (logVersion == 1 &&
239             db.getDbEnvironment().getUtilizationProfile().isRMWFixEnabled()) {
240             obsoleteOffsets = new PackedOffsets();
241         }
242     }
243
244     /*
245      * Dumping
246      */

247
248     public String JavaDoc toString() {
249         return dumpString(0, true);
250     }
251     
252     public String JavaDoc beginTag() {
253         return BEGIN_TAG;
254     }
255
256     public String JavaDoc endTag() {
257         return END_TAG;
258     }
259
260     public String JavaDoc dumpString(int nSpaces, boolean dumpTags) {
261         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
262         sb.append(super.dumpString(nSpaces, dumpTags));
263         sb.append('\n');
264         if (!isDeleted()) {
265             sb.append(baseSummary.toString());
266             sb.append(obsoleteOffsets.toString());
267         }
268         return sb.toString();
269     }
270
271     /**
272      * Dump additional fields. Done this way so the additional info can
273      * be within the XML tags defining the dumped log entry.
274      */

275     protected void dumpLogAdditional(StringBuffer JavaDoc sb, boolean verbose) {
276         if (!isDeleted()) {
277             baseSummary.dumpLog(sb, true);
278             if (verbose) {
279                obsoleteOffsets.dumpLog(sb, true);
280             }
281         }
282     }
283
284     /*
285      * Logging
286      */

287
288     /**
289      * Log type for transactional entries.
290      */

291     protected LogEntryType getTransactionalLogType() {
292         assert false : "Txnl access to UP db not allowed";
293         return LogEntryType.LOG_FILESUMMARYLN;
294     }
295
296     /**
297      * @see LN#getLogType
298      */

299     public LogEntryType getLogType() {
300         return LogEntryType.LOG_FILESUMMARYLN;
301     }
302
303     /**
304      * @see LoggableObject#marshallOutsideWriteLatch
305      * FileSummaryLNs must be marshalled within the log write latch, because
306      * that critical section is used to guarantee that all previous log
307      * entries are reflected in the summary.
308      */

309     public boolean marshallOutsideWriteLatch() {
310         return false;
311     }
312
313     /**
314      * @see LoggableObject#countAsObsoleteWhenLogged
315      */

316     public boolean countAsObsoleteWhenLogged() {
317         return false;
318     }
319
320     /**
321      * @see LN#getLogSize
322      */

323     public int getLogSize() {
324         int size = super.getLogSize();
325         if (!isDeleted()) {
326             size += baseSummary.getLogSize();
327             getOffsets();
328             size += obsoleteOffsets.getLogSize();
329         }
330         return size;
331     }
332
333     /**
334      * @see LN#writeToLog
335      */

336     public void writeToLog(ByteBuffer JavaDoc logBuffer) {
337
338         /*
339          * Add the tracked (live) summary to the base summary before writing it
340          * to the log, and reset the tracked summary. Do this even when
341          * deleting the LN, so that the tracked summary is cleared.
342          */

343         if (trackedSummary != null) {
344
345             baseSummary.add(trackedSummary);
346
347             if (!isDeleted()) {
348                 getOffsets();
349             }
350
351             /* Reset the totals to zero and clear the tracked offsets. */
352             trackedSummary.reset();
353         }
354
355         super.writeToLog(logBuffer);
356
357         if (!isDeleted()) {
358             baseSummary.writeToLog(logBuffer);
359             obsoleteOffsets.writeToLog(logBuffer);
360         }
361     }
362
363     /**
364      * @see LN#readFromLog
365      */

366     public void readFromLog(ByteBuffer JavaDoc itemBuffer, byte entryTypeVersion)
367         throws LogException {
368
369         super.readFromLog(itemBuffer, entryTypeVersion);
370
371         logVersion = entryTypeVersion;
372
373         if (!isDeleted()) {
374             baseSummary.readFromLog(itemBuffer, entryTypeVersion);
375             if (entryTypeVersion > 0) {
376                 obsoleteOffsets.readFromLog(itemBuffer, entryTypeVersion);
377             }
378         }
379     }
380
381     /**
382      * If tracked offsets may be present, get them so they are ready to be
383      * written to the log.
384      */

385     private void getOffsets() {
386         if (needOffsets) {
387             long[] offsets = trackedSummary.getObsoleteOffsets();
388             if (offsets != null) {
389                 obsoleteOffsets.pack(offsets);
390             }
391             needOffsets = false;
392         }
393     }
394 }
395
Popular Tags