001: /*
002:
003: Derby - Class org.apache.derby.impl.store.raw.data.OverflowInputStream
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.raw.data;
023:
024: import org.apache.derby.iapi.error.StandardException;
025: import org.apache.derby.iapi.reference.SQLState;
026:
027: import org.apache.derby.iapi.store.raw.RecordHandle;
028:
029: import org.apache.derby.iapi.types.Resetable;
030: import org.apache.derby.iapi.store.raw.LockingPolicy;
031: import org.apache.derby.iapi.store.access.TransactionController;
032:
033: import java.io.InputStream;
034: import java.io.IOException;
035:
036: /**
037: A OverflowInputStream is used by store to turn a long column
038: into an InputStream.
039: */
040: public class OverflowInputStream extends BufferedByteHolderInputStream
041: implements Resetable {
042: protected BaseContainerHandle owner;
043: protected long overflowPage;
044: protected int overflowId;
045: // remember first page and id for reset
046: protected long firstOverflowPage;
047: protected int firstOverflowId;
048: // the row to lock for Blobs/Clobs
049: protected RecordHandle recordToLock;
050:
051: public OverflowInputStream(ByteHolder bh,
052: BaseContainerHandle owner, long overflowPage,
053: int overflowId, RecordHandle recordToLock)
054: throws IOException, StandardException {
055: super (bh);
056: this .owner = owner;
057: this .overflowPage = overflowPage;
058: this .overflowId = overflowId;
059: this .firstOverflowPage = overflowPage;
060: this .firstOverflowId = overflowId;
061: this .recordToLock = recordToLock;
062: fillByteHolder();
063: }
064:
065: public void fillByteHolder() throws IOException {
066: if ((this .bh.available() == 0) && (this .overflowPage != -1)) {
067: this .bh.clear();
068:
069: try {
070: // fill the byte holder with data from the page.
071: BasePage columnOverflowPage = ((BasePage) this .owner
072: .getPage(overflowPage));
073:
074: if (columnOverflowPage != null) {
075: columnOverflowPage.restorePortionLongColumn(this );
076: columnOverflowPage.unlatch();
077: columnOverflowPage = null;
078: }
079: } catch (StandardException se) {
080: throw new IOException(se.toString());
081: }
082: this .bh.startReading();
083: }
084: }
085:
086: public long getOverflowPage() {
087: return this .overflowPage;
088: }
089:
090: public int getOverflowId() {
091: return this .overflowId;
092: }
093:
094: public void setOverflowPage(long overflowPage) {
095: this .overflowPage = overflowPage;
096: }
097:
098: public void setOverflowId(int overflowId) {
099: this .overflowId = overflowId;
100: }
101:
102: /*
103: Methods of Resetable interface.
104: */
105:
106: /*
107: Resets the stream to the beginning.
108: */
109: public void resetStream() throws IOException, StandardException {
110: // check the container is open, this is needed to make sure the
111: // container closed exception is thrown as a StandardException and not
112: // as an IOException
113: owner.checkOpen();
114: // return to the original overflow page and id
115: this .overflowPage = firstOverflowPage;
116: this .overflowId = firstOverflowId;
117: // completely clear the byte holder
118: this .bh.clear();
119: this .bh.startReading();
120: // fill the byte holder
121: fillByteHolder();
122: }
123:
124: /*
125: Initialize. Reopen the container. This will have the effect of
126: getting an intent shared lock on the table, which will stay around until
127: the end of the transaction (or until the enclosing blob/clob object is
128: closed). Also get a read lock on the appropriate row.
129: */
130: public void initStream() throws StandardException {
131: // it is possible that the transaction in which the stream was
132: // created is committed and no longer valid
133: // dont want to get NPE but instead throw error that
134: // container was not opened
135: if (owner.getTransaction() == null)
136: throw StandardException
137: .newException(SQLState.DATA_CONTAINER_CLOSED);
138: /*
139: We might want to use the mode and isolation level of the container.
140: This would have the advantage that, if the isolation level
141: is READ_COMMITTED, resources would be freed if blobs/clob finalizers are
142: called (e.g. they are garbage collected) before the end of transaction.
143: If the mode was MODE_CONTAINER, openContainer would get an S lock on the
144: table instead of an IS lock, and lockRecordForRead would have no effect.
145:
146: To do this, need to consider:
147: Sometimes the container's locking policy may NOT reflect the correct
148: locking policy. For example, if the container is a table (not an index)
149: and Access handles the locking of the table via an index, the container's
150: locking policy would be set to do no locking.
151: Moreover, if the container is an index, the locking policy would
152: always be set to do no locking.
153: */
154:
155: LockingPolicy lp = owner.getTransaction().newLockingPolicy(
156: LockingPolicy.MODE_RECORD,
157: TransactionController.ISOLATION_REPEATABLE_READ, true);
158:
159: // reopen the container
160: owner = (BaseContainerHandle) owner.getTransaction()
161: .openContainer(owner.getId(), lp, owner.getMode());
162:
163: // get a read lock on the appropriate row
164: // this will wait until either the lock is granted or an exception is
165: // thrown
166: owner.getLockingPolicy().lockRecordForRead(
167: owner.getTransaction(), owner, recordToLock, true,
168: false);
169: }
170:
171: /*
172: Close the container associated with this stream. (In the future if we use
173: a read committed isolation mode, this will also free the associated IS
174: table lock and the associated S row lock.)
175: */
176: public void closeStream() {
177: owner.close();
178: }
179:
180: }
|