KickJava   Java API By Example, From Geeks To Geeks.

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


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.Session;
11 import org.h2.message.Message;
12 import org.h2.result.Row;
13 import org.h2.result.SearchRow;
14 import org.h2.store.DataPage;
15 import org.h2.store.DiskFile;
16 import org.h2.table.Column;
17 import org.h2.util.IntArray;
18 import org.h2.util.ObjectArray;
19 import org.h2.value.Value;
20
21 /**
22  * Page format:
23  * N children.len children[0..len] data.len { data[0].pos [data[0]], ... }
24  *
25  * @author Thomas
26  */

27 public class BtreeNode extends BtreePage {
28
29     private boolean writePos;
30     private IntArray pageChildren;
31
32     BtreeNode(BtreeIndex index, DataPage s) throws SQLException JavaDoc {
33         super(index);
34         int len = s.readInt();
35         int[] array = new int[len];
36         for(int i=0; i<array.length; i++) {
37             array[i] = s.readInt();
38         }
39         pageChildren = new IntArray(array);
40         pageData = index.readRowArray(s);
41     }
42
43     BtreeNode(BtreeIndex index, BtreePage left, SearchRow pivot, BtreePage right) {
44         super(index);
45         pageChildren = new IntArray();
46         pageChildren.add(left.getPos());
47         pageChildren.add(right.getPos());
48         pageData = new ObjectArray();
49         pageData.add(pivot);
50     }
51
52     BtreeNode(BtreeIndex index, IntArray pageChildren, ObjectArray pageData) {
53         super(index);
54         this.pageChildren = pageChildren;
55         this.pageData = pageData;
56     }
57
58     protected SearchRow getData(int i) throws SQLException JavaDoc {
59         SearchRow r = (SearchRow) pageData.get(i);
60         if(r == null) {
61             int p = pageChildren.get(i+1);
62             BtreePage page = index.getPage(p);
63             r = page.getFirst();
64             pageData.set(i, r);
65         }
66         return r;
67     }
68
69     public int add(Row newRow, Session session) throws SQLException JavaDoc {
70         int l = 0, r = pageData.size();
71         if (!Constants.ALLOW_EMTPY_BTREE_PAGES && pageChildren.size() == 0) {
72             throw Message.getInternalError("Empty btree page");
73         }
74         while (l < r) {
75             int i = (l + r) >>> 1;
76             SearchRow row = getData(i);
77             int comp = index.compareRows(row, newRow);
78             if(comp == 0) {
79                 if(index.indexType.isUnique()) {
80                     if(!index.isNull(newRow)) {
81                         throw index.getDuplicateKeyException();
82                     }
83                 }
84                 comp = index.compareKeys(row, newRow);
85             }
86             if(comp > 0) {
87                 r = i;
88             } else {
89                 l = i + 1;
90             }
91         }
92         int at = l;
93         BtreePage page = index.getPage(pageChildren.get(at));
94         int splitPoint = page.add(newRow, session);
95         if (splitPoint == 0) {
96             return 0;
97         }
98         SearchRow pivot = page.getData(splitPoint);
99         BtreePage page2 = page.split(session, splitPoint);
100         index.deletePage(session, this);
101         pageChildren.add(at + 1, page2.getPos());
102         pageData.add(at, pivot);
103         splitPoint = getSplitPoint();
104         if(splitPoint > 1) {
105             return splitPoint;
106         }
107         index.updatePage(session, this);
108         return 0;
109     }
110
111     public SearchRow remove(Session session, Row oldRow, int level) throws SQLException JavaDoc {
112         int l = 0, r = pageData.size();
113         if (!Constants.ALLOW_EMTPY_BTREE_PAGES && pageChildren.size() == 0) {
114             throw Message.getInternalError("Empty btree page");
115         }
116         int comp = 0;
117         while (l < r) {
118             int i = (l + r) >>> 1;
119             SearchRow row = getData(i);
120             comp = index.compareRows(row, oldRow);
121             if(comp == 0) {
122                 comp = index.compareKeys(row, oldRow);
123             }
124             if(comp > 0) {
125                 r = i;
126             } else {
127                 l = i + 1;
128             }
129         }
130         int at = l;
131         // merge is not implemented to allow concurrent usage of btrees
132
BtreePage page = index.getPage(pageChildren.get(at));
133         SearchRow first = page.remove(session, oldRow, level+1);
134         if(first == null) {
135             // the first row didn't change - nothing to do here
136
return null;
137         }
138         if(first == oldRow) {
139             // this child is now empty
140
index.deletePage(session, this);
141             pageChildren.remove(at);
142             if(pageChildren.size()==0) {
143                 // no more children - this page is empty as well
144
// it can't be the root otherwise the index would have been truncated
145
return oldRow;
146             }
147             if(at == 0) {
148                 // the first child is empty - then the first row of this subtree has changed
149
first = getData(0);
150                 pageData.remove(0);
151             } else {
152                 // otherwise the first row didn't change
153
first = null;
154                 pageData.remove(at==0 ? 0 : at-1);
155             }
156             index.updatePage(session, this);
157             return first;
158         } else {
159             // the child still exists, but the first element has changed
160
if(at == 0) {
161                 // no change in this page, but there is a new first row for this subtree
162
return first;
163             } else {
164                 // the first row of another child has changed - need to update
165
index.deletePage(session, this);
166                 pageData.set(at-1, first);
167                 index.updatePage(session, this);
168                 // but then the first row of this subtree didn't change
169
return null;
170             }
171         }
172     }
173
174     public BtreePage split(Session session, int splitPoint) throws SQLException JavaDoc {
175         ObjectArray data = new ObjectArray();
176         IntArray children = new IntArray();
177         splitPoint++;
178         int max = pageData.size();
179         if(Constants.CHECK && index.getDatabase().getLogIndexChanges() && !getDeleted()) {
180             // page must have been deleted already before calling getSplitPoint()
181
throw Message.getInternalError();
182         }
183         for (int i = splitPoint; i < max; i++) {
184             data.add(getData(splitPoint));
185             children.add(getChild(splitPoint));
186             pageData.remove(splitPoint);
187             pageChildren.remove(splitPoint);
188         }
189         children.add(getChild(splitPoint));
190         pageData.remove(splitPoint-1);
191         pageChildren.remove(splitPoint);
192         BtreeNode n2 = new BtreeNode(index, children, data);
193         index.updatePage(session, this);
194         index.addPage(session, n2);
195         return n2;
196     }
197
198     int getChild(int i) {
199         return pageChildren.get(i);
200     }
201
202     public boolean findFirst(BtreeCursor cursor, SearchRow compare) throws SQLException JavaDoc {
203         int l = 0, r = pageData.size();
204         if (!Constants.ALLOW_EMTPY_BTREE_PAGES && pageChildren.size() == 0) {
205             throw Message.getInternalError("Empty btree page");
206         }
207         while (l < r) {
208             int i = (l + r) >>> 1;
209             SearchRow row = getData(i);
210             int comp = index.compareRows(row, compare);
211             if(comp >= 0) {
212                 r = i;
213             } else {
214                 l = i + 1;
215             }
216         }
217         if(l>=pageData.size()) {
218             BtreePage page = index.getPage(pageChildren.get(l));
219             cursor.push(this, l);
220             boolean result = page.findFirst(cursor, compare);
221             if(result) {
222                 return true;
223             }
224             cursor.pop();
225             return false;
226         }
227         BtreePage page = index.getPage(pageChildren.get(l));
228         cursor.push(this, l);
229         if(page.findFirst(cursor, compare)) {
230             return true;
231         }
232         cursor.pop();
233         int i=l+1;
234         for (; i < pageData.size(); i++) {
235             SearchRow row = getData(i);
236             int comp = index.compareRows(row, compare);
237             if (comp >=0) {
238                 page = index.getPage(pageChildren.get(i));
239                 cursor.push(this, i);
240                 if(page.findFirst(cursor, compare)) {
241                     return true;
242                 }
243                 cursor.pop();
244             }
245         }
246         page = index.getPage(pageChildren.get(i));
247         cursor.push(this, i);
248         boolean result = page.findFirst(cursor, compare);
249         if(result) {
250             return true;
251         }
252         cursor.pop();
253         return false;
254     }
255
256     public void next(BtreeCursor cursor, int i) throws SQLException JavaDoc {
257         i++;
258         if (i <= pageData.size()) {
259             cursor.setStackPosition(i);
260             BtreePage page = index.getPage(pageChildren.get(i));
261             page.first(cursor);
262             return;
263         }
264         nextUpper(cursor);
265     }
266
267     private void nextUpper(BtreeCursor cursor) throws SQLException JavaDoc {
268         cursor.pop();
269         BtreePosition upper = cursor.pop();
270         if (upper == null) {
271             cursor.setCurrentRow(Cursor.POS_NO_ROW);
272         } else {
273             cursor.push(upper.page, upper.position);
274             upper.page.next(cursor, upper.position);
275         }
276     }
277
278     public void first(BtreeCursor cursor) throws SQLException JavaDoc {
279         cursor.push(this, 0);
280         BtreePage page = index.getPage(pageChildren.get(0));
281         page.first(cursor);
282     }
283
284     public void prepareWrite() throws SQLException JavaDoc {
285         if(getRealByteCount() >= DiskFile.BLOCK_SIZE*BLOCKS_PER_PAGE) {
286             writePos = true;
287         } else {
288             writePos = false;
289         }
290     }
291
292     public void write(DataPage buff) throws SQLException JavaDoc {
293         buff.writeByte((byte)'N');
294         int len = pageChildren.size();
295         buff.writeInt(len);
296         for (int i = 0; i < len; i++) {
297             buff.writeInt(pageChildren.get(i));
298         }
299         len = pageData.size();
300         buff.writeInt(len);
301         Column[] columns = index.getColumns();
302         for (int i = 0; i < len; i++) {
303             if(writePos) {
304                 buff.writeInt(-1);
305             } else {
306                 SearchRow row = getData(i);
307                 buff.writeInt(row.getPos());
308                 for (int j = 0; j < columns.length; j++) {
309                     Value v = row.getValue(columns[j].getColumnId());
310                     buff.writeValue(v);
311                 }
312             }
313         }
314         if(buff.length() > BtreePage.BLOCKS_PER_PAGE*DiskFile.BLOCK_SIZE) {
315             throw Message.getInternalError("indexed data overflow");
316         }
317     }
318
319     int getRealByteCount() throws SQLException JavaDoc {
320         DataPage dummy = index.getDatabase().getDataPage();
321         int len = pageChildren.size();
322         int size = 2 + dummy.getIntLen() + dummy.getIntLen() * len;
323         len = pageData.size();
324         size += dummy.getIntLen();
325         size += len * dummy.getIntLen();
326         for (int i = 0; i < len; i++) {
327             SearchRow row = getData(i);
328             size += getRowSize(dummy, row);
329         }
330         return size + index.getRecordOverhead();
331     }
332
333     SearchRow getLast() throws SQLException JavaDoc {
334         if (!Constants.ALLOW_EMTPY_BTREE_PAGES && pageChildren.size() == 0) {
335             throw Message.getInternalError("Empty btree page");
336         }
337         for(int i=pageChildren.size()-1; i>=0; i--) {
338             BtreePage page = index.getPage(pageChildren.get(i));
339             if(page != null) {
340                 return page.getLast();
341             }
342         }
343         return null;
344     }
345
346     SearchRow getFirst() throws SQLException JavaDoc {
347         for(int i=0; i<pageChildren.size(); i++) {
348             BtreePage page = index.getPage(pageChildren.get(i));
349             if(page != null) {
350                 return page.getFirst();
351             }
352         }
353         return null;
354     }
355
356     public String JavaDoc print(String JavaDoc indent) throws SQLException JavaDoc {
357         System.out.println(indent + "node");
358         String JavaDoc first = null;
359         String JavaDoc last = null;
360         for(int i=0; i<pageChildren.size(); i++) {
361             String JavaDoc firstnow = index.getPage(pageChildren.get(i)).print(indent + " ");
362             if(first == null) {
363                 first = firstnow;
364             }
365             if(last != null && !last.equals(firstnow)) {
366                 System.out.println("STOP!!! " + last + " firstnow:" + firstnow);
367             }
368             if(i<pageData.size()) {
369                 String JavaDoc now = getData(i).getValue(1).getString().substring(4150);
370                 System.out.println(indent + " " + now);
371                 last = now;
372             }
373         }
374         return first;
375     }
376
377 }
378
Popular Tags