KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 2002,2006 Oracle. All rights reserved.
5  *
6  * $Id: ChildReference.java,v 1.100 2006/11/17 23:47:27 mark Exp $
7  */

8
9 package com.sleepycat.je.tree;
10
11 import java.nio.ByteBuffer JavaDoc;
12
13 import com.sleepycat.je.DatabaseException;
14 import com.sleepycat.je.dbi.DatabaseImpl;
15 import com.sleepycat.je.dbi.EnvironmentImpl;
16 import com.sleepycat.je.log.LogFileNotFoundException;
17 import com.sleepycat.je.log.LogReadable;
18 import com.sleepycat.je.log.LogUtils;
19 import com.sleepycat.je.log.LogWritable;
20 import com.sleepycat.je.utilint.DbLsn;
21
22 /**
23  * A ChildReference is a reference in the tree from parent to child. It
24  * contains a node reference, key, and LSN.
25  */

26 public class ChildReference implements LogWritable, LogReadable {
27
28     static final int ROOT_LOG_SIZE =
29             LogUtils.getByteArrayLogSize(new byte[0]) + // key
30
LogUtils.getLongLogSize() + // LSN
31
1; // state
32

33     private Node target;
34     private long lsn;
35     private byte[] key;
36
37     /*
38      * The state byte holds knownDeleted state in bit 0 and dirty state in bit
39      * 1. Bit flags are used here because of the desire to keep the child
40      * reference compact. State is persistent because knownDeleted is
41      * persistent, but the dirty bit is cleared when read in from the log.
42      *
43      * -- KnownDeleted is a way of indicating that the reference is invalid
44      * without logging new data. This happens in aborts and recoveries. If
45      * knownDeleted is true, this entry is surely deleted. If knownDeleted is
46      * false, this entry may or may not be deleted. Future space optimizations:
47      * store as a separate bit array in the BIN, or subclass ChildReference and
48      * make a special reference only used by BINs and not by INs.
49      *
50      * -- Dirty is true if the LSN or key has been changed since the last time
51      * the ownign node was logged. This supports the calculation of BIN deltas.
52      */

53     private byte state;
54     private static final byte KNOWN_DELETED_BIT = 0x1;
55     private static final byte DIRTY_BIT = 0x2;
56     private static final byte CLEAR_DIRTY_BIT = ~0x2;
57     private static final byte MIGRATE_BIT = 0x4;
58     private static final byte CLEAR_MIGRATE_BIT = ~0x4;
59     private static final byte PENDING_DELETED_BIT = 0x8;
60
61     /**
62      * Construct an empty child reference, for reading from the log.
63      */

64     ChildReference() {
65         init(null, Key.EMPTY_KEY, DbLsn.NULL_LSN, 0);
66     }
67
68     /**
69      * Construct a ChildReference for inserting a new entry.
70      */

71     public ChildReference(Node target, byte[] key, long lsn) {
72         init(target, key, lsn, DIRTY_BIT);
73     }
74
75     /**
76      * Construct a ChildReference for inserting an existing entry.
77      */

78     public ChildReference(Node target,
79               byte[] key,
80               long lsn,
81                           byte existingState) {
82         init(target, key, lsn, existingState | DIRTY_BIT);
83     }
84
85     private void init(Node target,
86               byte[] key,
87               long lsn,
88                       int state) {
89         this.target = target;
90         this.key = key;
91         this.lsn = lsn;
92         this.state = (byte) state;
93     }
94
95     /**
96      * Return the key for this ChildReference.
97      */

98     public byte[] getKey() {
99         return key;
100     }
101
102     /**
103      * Set the key for this ChildReference.
104      */

105     public void setKey(byte[] key) {
106         this.key = key;
107         setDirty();
108     }
109
110     /**
111      * Fetch the target object that this ChildReference refers to. If the
112      * object is already in VM, then just return the reference to it. If the
113      * object is not in VM, then read the object from the log. If the object
114      * has been faulted in and the in arg is supplied, then the total memory
115      * size cache in the IN is invalidated.
116      *
117      * @param database The database that this ChildReference resides in.
118      * @param in The IN that this ChildReference lives in. If
119      * the target is fetched (i.e. it is null on entry), then the
120      * total in memory count is invalidated in the IN. May be null.
121      * For example, the root is a ChildReference and there is no parent IN
122      * when the rootIN is fetched in.
123      * @return the Node object representing the target node in the tree, or
124      * null if there is no target of this ChildReference, or null if a
125      * pendingDelete or knownDeleted entry has been cleaned.
126      */

127     public Node fetchTarget(DatabaseImpl database, IN in)
128         throws DatabaseException {
129
130         if (target == null) {
131             /* fault object in from log */
132             if (lsn == DbLsn.NULL_LSN) {
133                 if (!isKnownDeleted()) {
134                     throw new DatabaseException(IN.makeFetchErrorMsg
135                         ("NULL_LSN without KnownDeleted", in, lsn, state));
136                 }
137                 /* Ignore a NULL_LSN (return null) if KnownDeleted is set. */
138             } else {
139                 try {
140                     EnvironmentImpl env = database.getDbEnvironment();
141                     Node node = (Node) env.getLogManager().get(lsn);
142                     node.postFetchInit(database, lsn);
143                     target = node;
144                     if (in != null) {
145                         in.updateMemorySize(null, target);
146                     }
147                 } catch (LogFileNotFoundException LNFE) {
148                     if (!isKnownDeleted() && !isPendingDeleted()) {
149                         throw new DatabaseException
150                             (IN.makeFetchErrorMsg
151                                 (LNFE.toString(), in, lsn, state),
152                              LNFE);
153                     }
154                     /* Ignore. Cleaner got to it, so just return null. */
155                 } catch (Exception JavaDoc e) {
156                     throw new DatabaseException
157                         (IN.makeFetchErrorMsg(e.toString(), in, lsn, state),
158                          e);
159                 }
160             }
161         }
162
163         return target;
164     }
165
166     /*
167      * Return the state byte for this ChildReference.
168      */

169     byte getState() {
170     return state;
171     }
172
173     /**
174      * Return the target for this ChildReference.
175      */

176     public Node getTarget() {
177         return target;
178     }
179
180     /**
181      * Sets the target for this ChildReference. No need to make dirty, that
182      * state only applies to key and LSN.
183      */

184     public void setTarget(Node target) {
185         this.target = target;
186     }
187
188     /**
189      * Clear the target for this ChildReference. No need to make dirty, that
190      * state only applies to key and LSN. This method is public because it's
191      * safe and used by RecoveryManager. This can't corrupt the tree.
192      */

193     public void clearTarget() {
194         this.target = null;
195     }
196
197     /**
198      * Return the LSN for this ChildReference.
199      *
200      * @return the LSN for this ChildReference.
201      */

202     public long getLsn() {
203         return lsn;
204     }
205
206     /**
207      * Sets the target LSN for this ChildReference.
208      *
209      * @param the target LSN.
210      */

211     public void setLsn(long lsn) {
212         this.lsn = lsn;
213         setDirty();
214     }
215
216     /**
217      * Do deferredWrite optional logging check.
218      */

219     void updateLsnAfterOptionalLog(DatabaseImpl dbImpl, long lsn) {
220         if ((lsn == DbLsn.NULL_LSN) &&
221             dbImpl.isDeferredWrite()) {
222             /*
223              * Don't update the lsn -- we don't want to overwrite a
224              * non-null lsn.
225              */

226             setDirty();
227         } else {
228             setLsn(lsn);
229         }
230     }
231
232     private void setDirty() {
233         state |= DIRTY_BIT;
234     }
235
236     /**
237      * @return true if the entry has been deleted, although the transaction the
238      * performed the deletion may not be committed.
239      */

240     private boolean isPendingDeleted() {
241         return ((state & PENDING_DELETED_BIT) != 0);
242     }
243
244     /**
245      * @return true if entry is deleted for sure.
246      */

247     public boolean isKnownDeleted() {
248         return ((state & KNOWN_DELETED_BIT) != 0);
249     }
250
251     /**
252      * @return true if the object is dirty.
253      */

254     private boolean isDirty() {
255         return ((state & DIRTY_BIT) != 0);
256     }
257
258     /**
259      * Get the entry migrate status.
260      */

261     public boolean getMigrate() {
262         return (state & MIGRATE_BIT) != 0;
263     }
264
265     /**
266      * Set the entry migrate status.
267      */

268     public void setMigrate(boolean migrate) {
269         if (migrate) {
270             state |= MIGRATE_BIT;
271         } else {
272             state &= CLEAR_MIGRATE_BIT;
273         }
274     }
275
276     /*
277      * Support for logging.
278      */

279
280     /**
281      * @see LogWritable#getLogSize
282      */

283     public int getLogSize() {
284         return
285             LogUtils.getByteArrayLogSize(key) + // key
286
LogUtils.getLongLogSize() + // LSN
287
1; // state
288
}
289
290     /**
291      * @see LogWritable#writeToLog
292      */

293     public void writeToLog(ByteBuffer JavaDoc logBuffer) {
294         LogUtils.writeByteArray(logBuffer, key); // key
295
LogUtils.writeLong(logBuffer, lsn);
296         logBuffer.put(state); // state
297
state &= CLEAR_DIRTY_BIT;
298     }
299
300     /**
301      * @see LogReadable#readFromLog
302      */

303     public void readFromLog(ByteBuffer JavaDoc itemBuffer, byte entryTypeVersion) {
304         key = LogUtils.readByteArray(itemBuffer); // key
305
lsn = LogUtils.readLong(itemBuffer); // LSN
306
state = itemBuffer.get(); // state
307
state &= CLEAR_DIRTY_BIT;
308     }
309
310     /**
311      * @see LogReadable#dumpLog
312      */

313     public void dumpLog(StringBuffer JavaDoc sb, boolean verbose) {
314         sb.append("<ref knownDeleted=\"").append(isKnownDeleted());
315         sb.append("\" pendingDeleted=\"").append(isPendingDeleted());
316         sb.append("\">");
317         sb.append(Key.dumpString(key, 0));
318     sb.append(DbLsn.toString(lsn));
319         sb.append("</ref>");
320     }
321
322     /**
323      * @see LogReadable#logEntryIsTransactional
324      */

325     public boolean logEntryIsTransactional() {
326     return false;
327     }
328
329     /**
330      * @see LogReadable#getTransactionId
331      */

332     public long getTransactionId() {
333     return 0;
334     }
335
336     /*
337      * Dumping
338      */

339     String JavaDoc dumpString(int nspaces, boolean dumpTags) {
340         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
341         if (lsn == DbLsn.NULL_LSN) {
342             sb.append(TreeUtils.indent(nspaces));
343             sb.append("<lsn/>");
344         } else {
345             sb.append(DbLsn.dumpString(lsn, nspaces));
346         }
347         sb.append('\n');
348         if (key == null) {
349             sb.append(TreeUtils.indent(nspaces));
350             sb.append("<key/>");
351         } else {
352             sb.append(Key.dumpString(key, nspaces));
353         }
354         sb.append('\n');
355         if (target == null) {
356             sb.append(TreeUtils.indent(nspaces));
357             sb.append("<target/>");
358         } else {
359             sb.append(target.dumpString(nspaces, true));
360         }
361         sb.append('\n');
362         sb.append(TreeUtils.indent(nspaces));
363         sb.append("<knownDeleted val=\"");
364         sb.append(isKnownDeleted()).append("\"/>");
365         sb.append("<pendingDeleted val=\"");
366         sb.append(isPendingDeleted()).append("\"/>");
367         sb.append("<dirty val=\"").append(isDirty()).append("\"/>");
368         return sb.toString();
369     }
370
371     public String JavaDoc toString() {
372         return dumpString(0, false);
373     }
374 }
375
Popular Tags