KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > mdr > persistence > btreeimpl > btreestorage > LogFile


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.netbeans.mdr.persistence.btreeimpl.btreestorage;
20
21 import java.io.*;
22 import java.text.*;
23 import java.util.*;
24
25 import org.netbeans.mdr.persistence.*;
26
27 /** The transaction log file used by the FileCache.
28 * <p>
29 * The scheme used is before-image logging. That is, before a page is modified,
30 * its contents are written to the log file. The log file itself contains two
31 * sorts of pages: these before-image pages, and map pages, which keep track
32 * of the PageID of each before-image file.
33 * <p>
34 * At the successful completion of each transaction, the log file is deleted.
35 * If, on cache creation, the log file exists, this indicates that a previous
36 * transaction did not complete successfully. Recovery is attempted, using the
37 * contents of the log file to back out the partially completed transaction.
38 */

39 class LogFile {
40
41     /* page size for the cache */
42     private int pageSize;
43
44     /* number of files in the cache */
45     private int numFiles;
46
47     /* name of the log file */
48     private final String JavaDoc baseName;
49
50     /* name of the log file */
51     private String JavaDoc name;
52
53     /* bitmaps showing which pages are currently logged */
54     private BitSet pageBitmaps[];
55
56     /* the current map page */
57     private MapPage currentMap;
58
59     /* owning cache */
60     private FileCache cache;
61
62     /* file ID */
63     long fileId;
64
65     /* counts for forced failure during regreession tests */
66     private int beforeWriteFailure = -1;
67     private int afterCommitFailure = -1;
68     private int recoveryFailure = -1;
69
70     /** Create the log file. If the file already exists on disk,
71     * attempt recovery. Note that exceptions pnly occur during recovery.
72     * @param fCache the cache which owns this log file
73     * @param baseName the name of the log file without the suffix - i.e. name of the repository
74     * @param pgSz the page size
75     * @param files the number of files being logged
76     * @param id the fileId for the files being logged
77     * @exception StorageException I/O error during recovery
78     * @exception BadParameterException the log file is not consistent with
79     * the files being recovered
80     * @exception ConsistencyException the log file is corrupt on disk
81     */

82     LogFile(FileCache fCache, String JavaDoc baseName, int pgSz, int files, long id)
83             throws StorageException {
84         // Size must be a power of 2 and >= 4096
85
// no more than 4096 files
86
cache = fCache;
87         pageSize = pgSz;
88         this.baseName = baseName;
89         numFiles = files;
90         fileId = id;
91         pageBitmaps = new BitSet[files];
92         for (int i = 0; i < files; i++)
93             pageBitmaps[i] = new BitSet();
94
95         if (new File(BtreeDatabase.getFileName(baseName, BtreeDatabase.LFL)).exists())
96             recover();
97     }
98
99     /* returns true if page is already logged */
100     private boolean isPageLogged(CachedPage page) {
101         return pageBitmaps[page.key.fileIndex].get(page.key.offset/pageSize);
102     }
103
104     /* create the log file */
105     private RandomAccessFile createPhysicalLog() throws StorageException {
106         String JavaDoc name = BtreeDatabase.getFileName(baseName, BtreeDatabase.LFL);
107         RandomAccessFile file = null;
108         try {
109             file = FileCache.getFile(name);
110             file.setLength(0);
111             writeMap(file);
112             return file;
113         } catch (IOException ex) {
114             throw new StorageIOException(ex);
115         } finally {
116             if (file != null) {
117                 this.name = name;
118             }
119         }
120     }
121
122     /* add a new page to the log file
123     * @param page the page to add
124     * @exception StorageException error loggin the page to the before file
125     */

126     void addPageToLog(CachedPage page) throws StorageException {
127
128         if (page.key.offset >= currentMap.getEOF(page.key.fileIndex)) {
129                 return;
130         }
131
132         if (isPageLogged(page))
133             return;
134
135         RandomAccessFile file;
136         try {
137             file = name == null ? createPhysicalLog() : FileCache.getFile(name);
138             file.seek(currentMap.nextPageOffset());
139             file.write(page.contents);
140         }
141         catch (IOException ex) {
142             throw new StorageIOException(ex);
143         }
144
145         beforeWriteFailure =
146             cache.checkForForcedFailure(
147         "org.netbeans.mdr.persistence.btreeimpl.btreestorage.LogFile.beforeWriteFailure",
148                 beforeWriteFailure);
149         pageBitmaps[page.key.fileIndex].set(page.key.offset/pageSize);
150
151         /* add to map */
152         currentMap.add(page);
153         if (currentMap.isFull()) {
154
155             // map is full; need to write it
156
writeMap(file);
157         }
158
159         /* prevent from being written until log is flushed */
160         cache.holdForLog(page);
161     }
162
163     /* write the current map page to the log */
164     private void writeMap(RandomAccessFile file) throws StorageException{
165         flushFile(file);
166         currentMap.write(file);
167         flushFile(file);
168         if (currentMap.isFull())
169             currentMap = new MapPage(currentMap);
170     }
171
172     /* sync the file to disk */
173     private void flushFile(RandomAccessFile file) throws StorageException{
174         try {
175             file.getFD().sync();
176         }
177         catch (IOException ex) {
178             throw new StorageIOException(ex);
179         }
180     }
181
182     /** make the log consistent on disk
183     * @exception StorageException I/O error writing the log
184     */

185     void flush() throws StorageException{
186         try {
187             writeMap(FileCache.getFile(name));
188             cache.logWasFlushed();
189         } catch (IOException e) {
190             throw new StorageIOException(e);
191         }
192     }
193
194     /** begin a new transaction
195     * @param files the files being logged
196     * @param timeStamp the timestamp for the previously comitted transaction
197     * @param long newTimeStamp the timestamp for the new transaction
198     * @exception StorageException I/O error accessing the files
199     */

200     void begin(String JavaDoc fileNames[], long timeStamp, long newTimeStamp)
201                 throws StorageException {
202
203         name = null;
204         currentMap = new MapPage(pageSize, numFiles, 0);
205         RandomAccessFile files[];
206         try {
207             files = FileCache.getFiles(fileNames);
208         } catch (IOException e) {
209             throw new StorageIOException(e);
210         }
211         currentMap.setEOFs(files);
212         for (int i = 0; i < numFiles; i++) {
213             pageBitmaps[i].xor(pageBitmaps[i]);
214         }
215         currentMap.setTimeStamps(timeStamp, newTimeStamp);
216         currentMap.setFileID(fileId);
217     }
218
219     /** commit the current transaction
220     * @exception StorageException I/O error closing or deleting the log
221     */

222     void commit() throws StorageException{
223         try {
224             if (name != null) {
225                 FileCache.closeFile(name);
226                 new File(name).delete();
227             }
228         }
229         catch (IOException ex) {
230             throw new StorageIOException(ex);
231         }
232         name = null;
233         afterCommitFailure =
234             cache.checkForForcedFailure(
235         "org.netbeans.mdr.persistence.btreeimpl.btreestorage.LogFile.afterCommitFailure",
236             afterCommitFailure);
237     }
238
239     /** close the log file
240     * @exception StorageException I/O error closing the log
241     */

242     void close() throws StorageException{
243         try {
244             if (name != null) {
245                 FileCache.closeFile(name);
246         }
247         } catch (IOException ex) {
248             throw new StorageIOException(ex);
249         }
250     }
251
252     /** return the current log file size */
253     int fileSize() {
254         return currentMap.nextPageOffset();
255     }
256
257     /** recover from an incomplete transaction
258     * @exception StorageException I/O error during recovery
259     * @exception BadParameterException the log file is not consistent with
260     * the files being recovered
261     * @exception ConsistencyException the log file is corrupt on disk
262     */

263     void recover() throws StorageException {
264         RandomAccessFile files[] = null;
265         RandomAccessFile logFile = null;
266
267         try {
268             try {
269                 logFile = new RandomAccessFile(BtreeDatabase.getFileName(baseName, BtreeDatabase.LFL), "r");
270                 files = cache.getFiles();
271                 if (files.length != numFiles) {
272                     throw new StorageBadRequestException(
273                         MessageFormat.format(
274                             "Log file contains {0} files; {1} were requested",
275                             new Object JavaDoc[] {
276                                 new Integer JavaDoc(numFiles),
277                                 new Integer JavaDoc(files.length)}));
278                 }
279
280                 int numPages = (int)logFile.length() / pageSize;
281                 if (numPages > 0) {
282                     byte pageBuffer[] = new byte[pageSize];
283
284                     MapPage page = new MapPage(logFile, 0, pageSize);
285                     page.checkParameters(pageSize, numFiles);
286
287                     for (int i = 0; i < numFiles; i++) {
288                         page.checkFileHeader(files[i]);
289
290                     }
291                     while (true) {
292                         page.recover(files, logFile, numPages, pageBuffer);
293
294                         recoveryFailure =
295                             cache.checkForForcedFailure(
296                 "org.netbeans.mdr.persistence.btreeimpl.btreestorage.LogFile.recoveryFailure",
297                                 recoveryFailure);
298                         MapPage newPage = page.getNext(logFile, numPages);
299                         if (newPage != null && !newPage.isEmpty()) {
300                             page = newPage;
301                         }
302                         else {
303                             break;
304                         }
305                     }
306
307                     page.truncateFiles(files);
308                     logFile.close();
309                     (new File(BtreeDatabase.getFileName(baseName, BtreeDatabase.LFL))).delete();
310                 }
311             }
312             finally {
313                 if (logFile != null) {
314                     logFile.close();
315
316                 }
317             }
318         }
319         catch (IOException ex) {
320             throw new StorageIOException(ex);
321         }
322     }
323 }
324
325
326
Popular Tags