KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > ozoneDB > core > storage > gammaStore > IndexNode


1 // You can redistribute this software and/or modify it under the terms of
2
// the Ozone Core License version 1 published by ozone-db.org.
3
//
4
// Copyright (C) 2003-@year@, Leo Mekenkamp. All rights reserved.
5
//
6
// $Id: IndexNode.java,v 1.4 2004/02/01 20:55:47 leomekenkamp Exp $
7

8 package org.ozoneDB.core.storage.gammaStore;
9
10 import java.io.ByteArrayInputStream JavaDoc;
11 import java.io.IOException JavaDoc;
12 import java.io.ObjectInputStream JavaDoc;
13 import java.util.logging.Level JavaDoc;
14 import java.util.logging.Logger JavaDoc;
15 import org.ozoneDB.OzoneInternalException;
16 import org.ozoneDB.core.storage.Cache;
17
18 /**
19  * <p>Index nodes are the nodes that make up the tree used for storing
20  * information on where objects can be found (cluster + location). Because
21  * memory is limited, it is impossible to have all index nodes in memory under
22  * all circumstances. Therefor there are no hard references to other index nodes
23  * but only ids are stored.</p>
24  *
25  * <p>There is not much logic here, most logic is in <code>IndexManager</code>.
26  * </p>
27  *
28  * @author <a HREF="mailto:leoATmekenkampD0Tcom">Leo Mekenkamp (mind the anti sp@m)</a>
29  * @version $Id: IndexNode.java,v 1.4 2004/02/01 20:55:47 leomekenkamp Exp $
30  */

31 public abstract class IndexNode implements Storable {
32     
33     private static final long serialVersionUID = 0L;
34
35     protected static final Logger JavaDoc log = Logger.getLogger(IndexNode.class.getName());
36
37     static {
38 // log.setLevel(Level.ALL);
39
}
40     
41     /**
42      * alternative <code>null</code> value
43      */

44     public static final long LONGNULL = Long.MIN_VALUE;
45     
46     public static final long MINOBJECTID = Long.MIN_VALUE + 1;
47
48     public static final long MAXOBJECTID = Long.MAX_VALUE;
49     
50     /**
51      * used for <code>StorageFactory</code> instances
52      */

53     private static final String JavaDoc INDEXNODENAMESUFFIX = ".idxnode";
54     
55     /**
56      * <p>Used to name indexfiles. We could take any value from 2 to
57      * <code>Character.MAX_RADIX</code> (36) here, but we settle for 16 because
58      * it looks nice and nerdy. 36 would look less nice because that would
59      * inevitably lead to filenames with very nasty words in them, like
60      * <code>fuck.idxnode</code> and <code>microsoft.idxnode</code>.</p>
61      * <p>Before you know it, someone sues you for trademark infringement.</p>
62      * <p>Insiders joke: CAFEBABE is not a trademark, is she?</p>
63      */

64     private static final int NAMECONVERTRADIX = 10; // 16;
65

66     /**
67      * Read buffer for instantiating new index nodes from storage.
68      */

69     private static ThreadLocal JavaDoc readBufHolder = new ThreadLocal JavaDoc() {
70         protected synchronized Object JavaDoc initialValue() {
71             return new byte[1024];
72         }
73     };
74
75     /**
76      * our id
77      */

78     private long nodeId = LONGNULL;
79     
80     /**
81      * parent in the tree
82      */

83     private long parentNodeId = LONGNULL;
84     
85     /**
86      * maximum number of subnodes or object entries
87      */

88     private int maxSize;
89     
90     /**
91      * indicates a change which requires a write to storage when finalized
92      */

93     private transient boolean dirty;
94     
95     /**
96      * sibling node in the tree
97      */

98     private long prevNodeId = LONGNULL;
99
100     /**
101      * sibling node in the tree
102      */

103     private long nextNodeId = LONGNULL;
104     
105     /**
106      * Index manager this instance is in. Set by constructor
107      * and/or <code>read()</code> factory method.
108      */

109     private transient IndexManager indexManager;
110     
111     private transient int invoked;
112     
113     /**
114      * Constructor for an index node. Extending classes should place themselves
115      * in its index managers cache.
116      *
117      * @param indexManager manages this instance
118      */

119     protected IndexNode(IndexManager indexManager) {
120         startInvoke();
121         nodeId = indexManager.nextNodeId();
122     }
123     
124     /**
125      * Returns the index manager that is 'managing' this tree.
126      *
127      * @return IndexManager manager this instance is in
128      */

129     protected IndexManager getIndexManager() {
130         return indexManager;
131     }
132     
133     /**
134      * Sets the index manager that is 'managing' this tree. Also deletes image
135      * from storage if necessary.
136      *
137      * @param indexManager manager this instance is in
138      */

139     protected void setIndexManager(IndexManager indexManager) {
140         Long JavaDoc id = new Long JavaDoc(getNodeId());
141         if (this.indexManager != null) {
142             this.indexManager.removeFromCaches(this);
143             this.indexManager.getNodeSerializer().remove(id);
144             this.indexManager.getDeleter().delete(this, this.indexManager.getStorageFactory());
145         }
146         this.indexManager = indexManager;
147         setDirty();
148         if (this.indexManager != null) {
149             this.indexManager.putInCaches(this);
150         }
151     }
152     
153     public String JavaDoc toString() {
154         return "id:" + getNodeId() + "; parent:" +
155                 ((getParentNodeId() == LONGNULL) ? "null" : Long.toString(getParentNodeId())) +
156 // "; prev:" +
157
// ((getPrevNodeId() == LONGNULL) ? "null" : Long.toString(getPrevNodeId()))
158
// + "; next:" +
159
// ((getNextNodeId() == LONGNULL) ? "null" : Long.toString(getNextNodeId())) +
160
"; dirty:" + isDirty() + "; minObjectId:" + getMinObjectId() +
161                 "; maxObjectId:" + getMaxObjectId() + "; size:" + size() + "; invoked: " + invoked;
162     }
163     
164     /**
165      * Indicates if this node has changed since last call to <code>write()</code>.
166      */

167     final boolean isDirty() {
168         return dirty;
169     }
170     
171     final void setDirty(boolean dirty) {
172         if (log.isLoggable(Level.FINEST)) log.finest(getNodeId() + " dirty: " + dirty);
173
174         boolean changed = this.dirty != dirty;
175         this.dirty = dirty;
176         if (changed) {
177             getIndexManager().nodeBecameDirty(this);
178         }
179     }
180     
181     final void setDirty() {
182         setDirty(true);
183     }
184
185     /**
186      * Converts a node id to corresponding (file)name for a node.
187      */

188     static String JavaDoc nodeIdToStorageName(long nodeId) {
189         return Long.toString(nodeId, NAMECONVERTRADIX) + INDEXNODENAMESUFFIX;
190     }
191
192     /**
193      * Converts an index (file)name to its corresponding node id
194      */

195     static long storageNameToNodeId(String JavaDoc indexFilename) {
196         String JavaDoc num = indexFilename.substring(0, indexFilename.length() - 1 - INDEXNODENAMESUFFIX.length());
197         return Long.parseLong(num, NAMECONVERTRADIX);
198     }
199     
200     /** Returnes the filename that this node can be saved to, or to be more
201      * precise: the name that can be used by a <code>StorageFactory</code> to
202      * create a unique <code>Storable</code>.
203      */

204     public String JavaDoc getStorageName() {
205         return nodeIdToStorageName(getNodeId());
206     }
207     
208     /** Factory method to create a node by reading it from the storage used
209      * for index nodes by the specified index manager.
210      *
211      * @param indexManager index manager that manages this instance
212      * @param nodeId id of the node to be read
213      */

214     static IndexNode read(IndexManager indexManager, long nodeId) throws IOException JavaDoc {
215         if (log.isLoggable(Level.FINE)) log.fine("about to read indexnode " + nodeId);
216         String JavaDoc nodeName = nodeIdToStorageName(nodeId);
217         IndexNode result;
218         Storage storage = null;
219         try {
220             storage = indexManager.getStorageFactory().createStorage(nodeName);
221             try {
222                 byte[] b = (byte[]) readBufHolder.get();
223                 int numBytesToRead = (int) storage.length();
224                 if (b.length < numBytesToRead) {
225                     b = new byte[numBytesToRead];
226                     readBufHolder.set(b);
227                 }
228                 storage.readFully(b, 0, numBytesToRead);
229                 StreamFactory streamFactory = indexManager.getStreamFactory();
230                 ObjectInputStream JavaDoc objIn;
231                 if (streamFactory == null) {
232                     objIn = new ObjectInputStream JavaDoc(new ByteArrayInputStream JavaDoc(b));
233                 } else {
234                     objIn = new ObjectInputStream JavaDoc(streamFactory.createInputStream(new ByteArrayInputStream JavaDoc(b)));
235                 }
236                 result = (IndexNode) objIn.readObject();
237                 result.startInvoke();
238                 result.setIndexManager(indexManager);
239             } catch (ClassNotFoundException JavaDoc e) {
240                 throw new OzoneInternalException("\"Ford, you are turning into a penguin. Stop it.\"", e);
241             }
242         } finally {
243             if (storage != null) {
244                 storage.close();
245             }
246         }
247 //if (nodeId == 8 || nodeId == 6) log.severe("read " + result);
248
if (result instanceof IndexLeafNode) {
249     if (result.getParentNodeId() == LONGNULL) {
250         log.severe("no parent for " + result.getNodeId());
251         throw new RuntimeException JavaDoc();
252     }
253 }
254         return result;
255     }
256     
257     /**
258      * Returns the number of elements in this node.
259      * @return number of elements in this node
260      */

261     protected abstract int size();
262     
263     /**
264      * Returns <code>true</code> if there is no more room for new elements,
265      * <code>false</code> otherwise
266      * @return <code>true</code> if this node is full, <code>false</code>
267      * otherwise
268      */

269     protected final boolean isFull() {
270         return isFull(0);
271     }
272     
273     /**
274      * Returns <code>true</code> if there is no more room for new elements after
275      * the specified number of elements were added,
276      * <code>false</code> otherwise
277      * @return <code>true</code> if this node (+ specified extra) is full,
278      * <code>false</code> otherwise
279      */

280     protected final boolean isFull(int withExtraElements) {
281         return size() + withExtraElements >= getMaxSize();
282     }
283     
284     /**
285      * Returns the relative size of this node, on a scale of [0 .. 1]
286      */

287     final float relSize() {
288         return (float) size() / (float) getMaxSize();
289     }
290
291     /**
292      * @throws IllegalStateException when called for the second time
293      */

294     protected final void setMaxSize(int maxSize) {
295         if (this.maxSize != 0) {
296             throw new IllegalStateException JavaDoc("cannot change max size");
297         }
298         this.maxSize = maxSize;
299     }
300
301     final int getMaxSize() {
302         return maxSize;
303     }
304     
305     /**
306      * Returns the minimum object id that can be found be in this node
307      */

308     abstract long getMinObjectId();
309     
310     /**
311      * Returns the maximum object id that can be found be in this node
312      */

313     abstract long getMaxObjectId();
314     
315     final long getNodeId() {
316         return nodeId;
317     }
318     
319     final long getParentNodeId() {
320         return parentNodeId;
321     }
322     
323     final void setParentNodeId(long parentNodeId) {
324         this.parentNodeId = parentNodeId;
325         setDirty();
326     }
327     
328     /**
329      * Only ment to be called from IndexBranchNode.putChildNode(IndexNode).
330      */

331     final void setParentNode(IndexBranchNode parent) {
332         if (parent == null) {
333             setParentNodeId(LONGNULL);
334         } else {
335             setParentNodeId(parent.getNodeId());
336         }
337     }
338     
339     final IndexBranchNode getParentNode() {
340         return (IndexBranchNode) getIndexManager().getNode(getParentNodeId());
341     }
342     
343     final long getPrevNodeId() {
344         return prevNodeId;
345     }
346
347     final IndexNode getPrevNode() {
348         return getIndexManager().getNode(getPrevNodeId());
349     }
350     
351     final void setPrevNodeId(long prevNodeId) {
352         this.prevNodeId = prevNodeId;
353         setDirty();
354     }
355     
356     final void setPrevNode(IndexNode prev) {
357         if (prev == null) {
358             setPrevNodeId(LONGNULL);
359         } else {
360             setPrevNodeId(prev.getNodeId());
361         }
362     }
363     
364     final long getNextNodeId() {
365         return nextNodeId;
366     }
367     
368     final IndexNode getNextNode() {
369         return getIndexManager().getNode(getNextNodeId());
370     }
371     
372     final void setNextNodeId(long nextNodeId) {
373         this.nextNodeId = nextNodeId;
374         setDirty();
375     }
376     
377     final void setNextNode(IndexNode next) {
378         if (next == null) {
379             setNextNodeId(LONGNULL);
380         } else {
381             setNextNodeId(next.getNodeId());
382         }
383     }
384     
385     final void startInvoke() {
386         invoked++;
387         if (invoked > 3) throw new OzoneInternalException("pretty big invoke for node: " + getNodeId());
388     }
389
390     final void endInvoke() {
391         invoked--;
392         if (invoked < 0) throw new OzoneInternalException("pretty small invoke for node: " + getNodeId());
393     }
394     
395     final boolean isInvoked() {
396         return invoked > 0;
397     }
398  
399     protected void finalize() throws Throwable JavaDoc {
400         if (isDirty()) {
401             log.severe("how can I (" + getNodeId() + ") be dirty on finalize()?");
402         }
403         super.finalize();
404     }
405 }
406
Popular Tags