001: /*
002:
003: Derby - Class org.apache.derby.impl.store.access.heap.HeapRowLocation
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.impl.store.access.heap;
023:
024: /**
025:
026: A heap row location represents the location of a row in the heap.
027: <P>
028: It's implementad as a wrapper around a raw store record handle.
029:
030: **/
031:
032: import org.apache.derby.iapi.services.io.ArrayInputStream;
033: import org.apache.derby.iapi.services.io.CompressedNumber;
034:
035: import org.apache.derby.iapi.error.StandardException;
036: import org.apache.derby.iapi.store.access.conglomerate.TransactionManager;
037: import org.apache.derby.iapi.types.CloneableObject;
038: import org.apache.derby.iapi.types.Orderable;
039: import org.apache.derby.iapi.types.RowLocation;
040: import org.apache.derby.iapi.store.raw.RecordHandle;
041: import org.apache.derby.iapi.store.raw.ContainerHandle;
042: import org.apache.derby.iapi.store.raw.Transaction;
043:
044: import org.apache.derby.iapi.services.io.FormatIdUtil;
045: import org.apache.derby.iapi.services.io.StoredFormatIds;
046:
047: import org.apache.derby.iapi.services.sanity.SanityManager;
048:
049: import org.apache.derby.iapi.types.DataValueDescriptor;
050:
051: import org.apache.derby.iapi.services.cache.ClassSize;
052:
053: import org.apache.derby.iapi.types.DataType;
054:
055: import java.io.ObjectOutput;
056: import java.io.ObjectInput;
057: import java.io.IOException;
058:
059: /**
060: * @format_id ACCESS_HEAP_ROW_LOCATION_V1_ID
061: *
062: * @purpose Object used to store the location of a row within a Heap table.
063: * One of these is stored in every row of a btree secondary index
064: * built on a heap base table.
065: *
066: * @upgrade The type of the btree determines the type of rowlocation stored.
067: * In current btree implementations only one type of rowlocation can
068: * be stored per tree, and it's type is stored in the format id
069: * array stored in the Conglomerate object.
070: *
071: * @disk_layout
072: * page number(CompressedNumber.writeLong())
073: * record id(CompressedNumber.writeInt())
074: **/
075:
076: public class HeapRowLocation extends DataType implements RowLocation {
077: /**
078: The HeapRowLocation simply maintains a raw store record handle.
079: **/
080: private long pageno;
081: private int recid;
082: private RecordHandle rh;
083:
084: private static final int BASE_MEMORY_USAGE = ClassSize
085: .estimateBaseFromCatalog(HeapRowLocation.class);
086: private static final int RECORD_HANDLE_MEMORY_USAGE = ClassSize
087: .estimateBaseFromCatalog(org.apache.derby.impl.store.raw.data.RecordId.class);
088:
089: public int estimateMemoryUsage() {
090: int sz = BASE_MEMORY_USAGE;
091:
092: if (null != rh)
093: sz += RECORD_HANDLE_MEMORY_USAGE;
094: return sz;
095: } // end of estimateMemoryUsage
096:
097: public String getTypeName() {
098: return "RowLocation";
099: }
100:
101: public void setValueFromResultSet(java.sql.ResultSet resultSet,
102: int colNumber, boolean isNullable) {
103: }
104:
105: public DataValueDescriptor getNewNull() {
106: return new HeapRowLocation();
107: }
108:
109: public Object getObject() {
110: return null;
111: }
112:
113: /*
114: ** Methods of CloneableObject.
115: */
116: public Object cloneObject() {
117: return getClone();
118:
119: }
120:
121: public DataValueDescriptor getClone() {
122: return new HeapRowLocation(this );
123: }
124:
125: public int getLength() {
126: return 10;
127: }
128:
129: public String getString() {
130: return toString();
131: }
132:
133: /*
134: ** Methods of Orderable (from RowLocation)
135: **
136: ** see description in
137: ** protocol/Database/Storage/Access/Interface/Orderable.java
138: **
139: */
140:
141: public boolean compare(int op, DataValueDescriptor other,
142: boolean orderedNulls, boolean unknownRV) {
143: // HeapRowLocation should not be null, ignore orderedNulls
144: int result = compare(other);
145:
146: switch (op) {
147: case ORDER_OP_LESSTHAN:
148: return (result < 0); // this < other
149: case ORDER_OP_EQUALS:
150: return (result == 0); // this == other
151: case ORDER_OP_LESSOREQUALS:
152: return (result <= 0); // this <= other
153: default:
154:
155: if (SanityManager.DEBUG)
156: SanityManager.THROWASSERT("Unexpected operation");
157: return false;
158: }
159: }
160:
161: public int compare(DataValueDescriptor other) {
162: // REVISIT: do we need this check?
163: if (SanityManager.DEBUG)
164: SanityManager.ASSERT(other instanceof HeapRowLocation);
165:
166: HeapRowLocation arg = (HeapRowLocation) other;
167:
168: // XXX (nat) assumption is that these HeapRowLocations are
169: // never null. However, if they ever become null, need
170: // to add null comparison logic.
171: //
172: // RESOLVE - change these to be state based
173: /*
174: if (SanityManager.DEBUG)
175: SanityManager.ASSERT(getRecordHandle() != null);
176: if (SanityManager.DEBUG)
177: SanityManager.ASSERT(arg.getRecordHandle() != null);
178: */
179:
180: long myPage = this .pageno;
181: long otherPage = arg.pageno;
182:
183: if (myPage < otherPage)
184: return -1;
185: else if (myPage > otherPage)
186: return 1;
187:
188: int myRecordId = this .recid;
189: int otherRecordId = arg.recid;
190:
191: if (myRecordId == otherRecordId)
192: return 0;
193: else if (myRecordId < otherRecordId)
194: return -1;
195: else
196: return 1;
197: }
198:
199: /*
200: ** Methods of HeapRowLocation
201: */
202:
203: HeapRowLocation(RecordHandle rh) {
204: setFrom(rh);
205: }
206:
207: public HeapRowLocation() {
208: this .pageno = 0;
209: this .recid = RecordHandle.INVALID_RECORD_HANDLE;
210: }
211:
212: /* For cloning */
213: private HeapRowLocation(HeapRowLocation other) {
214: this .pageno = other.pageno;
215: this .recid = other.recid;
216: this .rh = other.rh;
217: }
218:
219: public RecordHandle getRecordHandle(ContainerHandle ch)
220: throws StandardException {
221: if (rh != null)
222: return rh;
223:
224: return rh = ch.makeRecordHandle(this .pageno, this .recid);
225: }
226:
227: void setFrom(RecordHandle rh) {
228: this .pageno = rh.getPageNumber();
229: this .recid = rh.getId();
230: this .rh = rh;
231: }
232:
233: //public void setFrom(long pageno, int recid)
234: //{
235: // this.pageno = pageno;
236: // this.recid = recid;
237: //}
238:
239: /*
240: * InternalRowLocation interface
241: */
242:
243: /**
244: * Return a RecordHandle built from current RowLocation.
245: * <p>
246: * Build a RecordHandle from the current RowLocation. The main client
247: * of this interface is row level locking secondary indexes which read
248: * the RowLocation field from a secondary index row, and then need a
249: * RecordHandle built from this RowLocation.
250: * <p>
251: * The interface is not as generic as one may have wanted in order to
252: * store as compressed a version of a RowLocation as possible. So
253: * if an implementation of a RowLocation does not have the segmentid,
254: * and containerid stored, use the input parameters instead. If the
255: * RowLocation does have the values stored use them and ignore the
256: * input parameters.
257: * <p>
258: * Example:
259: * <p>
260: * The HeapRowLocation implementation of RowLocation generated by the
261: * Heap class, only stores the page and record id. The B2I conglomerate
262: * implements a secondary index on top of a Heap class. B2I knows the
263: * segmentid and containerid of it's base table, and knows that it can
264: * find an InternalRowLocation in a particular column of it's rows. It
265: * uses InternalRowLocation.getRecordHandle() to build a RecordHandle
266: * from the InternalRowLocation, and uses it to set a row lock on that
267: * row in the btree.
268: *
269: * @return The newly allocated RecordHandle.
270: *
271: * @param segmentid The segment id to store in RecordHandle.
272: * @param containerid The segment id to store in RecordHandle.
273: *
274: * @exception StandardException Standard exception policy.
275: **/
276: /*public RecordHandle getRecordHandle(
277: TransactionManager tran,
278: long segmentid,
279: long containerid)
280: throws StandardException
281: {
282: return(
283: this.getRecordHandle(
284: tran.getRawStoreXact(), segmentid, containerid));
285: }
286: */
287:
288: /*
289: * Storable interface, implies Externalizable, TypedFormat
290: */
291:
292: /**
293: Return my format identifier.
294:
295: @see org.apache.derby.iapi.services.io.TypedFormat#getTypeFormatId
296: */
297: public int getTypeFormatId() {
298: return StoredFormatIds.ACCESS_HEAP_ROW_LOCATION_V1_ID;
299: }
300:
301: public boolean isNull() {
302: return false;
303: }
304:
305: public void writeExternal(ObjectOutput out) throws IOException {
306: // Write the page number, compressed
307: CompressedNumber.writeLong(out, this .pageno);
308:
309: // Write the record id
310: CompressedNumber.writeInt(out, this .recid);
311: }
312:
313: /**
314: @exception java.lang.ClassNotFoundException A class needed to read the
315: stored form of this object could not be found.
316: @see java.io.Externalizable#readExternal
317: */
318: public void readExternal(ObjectInput in) throws IOException,
319: ClassNotFoundException {
320: this .pageno = CompressedNumber.readLong(in);
321:
322: this .recid = CompressedNumber.readInt(in);
323:
324: rh = null;
325: }
326:
327: public void readExternalFromArray(ArrayInputStream in)
328: throws IOException, ClassNotFoundException {
329: this .pageno = in.readCompressedLong();
330:
331: this .recid = in.readCompressedInt();
332:
333: rh = null;
334: }
335:
336: public void restoreToNull() {
337: if (SanityManager.DEBUG)
338: SanityManager.THROWASSERT("HeapRowLocation is never null");
339: }
340:
341: protected void setFrom(DataValueDescriptor theValue) {
342: if (SanityManager.DEBUG)
343: SanityManager.THROWASSERT("SHOULD NOT BE CALLED");
344: }
345:
346: /*
347: ** Methods of Object
348: */
349:
350: /**
351: Implement value equality.
352: <BR>
353: MT - Thread safe
354: */
355: public boolean equals(Object ref) {
356:
357: if ((ref instanceof HeapRowLocation)) {
358: HeapRowLocation other = (HeapRowLocation) ref;
359:
360: return ((this .pageno == other.pageno) && (this .recid == other.recid));
361: } else {
362: return false;
363: }
364:
365: }
366:
367: /**
368: Return a hashcode based on value.
369: <BR>
370: MT - thread safe
371: */
372: public int hashCode() {
373: return ((int) this .pageno) ^ this .recid;
374: }
375:
376: /*
377: * Standard toString() method.
378: */
379: public String toString() {
380: String string = "(" + this .pageno + "," + this .recid + ")";
381: return (string);
382: }
383: }
|