001: package com.quadcap.sql.file;
002:
003: /* Copyright 1997 - 2003 Quadcap Software. All rights reserved.
004: *
005: * This software is distributed under the Quadcap Free Software License.
006: * This software may be used or modified for any purpose, personal or
007: * commercial. Open Source redistributions are permitted. Commercial
008: * redistribution of larger works derived from, or works which bundle
009: * this software requires a "Commercial Redistribution License"; see
010: * http://www.quadcap.com/purchase.
011: *
012: * Redistributions qualify as "Open Source" under one of the following terms:
013: *
014: * Redistributions are made at no charge beyond the reasonable cost of
015: * materials and delivery.
016: *
017: * Redistributions are accompanied by a copy of the Source Code or by an
018: * irrevocable offer to provide a copy of the Source Code for up to three
019: * years at the cost of materials and delivery. Such redistributions
020: * must allow further use, modification, and redistribution of the Source
021: * Code under substantially the same terms as this license.
022: *
023: * Redistributions of source code must retain the copyright notices as they
024: * appear in each source code file, these license terms, and the
025: * disclaimer/limitation of liability set forth as paragraph 6 below.
026: *
027: * Redistributions in binary form must reproduce this Copyright Notice,
028: * these license terms, and the disclaimer/limitation of liability set
029: * forth as paragraph 6 below, in the documentation and/or other materials
030: * provided with the distribution.
031: *
032: * The Software is provided on an "AS IS" basis. No warranty is
033: * provided that the Software is free of defects, or fit for a
034: * particular purpose.
035: *
036: * Limitation of Liability. Quadcap Software shall not be liable
037: * for any damages suffered by the Licensee or any third party resulting
038: * from use of the Software.
039: */
040:
041: import java.io.IOException;
042:
043: import com.quadcap.util.Debug;
044:
045: /**
046: * This class is used to locate a specified offset within a randomly
047: * accessible <code>BlockAccess</code> object. The path has two
048: * components, a logical component, <b>p</b> which specifies the offsets of the
049: * block references needed to locate the block and position corresponding
050: * to the selected byte, and a physical component <b>r</b> which contains
051: * the block references of the blocks needed to locate the actual byte.
052: *
053: * @author Stan Bailes
054: */
055:
056: class BlockPath {
057: /** The actual bytes */
058: BlockAccess a;
059: /** Depth of this path */
060: int depth;
061: /** Byte offset info 'a' */
062: long pos;
063: /** Logical path */
064: int[] p;
065: /** Block refs */
066: long[] r;
067: /** A temporary (logical) path */
068: int[] tp;
069:
070: /**
071: * Construct a new BlockPath to represent the specified byte in the
072: * specified region.
073: *
074: * @param a the region into which the index is made
075: * @param pos the byte offset in the region
076: */
077: public BlockPath(BlockAccess a, long pos) throws IOException {
078: this .a = a;
079: this .pos = pos;
080:
081: depth = a.depth;
082:
083: p = new int[depth + 1];
084: r = new long[depth + 1];
085: tp = new int[depth + 1];
086:
087: getPath(pos, p);
088: getRefs();
089: }
090:
091: /**
092: * Return the block which actually contains the data. This is the
093: * final block in the path.
094: * <p>
095: * <B>NOTE</b>: This block needs to have its reference count decremented
096: * when you're done with it!!
097: */
098: public final Page getLeafBlock() throws IOException {
099: return a.file.getPage(r[r.length - 1]);
100: }
101:
102: /**
103: * Return the byte offset within the leaf block where the designated
104: * byte can be found.
105: */
106: public final int getBufPos() {
107: return p[p.length - 1];
108: }
109:
110: /**
111: * Return the depth of this path
112: */
113: public final int getDepth() {
114: return depth;
115: }
116:
117: /**
118: * Return the current position referred to by this path
119: */
120: public final long getPos() {
121: return pos;
122: }
123:
124: /**
125: * Return the current position referred to by this path
126: */
127: public final void setPos(long newpos) throws IOException {
128: if (newpos != pos) {
129: getPath(newpos, tp);
130: updatePath(tp);
131: pos = newpos;
132: }
133: }
134:
135: /**
136: * Adjust this BlockPath to point to a new location, with a minimum
137: * number of block accesses.
138: *
139: * @param cnt The offset from the current location
140: */
141: public final void incr(long offset) throws IOException {
142: setPos(pos + offset);
143: }
144:
145: /**
146: * Build the (logical) path vector for a specified byte in the region.
147: */
148: private final void getPath(long pos, int[] path) {
149: //Debug.println("getPath(" + pos + ")");
150: int len = a.radices.length;
151: for (int i = 0; i < len; i++) {
152: path[i] = (int) (pos / a.radices[i]);
153: pos %= a.radices[i];
154: //Debug.println(" " + i + ": " + path[i] + " (" + a.radices[i] +
155: // ", pos = " + pos + ")");
156: }
157: path[len] = (int) pos;
158: //Debug.println(" * " + len + ": " + path[len]);
159: }
160:
161: /**
162: * Find the actual block refs, given the logical path vector.
163: */
164: private final void getRefs() throws IOException {
165: r[0] = a.rootBlock;
166: for (int i = 1; i < r.length; i++) {
167: try {
168: Page b = a.file.getPage(r[i - 1]);
169: try {
170: r[i] = a.makeBlockRef(b, p[i - 1], i == 1);
171: } finally {
172: b.decrRefCount();
173: }
174: } catch (IOException ex) {
175: Debug.println("getRefs, i = " + i + ", r[" + i + "]="
176: + SubPageManager.toString(r[i - 1]));
177: Debug.println("this = " + this );
178: throw ex;
179: } catch (RuntimeException ex) {
180: Debug.println("getRefs, i = " + i + ", r[" + i + "]="
181: + SubPageManager.toString(r[i - 1]));
182: Debug.println("this = " + this );
183: throw ex;
184: }
185: }
186: }
187:
188: /**
189: * Update the block refs, given a new logical path, attempting
190: * to minimize the number of block accesses.
191: */
192: private final void updatePath(int[] path) throws IOException {
193: if (true) {
194: this .p = path;
195: getRefs();
196: } else {
197: boolean update = false;
198: for (int i = 1; i < r.length; i++) {
199: update |= (p[i - 1] != path[i - 1]);
200: p[i - 1] = path[i - 1];
201: if (update) {
202: Page b = a.file.getPage(r[i - 1]);
203: try {
204: r[i] = a.makeBlockRef(b, path[i - 1], i == 1);
205: } finally {
206: b.decrRefCount();
207: }
208: }
209: }
210: p[r.length - 1] = path[r.length - 1];
211: }
212: }
213:
214: //#ifdef DEBUG
215: /**
216: * For debugging, return a displayable representation of this BlockPath.
217: */
218: public String toString() {
219: StringBuffer sb = new StringBuffer();
220: sb.append("Path[" + pos + "] p(");
221: for (int i = 0; i < p.length; i++) {
222: if (i > 0)
223: sb.append(", ");
224: sb.append("" + p[i]);
225: }
226: sb.append(") r(");
227: for (int i = 0; i < r.length; i++) {
228: if (i > 0)
229: sb.append(", ");
230: sb.append("" + SubPageManager.toString(r[i]));
231: }
232: sb.append(")");
233: return sb.toString();
234: }
235: //#endif
236:
237: }
|