KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > h2 > index > BtreeIndex


1 /*
2  * Copyright 2004-2006 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
3  * Initial Developer: H2 Group
4  */

5 package org.h2.index;
6
7 import java.sql.SQLException JavaDoc;
8
9 import org.h2.engine.Constants;
10 import org.h2.engine.Database;
11 import org.h2.engine.Session;
12 import org.h2.message.Message;
13 import org.h2.result.Row;
14 import org.h2.result.SearchRow;
15 import org.h2.store.DataPage;
16 import org.h2.store.Record;
17 import org.h2.store.RecordReader;
18 import org.h2.store.Storage;
19 import org.h2.table.Column;
20 import org.h2.table.TableData;
21 import org.h2.util.ObjectArray;
22 import org.h2.value.Value;
23 import org.h2.value.ValueNull;
24
25 /**
26  * @author Thomas
27  */

28 public class BtreeIndex extends Index implements RecordReader {
29
30     // TODO index / btree: tune page size
31
// final static int MAX_PAGE_SIZE = 256;
32

33     private Storage storage;
34     private BtreePage root;
35     private TableData tableData;
36     private BtreeHead head;
37     private boolean needRebuild;
38     private int headPos;
39     private long lastChange;
40
41     public BtreeIndex(Session session, TableData table, int id, String JavaDoc indexName, Column[] columns,
42             IndexType indexType, int headPos) throws SQLException JavaDoc {
43         // TODO we need to log index data
44
super(table, id, indexName, columns, indexType);
45         this.tableData = table;
46         Database db = table.getDatabase();
47         storage = db.getStorage(this, id, false);
48         this.headPos = headPos;
49         if (headPos == Index.EMPTY_HEAD || database.getRecovery()) {
50             truncate(session);
51             needRebuild = true;
52         } else {
53             Record rec = storage.getRecordIfStored(headPos);
54             if(rec != null && (rec instanceof BtreeHead)) {
55                 head = (BtreeHead) rec;
56             }
57             if(head != null && head.getConsistent()) {
58                 setRoot((BtreePage) storage.getRecord(head.getRootPosition()));
59                 needRebuild = false;
60                 rowCount = table.getRowCount();
61             } else {
62                 truncate(session);
63                 needRebuild = true;
64             }
65         }
66     }
67
68     private void setRoot(BtreePage newRoot) {
69         if (root != null) {
70             root.setRoot(false);
71         }
72         newRoot.setRoot(true);
73         root = newRoot;
74     }
75
76     public int getHeadPos() {
77         return headPos;
78     }
79
80     public void remove(Session session) throws SQLException JavaDoc {
81         storage.delete(session);
82         storage = null;
83     }
84
85     private void setChanged(Session session) throws SQLException JavaDoc {
86         if(head != null && !database.getLogIndexChanges()) {
87             // maybe there was a checkpoint, need to invalidate the summary in this case too
88
database.invalidateIndexSummary();
89             if(head.getConsistent()) {
90                 deletePage(session, head);
91                 head.setConsistent(false);
92                 flushHead(session);
93             }
94             lastChange = System.currentTimeMillis();
95         }
96     }
97
98     void updatePage(Session session, Record p) throws SQLException JavaDoc {
99         if(database.getLogIndexChanges()) {
100             storage.addRecord(session, p, p.getPos());
101         } else {
102             storage.updateRecord(session, p);
103         }
104     }
105
106     void deletePage(Session session, Record p) throws SQLException JavaDoc {
107         if(database.getLogIndexChanges()) {
108             storage.removeRecord(session, p.getPos());
109         }
110     }
111
112     void addPage(Session session, Record p) throws SQLException JavaDoc {
113         storage.addRecord(session, p, Storage.ALLOCATE_POS);
114     }
115
116     public BtreePage getPage(int i) throws SQLException JavaDoc {
117         return (BtreePage) storage.getRecord(i);
118     }
119
120     public void flush(Session session) throws SQLException JavaDoc {
121         lastChange = 0;
122         if(storage != null) {
123             storage.flushFile();
124             deletePage(session, head);
125             // if we log index changes now, then the index is consistent
126
// if we don't log index changes, then the index is only consistent if there are no in doubt transactions
127
if(database.getLogIndexChanges() || !database.getLog().containsInDoubtTransactions()) {
128                 head.setConsistent(true);
129             }
130             flushHead(session);
131         }
132     }
133
134     public void close(Session session) throws SQLException JavaDoc {
135         flush(session);
136         storage = null;
137     }
138
139     public void add(Session session, Row r) throws SQLException JavaDoc {
140         // create a row that only contains the key values
141
setChanged(session);
142         Row row = table.getTemplateRow();
143         row.setPos(r.getPos());
144         for (int i = 0; i < columns.length; i++) {
145             Column col = columns[i];
146             int idx = col.getColumnId();
147             Value v = r.getValue(idx);
148             row.setValue(idx, v);
149         }
150         int splitPoint = root.add(row, session);
151         if (splitPoint != 0) {
152             SearchRow pivot = root.getData(splitPoint);
153             BtreePage page1 = root;
154             BtreePage page2 = root.split(session, splitPoint);
155             setRoot(new BtreeNode(this, page1, pivot, page2));
156             addPage(session, root);
157             deletePage(session, head);
158             head.setRootPosition(root.getPos());
159             flushHead(session);
160         }
161         rowCount++;
162     }
163
164     public void remove(Session session, Row row) throws SQLException JavaDoc {
165         setChanged(session);
166         if(rowCount == 1) {
167             // TODO performance: maybe improve truncate performance in this case
168
truncate(session);
169         } else {
170             root.remove(session, row, 0);
171             rowCount--;
172         }
173     }
174
175     public Cursor find(Session session, SearchRow first, SearchRow last) throws SQLException JavaDoc {
176         if(Constants.CHECK && storage == null) {
177             throw Message.getSQLException(Message.OBJECT_CLOSED);
178         }
179         if(first==null) {
180             BtreeCursor cursor = new BtreeCursor(this, last);
181             root.first(cursor);
182             return cursor;
183         } else {
184             BtreeCursor cursor = new BtreeCursor(this, last);
185             if (!root.findFirst(cursor, first)) {
186                 cursor.setCurrentRow(Cursor.POS_NO_ROW);
187             }
188             return cursor;
189         }
190     }
191
192     public int getLookupCost(int rowCount) {
193         for(int i=0, j = 1; ; i++) {
194             j *= BtreePage.BLOCKS_PER_PAGE;
195             if(j>rowCount) {
196                 return (i+1);
197             }
198         }
199     }
200
201     public int getCost(int[] masks) throws SQLException JavaDoc {
202         return 10 * getCostRangeIndex(masks, tableData.getRowCount());
203     }
204
205     public Record read(DataPage s) throws SQLException JavaDoc {
206         char c = (char) s.readByte();
207         if (c == 'N') {
208             return new BtreeNode(this, s);
209         } else if (c == 'L') {
210             return new BtreeLeaf(this, s);
211         } else if (c == 'H') {
212             return new BtreeHead(s);
213         } else {
214             throw Message.getSQLException(Message.FILE_CORRUPTED_1, getName());
215         }
216     }
217
218     ObjectArray readRowArray(DataPage s) throws SQLException JavaDoc {
219         int len = s.readInt();
220         ObjectArray rows = new ObjectArray(len);
221         for (int i = 0; i < len; i++) {
222             int pos = s.readInt();
223             SearchRow r;
224             if(pos < 0) {
225                 r = null;
226             } else {
227                 r = table.getTemplateSimpleRow(columns.length==1);
228                 r.setPos(pos);
229                 for (int j = 0; j < columns.length; j++) {
230                     int idx = columns[j].getColumnId();
231                     r.setValue(idx, s.readValue());
232                 }
233             }
234             rows.add(r);
235         }
236         return rows;
237     }
238
239     public Row getRow(int pos) throws SQLException JavaDoc {
240         return tableData.getRow(pos);
241     }
242
243     private void flushHead(Session session) throws SQLException JavaDoc {
244         updatePage(session, head);
245         if(!database.getLogIndexChanges() && !database.getReadOnly()) {
246             storage.flushRecord(head);
247         }
248         trace.debug("Index " + getSQL() + " head consistent="+head.getConsistent());
249     }
250
251     public void truncate(Session session) throws SQLException JavaDoc {
252         setChanged(session);
253         storage.truncate(session);
254         head = new BtreeHead();
255         addPage(session, head);
256         setRoot(new BtreeLeaf(this, new ObjectArray()));
257         addPage(session, root);
258         deletePage(session, head);
259         head.setRootPosition(root.getPos());
260         head.setConsistent(database.getLogIndexChanges());
261         lastChange = System.currentTimeMillis();
262         flushHead(session);
263         headPos = head.getPos();
264         rowCount = 0;
265     }
266
267     public void checkRename() throws SQLException JavaDoc {
268         // ok
269
}
270
271     public boolean needRebuild() {
272         return needRebuild;
273     }
274
275     public int getRecordOverhead() {
276         return storage.getRecordOverhead();
277     }
278
279     public long getLastChange() {
280         return lastChange;
281     }
282
283     public boolean canGetFirstOrLast(boolean first) {
284         return true;
285     }
286
287     public Value findFirstOrLast(Session session, boolean first) throws SQLException JavaDoc {
288         if(first) {
289             // TODO optimization: this loops through NULL values
290
Cursor cursor = find(session, null, null);
291             while(cursor.next()) {
292                 Value v = cursor.get().getValue(columnIndex[0]);
293                 if(v != ValueNull.INSTANCE) {
294                     return v;
295                 }
296             }
297             return ValueNull.INSTANCE;
298         } else {
299             SearchRow row = root.getLast();
300             if(row != null) {
301                 Value v = row.getValue(columnIndex[0]);
302                 return v;
303             }
304             return ValueNull.INSTANCE;
305         }
306     }
307
308 }
309
Popular Tags