KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > activemq > kaha > impl > index > tree > TreeIndex


1 /**
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE
4  * file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file
5  * to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
6  * License. You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
11  * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
12  * specific language governing permissions and limitations under the License.
13  */

14
15 package org.apache.activemq.kaha.impl.index.tree;
16
17 import java.io.File JavaDoc;
18 import java.io.IOException JavaDoc;
19 import java.io.RandomAccessFile JavaDoc;
20 import java.util.concurrent.atomic.AtomicBoolean JavaDoc;
21 import org.apache.activemq.kaha.Marshaller;
22 import org.apache.activemq.kaha.StoreEntry;
23 import org.apache.activemq.kaha.impl.index.Index;
24 import org.apache.activemq.kaha.impl.index.IndexManager;
25 import org.apache.activemq.util.DataByteArrayInputStream;
26 import org.apache.activemq.util.DataByteArrayOutputStream;
27 import org.apache.activemq.util.LRUCache;
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30
31 /**
32  * BTree implementation
33  *
34  * @version $Revision: 1.1.1.1 $
35  */

36 public class TreeIndex implements Index{
37
38     private static final String JavaDoc NAME_PREFIX="tree-index-";
39     private static final int DEFAULT_PAGE_SIZE;
40     private static final int DEFAULT_KEY_SIZE;
41     private static final Log log=LogFactory.getLog(TreeIndex.class);
42     private final String JavaDoc name;
43     private File JavaDoc directory;
44     private File JavaDoc file;
45     private RandomAccessFile JavaDoc indexFile;
46     private IndexManager indexManager;
47     private int pageSize=DEFAULT_PAGE_SIZE;
48     private int keySize=DEFAULT_KEY_SIZE;
49     private int keysPerPage=pageSize/keySize;
50     private TreePage root;
51     private LRUCache<Long JavaDoc,TreePage> pageCache;
52     private DataByteArrayInputStream dataIn;
53     private DataByteArrayOutputStream dataOut;
54     private byte[] readBuffer;
55     private Marshaller keyMarshaller;
56     private long length=0;
57     private TreePage firstFree;
58     private TreePage lastFree;
59     private AtomicBoolean JavaDoc loaded=new AtomicBoolean JavaDoc();
60     private boolean enablePageCaching=true;
61     private int pageCacheSize=10;
62
63     /**
64      * Constructor
65      *
66      * @param directory
67      * @param name
68      * @param indexManager
69      * @throws IOException
70      */

71     public TreeIndex(File JavaDoc directory,String JavaDoc name,IndexManager indexManager) throws IOException JavaDoc{
72         this.directory=directory;
73         this.name=name;
74         this.indexManager=indexManager;
75         pageCache=new LRUCache<Long JavaDoc,TreePage>(pageCacheSize,pageCacheSize,0.75f,true);
76         openIndexFile();
77     }
78
79     /**
80      * Set the marshaller for key objects
81      *
82      * @param marshaller
83      */

84     public void setKeyMarshaller(Marshaller marshaller){
85         if(loaded.get()){
86             throw new RuntimeException JavaDoc("Pages already loaded - can't set marshaller now");
87         }
88         this.keyMarshaller=marshaller;
89     }
90
91     /**
92      * @return the keySize
93      */

94     public int getKeySize(){
95         return this.keySize;
96     }
97
98     /**
99      * @param keySize the keySize to set
100      */

101     public void setKeySize(int keySize){
102         this.keySize=keySize;
103         if(loaded.get()){
104             throw new RuntimeException JavaDoc("Pages already loaded - can't reset key size");
105         }
106     }
107
108     /**
109      * @return the pageSize
110      */

111     public int getPageSize(){
112         return this.pageSize;
113     }
114
115     /**
116      * @param pageSize the pageSize to set
117      */

118     public void setPageSize(int pageSize){
119         if(loaded.get()&&pageSize!=this.pageSize){
120             throw new RuntimeException JavaDoc("Pages already loaded - can't reset page size");
121         }
122         this.pageSize=pageSize;
123     }
124
125     public boolean isTransient(){
126         return false;
127     }
128
129     /**
130      * @return the enablePageCaching
131      */

132     public boolean isEnablePageCaching(){
133         return this.enablePageCaching;
134     }
135
136     /**
137      * @param enablePageCaching the enablePageCaching to set
138      */

139     public void setEnablePageCaching(boolean enablePageCaching){
140         this.enablePageCaching=enablePageCaching;
141     }
142
143     /**
144      * @return the pageCacheSize
145      */

146     public int getPageCacheSize(){
147         return this.pageCacheSize;
148     }
149
150     /**
151      * @param pageCacheSize the pageCacheSize to set
152      */

153     public void setPageCacheSize(int pageCacheSize){
154         this.pageCacheSize=pageCacheSize;
155         pageCache.setMaxCacheSize(pageCacheSize);
156     }
157
158     public void load(){
159         if(loaded.compareAndSet(false,true)){
160             keysPerPage=pageSize/keySize;
161             dataIn=new DataByteArrayInputStream();
162             dataOut=new DataByteArrayOutputStream(pageSize);
163             readBuffer=new byte[pageSize];
164             try{
165                 openIndexFile();
166                 long offset=0;
167                 while((offset+pageSize)<=indexFile.length()){
168                     indexFile.seek(offset);
169                     indexFile.readFully(readBuffer,0,TreePage.PAGE_HEADER_SIZE);
170                     dataIn.restart(readBuffer);
171                     TreePage page=new TreePage(keysPerPage);
172                     page.setTree(this);
173                     page.setId(offset);
174                     page.readHeader(dataIn);
175                     if(!page.isActive()){
176                         if(lastFree!=null){
177                             lastFree.setNextFreePageId(offset);
178                             indexFile.seek(lastFree.getId());
179                             dataOut.reset();
180                             lastFree.writeHeader(dataOut);
181                             indexFile.write(dataOut.getData(),0,TreePage.PAGE_HEADER_SIZE);
182                             lastFree=page;
183                         }else{
184                             lastFree=firstFree=page;
185                         }
186                     }else if(root==null&&page.isRoot()){
187                         root=getFullPage(offset);
188                     }
189                     offset+=pageSize;
190                 }
191                 length=offset;
192                 if(root==null){
193                     root=createRoot();
194                 }
195             }catch(IOException JavaDoc e){
196                 log.error("Failed to load index ",e);
197                 throw new RuntimeException JavaDoc(e);
198             }
199         }
200     }
201
202     public void unload() throws IOException JavaDoc{
203         if(loaded.compareAndSet(true,false)){
204             if(indexFile!=null){
205                 indexFile.close();
206                 indexFile=null;
207                 pageCache.clear();
208                 root=null;
209                 firstFree=lastFree=null;
210             }
211         }
212     }
213
214     public void store(Object JavaDoc key,StoreEntry value) throws IOException JavaDoc{
215         TreeEntry entry=new TreeEntry();
216         entry.setKey((Comparable JavaDoc)key);
217         entry.setIndexOffset(value.getOffset());
218         root.put(entry);
219     }
220
221     public StoreEntry get(Object JavaDoc key) throws IOException JavaDoc{
222         TreeEntry entry=new TreeEntry();
223         entry.setKey((Comparable JavaDoc)key);
224         TreeEntry result=root.find(entry);
225         return result!=null?indexManager.getIndex(result.getIndexOffset()):null;
226     }
227
228     public StoreEntry remove(Object JavaDoc key) throws IOException JavaDoc{
229         TreeEntry entry=new TreeEntry();
230         entry.setKey((Comparable JavaDoc)key);
231         TreeEntry result = root.remove(entry);
232         return result!=null?indexManager.getIndex(result.getIndexOffset()):null;
233     }
234
235     public boolean containsKey(Object JavaDoc key) throws IOException JavaDoc{
236         TreeEntry entry=new TreeEntry();
237         entry.setKey((Comparable JavaDoc)key);
238         return root.find(entry)!=null;
239     }
240
241     public void clear() throws IOException JavaDoc{
242         unload();
243         delete();
244         openIndexFile();
245         load();
246     }
247
248     public void delete() throws IOException JavaDoc{
249         unload();
250         if(file.exists()){
251             boolean result=file.delete();
252         }
253         length=0;
254     }
255
256     /**
257      * @return the root
258      */

259     TreePage getRoot(){
260         return this.root;
261     }
262
263
264     TreePage lookupPage(long pageId) throws IOException JavaDoc{
265         TreePage result=null;
266         if(pageId>=0){
267             if(root!=null&&root.getId()==pageId){
268                 result=root;
269             }else{
270                 result=getFromCache(pageId);
271             }
272             if(result==null){
273                 result=getFullPage(pageId);
274                 if(result!=null){
275                     if(result.isActive()){
276                         addToCache(result);
277                     }else{
278                         throw new IllegalStateException JavaDoc("Trying to access an inactive page: "+pageId+" root is "+root);
279                     }
280                 }
281             }
282         }
283         return result;
284     }
285
286     TreePage createRoot() throws IOException JavaDoc{
287         TreePage result=createPage(-1);
288         root=result;
289         return result;
290     }
291
292     TreePage createPage(long parentId) throws IOException JavaDoc{
293         TreePage result=getNextFreePage();
294         if(result==null){
295             // allocate one
296
result=new TreePage(keysPerPage);
297             result.setId(length);
298             result.setTree(this);
299             result.setParentId(parentId);
300             writePage(result);
301             length+=pageSize;
302             indexFile.seek(length);
303             indexFile.write(TreeEntry.NOT_SET);
304         }
305         addToCache(result);
306         return result;
307     }
308
309     void releasePage(TreePage page) throws IOException JavaDoc{
310         removeFromCache(page);
311         page.reset();
312         page.setActive(false);
313         if(lastFree==null){
314             firstFree=lastFree=page;
315         }else{
316             lastFree.setNextFreePageId(page.getId());
317             writePage(lastFree);
318         }
319         writePage(page);
320     }
321     
322     private TreePage getNextFreePage() throws IOException JavaDoc{
323         TreePage result=null;
324         if(firstFree!=null){
325             if(firstFree.equals(lastFree)){
326                 result=firstFree;
327                 firstFree=lastFree=null;
328             }else{
329                 result=firstFree;
330                 firstFree=getPage(firstFree.getNextFreePageId());
331                 if(firstFree==null){
332                     lastFree=null;
333                 }
334             }
335             result.setActive(true);
336             result.reset();
337             result.saveHeader();
338         }
339         return result;
340     }
341
342     void writeFullPage(TreePage page) throws IOException JavaDoc{
343         dataOut.reset();
344         page.write(keyMarshaller,dataOut);
345         if(dataOut.size()>pageSize){
346             throw new IOException JavaDoc("Page Size overflow: pageSize is "+pageSize+" trying to write "+dataOut.size());
347         }
348         indexFile.seek(page.getId());
349         indexFile.write(dataOut.getData(),0,dataOut.size());
350     }
351
352     void writePage(TreePage page) throws IOException JavaDoc{
353         dataOut.reset();
354         page.writeHeader(dataOut);
355         indexFile.seek(page.getId());
356         indexFile.write(dataOut.getData(),0,TreePage.PAGE_HEADER_SIZE);
357     }
358
359     TreePage getFullPage(long id) throws IOException JavaDoc{
360         indexFile.seek(id);
361         indexFile.readFully(readBuffer,0,pageSize);
362         dataIn.restart(readBuffer);
363         TreePage page=new TreePage(keysPerPage);
364         page.setId(id);
365         page.setTree(this);
366         page.read(keyMarshaller,dataIn);
367         return page;
368     }
369
370     TreePage getPage(long id) throws IOException JavaDoc{
371         indexFile.seek(id);
372         indexFile.readFully(readBuffer,0,TreePage.PAGE_HEADER_SIZE);
373         dataIn.restart(readBuffer);
374         TreePage page=new TreePage(keysPerPage);
375         page.setId(id);
376         page.setTree(this);
377         page.readHeader(dataIn);
378         return page;
379     }
380
381     
382
383     private TreePage getFromCache(long pageId){
384         TreePage result=null;
385         if(enablePageCaching){
386             result=pageCache.get(pageId);
387         }
388         return result;
389     }
390
391     private void addToCache(TreePage page){
392         if(enablePageCaching){
393             pageCache.put(page.getId(),page);
394         }
395     }
396
397     private void removeFromCache(TreePage page){
398         if(enablePageCaching){
399             pageCache.remove(page.getId());
400         }
401     }
402
403     protected void openIndexFile() throws IOException JavaDoc{
404         if(indexFile==null){
405             file=new File JavaDoc(directory,NAME_PREFIX+name);
406             indexFile=new RandomAccessFile JavaDoc(file,"rw");
407         }
408     }
409     static{
410         DEFAULT_PAGE_SIZE=Integer.parseInt(System.getProperty("defaultPageSize","16384"));
411         DEFAULT_KEY_SIZE=Integer.parseInt(System.getProperty("defaultKeySize","96"));
412     }
413 }
414
Popular Tags