-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathTreeDeserializer.java
196 lines (164 loc) · 6.34 KB
/
TreeDeserializer.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
package com.dbms.index;
import com.dbms.utils.Catalog;
import com.dbms.utils.TupleReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.List;
/** A class that deserializes an index by first traversing to a leaf node, then walking across the
* leaf layer to extract tuples. If the index is clustered, this reads directly from file after the
* first traversal. */
public class TreeDeserializer {
/** Bytes per page */
private static final int PAGE_SIZE = 4096;
/** Read buffer */
private ByteBuffer buffer;
/** The index at which to read the next integer in the buffer */
private int bufferIndex;
/** Input stream for the file */
private FileInputStream fin;
/** Channel to read the stream into the buffer */
private FileChannel fc;
/** Reader for the relation file */
private TupleReader tr;
/** True if the index is clustered */
private boolean isClustered;
/** Page number of the root node */
private int rootAddress;
/** Number of leaves in the index */
private int numLeaves;
/** Order of the index */
// private int order;
/** The current leaf node page to read next tuple. */
private int currLeafPage;
/** The current number of entries on leaf page. */
private int currNumEntries;
/** The current number of RIDs in current data entry */
private int currNumRids;
/** Number of data entries read in the current leaf page */
private int currNumEntriesRead;
/** Number of RIDs read in the current data entry */
private int currNumRidsRead;
public TreeDeserializer(Index i) throws IOException {
buffer = ByteBuffer.allocate(PAGE_SIZE);
fin = new FileInputStream(Catalog.pathToIndexFile(i.name));
fc = fin.getChannel();
tr = new TupleReader(Catalog.pathToTable(i.name.TABLE));
isClustered = i.isClustered;
// read header page
readNode(0);
rootAddress = buffer.getInt(0);
numLeaves = buffer.getInt(4);
// order = buffer.getInt(8);
}
/** Reads the index to a leaf node and extracts the first matching tuple.
*
* @param key the attribute key of the tuple to look up; may not be present, null for lowest key
* @return the first tuple in the relation with the key
* @throws IOException */
public List<Integer> getFirstTupleAtKey(Integer key) throws IOException {
readNode(rootAddress);
// find leaf node
int leafPage = 0;
while (true) {
int nodeType = readInt();
if (nodeType == 0) break;
int numKeys = readInt();
int childIndex = numKeys;
for (int i = 0; i < numKeys; i++) {
int indexKey = readInt();
if ((key == null || key < indexKey) && childIndex == numKeys) childIndex = i;
}
leafPage = buffer.getInt(bufferIndex + 4 * childIndex);
readNode(leafPage);
}
// find data entry with matching key, go to next entry if key not found
int numEntries = readInt();
int entryNum = 0;
int numRids = 0;
for (int i = 0; i < numEntries; i++) {
int entryKey = readInt();
numRids = readInt();
if (key == null || entryKey >= key) break;
bufferIndex += 8 * numRids;
entryNum++;
}
currLeafPage = leafPage;
currNumEntries = numEntries;
currNumEntriesRead = entryNum;
currNumRids = numRids;
currNumRidsRead = 1;
// check if key not found on node, step to next node
if (entryNum == numEntries) {
currNumRidsRead = numRids;
currNumEntriesRead -= 1; // hack to make stepping work
if (!stepLeafLayer()) return null;
}
// read first tuple RID and return tuple
return readTuple();
}
/** Reads the next tuple in the leaves. Requires getFirstTupleAtKey was called to set the
* deserializer to the beginning of a data entry.
*
* @return the next tuple as ordered by the leaves
* @throws IOException */
public List<Integer> getNextTuple() throws IOException {
if (isClustered) return tr.nextTuple();
if (!stepLeafLayer()) return null;
return readTuple();
}
/** Reads the next two integers in the buffer and looks up the associated RID in the file.
*
* @return tuple at next RID
* @throws IOException */
private List<Integer> readTuple() throws IOException {
int pageId = readInt();
int tupleId = readInt();
return tr.readTuple(new RID(pageId, tupleId));
}
/** Steps the leaf layer by incrementing currNumRidsRead and checking for data entry and node
* overflow. Finishes with the buffer index at the next RID to read.
*
* @return true if successfully stepped to new RID, false if none left
* @throws IOException */
private boolean stepLeafLayer() throws IOException {
if (currNumRidsRead == currNumRids) {
currNumEntriesRead++;
if (currNumEntriesRead == currNumEntries) {
if (currLeafPage == numLeaves) return false;
readNode(++currLeafPage);
currNumEntriesRead = 0;
readInt(); // discard first number indicating a leaf node
currNumEntries = readInt();
}
currNumRidsRead = 0;
readInt(); // discard entry key
currNumRids = readInt();
}
currNumRidsRead++;
return true;
}
/** Reads buffer at bufferIndex and increments bufferIndex by 4.
*
* @return integer at bufferIndex */
private int readInt() {
int num = buffer.getInt(bufferIndex);
bufferIndex += 4;
return num;
}
/** Clears the buffer by filling it with zeros and resetting the position to the front. */
private void clearBuffer() {
buffer.clear();
buffer.put(new byte[PAGE_SIZE]); // hack to reset with zeros
buffer.clear();
}
/** @param pageNumber the page number of the node to read
* @throws IOException */
private void readNode(int pageNumber) throws IOException {
clearBuffer();
fc.position(pageNumber * PAGE_SIZE);
fc.read(buffer);
bufferIndex = 0;
}
}