KickJava   Java API By Example, From Geeks To Geeks.

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


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 org.netbeans.mdr.persistence.btreeimpl.btreeindex.*;
22 import org.netbeans.mdr.persistence.*;
23 import java.io.*;
24 import java.text.*;
25 import java.util.*;
26
27 /**
28  * BtreePageSource implementation for pages which are stored directly in a file
29  * (the primary index pages) rather than as repository objects. The file
30  * access is all handled by the FileCache class.
31  *
32  * @author Dana Bergen
33  * @version 1.0
34  */

35
36 public class BtreeFileSource extends Object JavaDoc
37             implements BtreePageSource, FileCache.NotifyOnCommit {
38
39 /*
40  * A page exists in two forms: as an instantiated BtreePage object, and as
41  * a byte array. On disk or in the FileCache, it is in the array form.
42  * Each BtreePage has a reference (pageBuffer) to its array in the
43  * FileCache.
44  *
45  * BtreeFileSource also maintains a cache of instantiated BtreePage's.
46  * These cached BtreePage's may be reused, that is reinitialized
47  * from a different page buffer for a different page.
48  *
49  * All pages in the BtreePage cache are pinned with respect to the
50  * FileCache regardless of whether they are pinned with respect to the
51  * BtreePage cache. A page is unpinned in the BtreePage cache if the BtreePage
52  * is not in use. When a BtreePage is removed from the BtreePage cache, it is
53  * then unpinned with respect to the FileCache.
54  */

55     static final int MAGIC = 123456789;
56     static final int VERSION = 1;
57     static final int NO_PAGEID = -1;
58     static final int NEXTFREE_OFFSET = FileHeader.HEADER_SIZE + 8;
59     static final int CACHE_SIZE = 5;
60
61
62     private FileCache fileCache; // source of pages from file
63
private int fileId; // file where our pages are stored,
64
// for making FileCache requests
65
private int pageSize;
66     private EntryTypeInfo pageIdInfo;
67     private byte[] noPageId;
68     private boolean metaChanged;
69     private int nextFree; // page number of next free page
70
private BtreeStorage storage;
71
72     private Hashtable btreeCache; // BtreePages hashed on pageId
73
private IntrusiveList lruList; // unpinned BtreePages lru first
74

75     private MofidGenerator gen;
76
77     private static class CacheEntry extends IntrusiveList.Member {
78         BtreePage page;
79     CachedPage fcp; // FileCache's cache entry
80
int pinned; // number of current users of this page
81
boolean needsStore; // has the page been modified
82
}
83
84     /**
85      * Constructor for a BtreeFileSource from a new or existing index file.
86      *
87      * @param fileId file ID to use in FileCache requests
88      * @param fileCache source of index pages
89      * @param pageSize size of index pages
90      * @param isNew true if this index is being newly created
91      * @param mGen Mofid generator
92      */

93     public BtreeFileSource(int fileId, FileCache fileCache, int pageSize,
94                     boolean isNew, MofidGenerator mGen, BtreeStorage storage)
95                 throws StorageException {
96
97     CachedPage metaFCP;
98     byte[] metadata;
99     int offset;
100
101     this.fileId = fileId;
102     this.fileCache = fileCache;
103     this.pageSize = pageSize;
104         this.storage = storage;
105     gen = mGen;
106
107     pageIdInfo = EntryTypeInfo.getEntryTypeInfo(Storage.EntryType.INT, null);
108     noPageId = pageIdInfo.toBuffer(new Integer JavaDoc(NO_PAGEID));
109     btreeCache = new Hashtable(10);
110     lruList = new IntrusiveList();
111
112     metaChanged = false;
113     
114     metaFCP = fileCache.getPage(fileId, 0);
115     metadata = metaFCP.contents;
116     offset = FileHeader.HEADER_SIZE;
117
118     if (isNew) {
119         // Initialize the metadata page
120
offset = Converter.writeInt(metadata, offset, MAGIC);
121         offset = Converter.writeInt(metadata, offset, VERSION);
122         nextFree = 1;
123         offset = Converter.writeInt(metadata, offset, nextFree);
124         fileCache.setWritable(metaFCP);
125     } else {
126         // Read the metadata page and verify
127
int magic, version;
128         magic = Converter.readInt(metadata, offset);
129         offset += 4;
130         version = Converter.readInt(metadata, offset);
131         offset += 4;
132         nextFree = Converter.readInt(metadata, offset);
133          
134         if (magic != MAGIC) {
135         throw new StorageBadRequestException(
136             MessageFormat.format(
137             "Index file has bad magic number ",
138             new Object JavaDoc[] {new Integer JavaDoc(magic) } ));
139         }
140         if (version != VERSION) {
141         throw new StorageBadRequestException(
142             MessageFormat.format(
143         "Index file has incorrect version number. {0} expected, {1} found",
144             new Object JavaDoc[] {
145             new Integer JavaDoc(VERSION),
146             new Integer JavaDoc(version) } ));
147         }
148     }
149
150     fileCache.unpin(metaFCP);
151
152     fileCache.addNotifier(this);
153     }
154
155     public EntryTypeInfo getPageIdInfo() {
156     return new IntInfo();
157     }
158
159     /**
160      * Set the passed-in pageId to contain the special value noPageId
161      */

162     public void setNoPage(byte[] pageId) {
163
164         System.arraycopy(noPageId, 0, pageId, 0, pageId.length);
165     }
166
167     /**
168      * Test whether the passed-in pageId contains the special value noPageId
169      */

170     public boolean isNoPage(byte[] pageId) {
171     
172     for (int i = 0; i < pageId.length; i++) {
173         if (pageId[i] != noPageId[i]) {
174             return false;
175         }
176     }
177     return true;
178     }
179
180     /**
181      * Prepares all cached modified pages to be written out.
182      */

183     public synchronized void prepareToCommit() throws StorageException {
184
185         Enumeration entries;
186     CacheEntry entry;
187     CachedPage metaFCP;
188
189     entries = btreeCache.elements();
190
191     while (entries.hasMoreElements()) {
192         entry = (CacheEntry) entries.nextElement();
193         if (entry.needsStore) {
194         entry.page.store();
195         }
196     }
197     
198     /* Update the metadata page if necessary */
199         if (metaChanged) {
200         metaFCP = fileCache.getPage(fileId, 0);
201         fileCache.setWritable(metaFCP);
202         Converter.writeInt(metaFCP.contents, NEXTFREE_OFFSET, nextFree);
203         fileCache.unpin(metaFCP);
204     }
205     metaChanged = false;
206     }
207
208     /**
209      * Return the root page if it already exists, otherwise create it.
210      *
211      * @return BtreePage which is the root page
212      */

213     public BtreePage getRootPage(Btree btree) throws StorageException {
214
215         if (nextFree > 1) {
216         return getPage(pageIdInfo.toBuffer(new Integer JavaDoc(1)), btree);
217     } else {
218         return newPage(btree);
219     }
220     }
221
222     /**
223      * Get a BtreePage by its pageId.
224      *
225      * @param pageId Byte array containing pageId
226      *
227      * @return The page identified by pageId.
228      *
229      * @exception StorageException If the page is not valid
230      */

231     public synchronized BtreePage getPage(byte[] pageId, Btree btree)
232                             throws StorageException {
233         Integer JavaDoc pageNum;
234     CacheEntry entry;
235
236     pageNum = (Integer JavaDoc) pageIdInfo.fromBuffer(pageId);
237     entry = (CacheEntry) btreeCache.get(pageNum);
238     if (entry == null) {
239         entry = addToBtreeCache(pageId, pageNum, false, btree);
240     } else if (entry.pinned == 0) {
241         lruList.remove((IntrusiveList.Member)entry);
242     }
243     entry.pinned++;
244     return entry.page;
245     }
246
247     private CacheEntry addToBtreeCache(byte[] pageId,
248                 Integer JavaDoc pageNum, boolean isNew, Btree btree)
249                         throws StorageException {
250         
251     CacheEntry entry;
252
253     entry = getCacheEntry();
254     entry.fcp = fileCache.getPage(fileId, pageNum.intValue());
255     if (entry.page == null) {
256         entry.page = btree.pageFactory();
257     } else {
258         entry.page.uninit();
259     }
260     entry.page.init(btree, pageId, entry.fcp.contents, isNew);
261     btreeCache.put(pageNum, entry);
262     return entry;
263     }
264
265     private CacheEntry getCacheEntry() throws StorageException {
266
267     CacheEntry entry = null;
268     Integer JavaDoc pageNum;
269
270         if (btreeCache.size() >= CACHE_SIZE) {
271         /* look for a page to recycle */
272         entry = (CacheEntry) lruList.removeFirst();
273     }
274     if (entry != null) {
275         pageNum = (Integer JavaDoc) pageIdInfo.fromBuffer(entry.page.pageId);
276         btreeCache.remove(pageNum);
277         if (entry.needsStore) {
278             entry.page.store();
279         entry.needsStore = false;
280         }
281         fileCache.unpin(entry.fcp);
282         } else {
283             entry = new CacheEntry();
284     }
285     return entry;
286     }
287
288     /**
289      * Returns a newly allocated btree page.
290      *
291      * @return A new BtreePage
292      *
293      * @exception StorageException If the page is not valid
294      */

295     public synchronized BtreePage newPage(Btree btree) throws StorageException {
296
297         CacheEntry entry;
298     Integer JavaDoc pageNum;
299     byte[] pageId;
300
301     pageNum = new Integer JavaDoc(nextFree);
302     nextFree++;
303     metaChanged = true;
304     pageId = pageIdInfo.toBuffer(pageNum);
305     entry = addToBtreeCache(pageId, pageNum, true, btree);
306     entry.pinned++;
307     dirtyPage(entry.page);
308     return entry.page;
309     }
310
311     /**
312      * Returns a newly allocated BigKeyPage.
313      * BigKeyPages are not recycled. They are only cached while in use.
314      */

315     public synchronized BigKeyPage newBigKeyPage(Btree btree)
316                             throws StorageException {
317     CacheEntry entry;
318     Integer JavaDoc pageNum;
319     byte[] pageId;
320
321     pageNum = new Integer JavaDoc(nextFree);
322     nextFree++;
323     metaChanged = true;
324     pageId = pageIdInfo.toBuffer(pageNum);
325     entry = new CacheEntry();
326     entry.fcp = fileCache.getPage(fileId, pageNum.intValue());
327     entry.page = new BigKeyPage();
328     entry.page.init(btree, pageId, entry.fcp.contents, true);
329     btreeCache.put(pageNum, entry);
330     entry.pinned++;
331     dirtyPage(entry.page);
332     return (BigKeyPage)entry.page;
333     }
334     
335     /**
336      * Notifies the btree that the caller is done using this page. This
337      * decrements its pinned count in the btree cache. It does not change
338      * its pinned status in the FileCache; that only happens when a page is
339      * removed from the btree cache.
340      *
341      * @param page BtreePage to be unpinned
342      */

343     public synchronized void unpinPage(BtreePage page) {
344         
345     CacheEntry entry;
346
347     entry = (CacheEntry) btreeCache.get(pageIdInfo.fromBuffer(page.pageId));
348     if (--entry.pinned == 0) {
349         lruList.addLast((IntrusiveList.Member)entry);
350     }
351     }
352         
353     public synchronized void unpinPage(BigKeyPage page) throws StorageException {
354
355     CacheEntry entry;
356     Integer JavaDoc pageNum;
357
358     entry = (CacheEntry) btreeCache.get(pageIdInfo.fromBuffer(page.pageId));
359     if (--entry.pinned == 0) {
360         pageNum = (Integer JavaDoc) pageIdInfo.fromBuffer(entry.page.pageId);
361         btreeCache.remove(pageNum);
362         if (entry.needsStore) {
363             entry.page.store();
364         entry.needsStore = false;
365         }
366         fileCache.unpin(entry.fcp);
367     }
368     }
369
370     /**
371      * Notifies the btree that the caller is going to modify this page.
372      * This must be called prior to modifying the page contents.
373      *
374      * @param page The page being modified
375      */

376     public synchronized void dirtyPage(BtreePage page) throws StorageException {
377         
378     CacheEntry entry;
379
380     entry = (CacheEntry) btreeCache.get(pageIdInfo.fromBuffer(page.pageId));
381     entry.needsStore = true;
382     fileCache.setWritable(entry.fcp);
383     }
384
385     public int getPageIdLength() {
386         return pageIdInfo.getLength();
387     }
388
389     public int getPageSize() {
390         return pageSize;
391     }
392
393     public long getNextMofid() {
394         if (gen != null)
395         return gen.getNextMofid();
396         throw new RuntimeException JavaDoc("Not implemented");
397     }
398
399     public String JavaDoc getMofidPrefix() {
400         if (gen != null)
401         return gen.getMofidPrefix();
402         throw new RuntimeException JavaDoc("Not implemented");
403     }
404     
405     public BtreeStorage getStorage () {
406         return storage;
407     }
408     
409 }
410
Popular Tags