001: //
002: // Copyright 1998 CDS Networks, Inc., Medford Oregon
003: //
004: // All rights reserved.
005: //
006: // Redistribution and use in source and binary forms, with or without
007: // modification, are permitted provided that the following conditions are met:
008: // 1. Redistributions of source code must retain the above copyright
009: // notice, this list of conditions and the following disclaimer.
010: // 2. Redistributions in binary form must reproduce the above copyright
011: // notice, this list of conditions and the following disclaimer in the
012: // documentation and/or other materials provided with the distribution.
013: // 3. All advertising materials mentioning features or use of this software
014: // must display the following acknowledgement:
015: // This product includes software developed by CDS Networks, Inc.
016: // 4. The name of CDS Networks, Inc. may not be used to endorse or promote
017: // products derived from this software without specific prior
018: // written permission.
019: //
020: // THIS SOFTWARE IS PROVIDED BY CDS NETWORKS, INC. ``AS IS'' AND
021: // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
022: // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
023: // ARE DISCLAIMED. IN NO EVENT SHALL CDS NETWORKS, INC. BE LIABLE
024: // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
025: // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
026: // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
027: // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
028: // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
029: // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
030: // SUCH DAMAGE.
031: //
032:
033: package com.internetcds.jdbc.tds;
034:
035: /**
036: * This class provides support for canceling queries.
037: * <p>
038: * Basically all threads can be divided into two groups, workers and
039: * cancelers. The canceler can cancel at anytime, even when there is no
040: * outstanding query to cancel. A worker can be in one of 4 states-
041: * <p>
042: * 1) Not doing anything DB related.<br>
043: * 2) currently sending a request to the database. (Note- any time
044: * a request is sent to the DB the DB will send a response. This
045: * means a thread in state 2 must go to state 3.)<br>
046: * 3) waiting for a response from DB<br>
047: * 4) reading the response from DB<br>
048: * <p>
049: * I can easily make it so that only one thread at a time can be in state
050: * 2, 3, or 4.
051: * <p>
052: * The way that a cancel works in TDS is you send a cancel packet to
053: * server. The server will then stop whatever it might be doing and
054: * reply with END_OF_DATA packet with the cancel flag set. (It sends
055: * this packet even if it wasn't doing anything.) I will call this
056: * packet a CANCEL_ACK packet
057: * <p>
058: * All that I really need is to do is make sure that I try to read as
059: * many CANCEL_ACKs as I request and the I make sure that some thread is
060: * out there ready to read any CANCEL_ACKs that i request.
061: * <p>
062: * Clearly if all my worker threads are in state 1 then the cancel
063: * request could be just a nop.
064: * <p>
065: * If I have some worker thread in state 2, 3, or 4 I think I will be fine
066: * if I just make sure that the thread reads until the CANCEL_ACK packet.
067: * <p>
068: * I think I will just have a control object that has one boolean,
069: * readInProgress and two integers, cancelsRequested and
070: * cancelsProcessed.
071: * <p>
072: * <p>
073: * The doCancel() method will-
074: * a) lock the object
075: * b) if there is no read in progress it will unlock and return.
076: * c) otherwise it will send the CANCEL packet,
077: * d) increment the cancelsRequested
078: * e) unlock object and wait until notified that the
079: * cancel was ack'd
080: * <p>
081: * Whenever the worker thread wants to read a response from the DB it
082: * must-
083: * a) lock the control object,<b>
084: * b) set the queryOutstanding flag<b>
085: * c) unlock the control object<b>
086: * d) call the Tds.processSubPacket() method.<b>
087: * e) lock the control object<b>
088: * f) If the packet was a cancel ack it will increment
089: * cancelsProcessed <b>
090: * g) notify any threads that are waiting for cancel acknowledgment<b>
091: * h) unlock the control object.<b>
092: *
093: * @version $Id: CancelController.java,v 1.2 2007-10-19 13:21:40 sinisa Exp $
094: @ @author Craig Spannring
095: */
096: public class CancelController {
097: public static final String cvsVersion = "$Id: CancelController.java,v 1.2 2007-10-19 13:21:40 sinisa Exp $";
098:
099: boolean awaitingData = false;
100: int cancelsRequested = 0;
101: int cancelsProcessed = 0;
102:
103: public synchronized void setQueryInProgressFlag() {
104: awaitingData = true;
105: }
106:
107: private synchronized void clearQueryInProgressFlag() {
108: awaitingData = false;
109: }
110:
111: public synchronized void finishQuery(boolean wasCanceled,
112: boolean moreResults) {
113: // XXX Do we want to clear the query in progress flag if
114: // there are still more results for multi result set query?
115: // Whatever mechanism is used to handle outstanding query
116: // requires knowing if there is any thread out there that could
117: // still process the query acknowledgment. Prematurely clearing
118: // could cause data to be thrown out before the thread expecting
119: // the data gets a chance to process it. That could cause the
120: // thread to read some other threads query.
121: //
122: // Is it good enough to just look at the MORERESULTS bit in the
123: // TDS_END* packet and not clear the flag if we have more
124: // results?
125: if (!moreResults) {
126: clearQueryInProgressFlag();
127: }
128:
129: if (wasCanceled) {
130: handleCancelAck();
131: }
132:
133: // XXX Should we see if there are any more cancels pending and
134: // try to read the cancel acknowledgments?
135: }
136:
137: public synchronized void doCancel(TdsComm comm)
138: throws java.io.IOException {
139: if (awaitingData) {
140: comm.startPacket(TdsComm.CANCEL);
141: comm.sendPacket();
142: cancelsRequested++;
143:
144: while (cancelsRequested > cancelsProcessed) {
145: try {
146: wait();
147: // XXX If there are cancels pending but nobody is is
148: // awaiting data on this connection, should we go out
149: // and try to get the CANCELACK packet?
150: } catch (java.lang.InterruptedException e) {
151: // nop
152: }
153: }
154: } else {
155: // if we aren't waiting for anything from
156: // the server then we have nothing to cancel
157:
158: // nop
159: }
160: }
161:
162: private synchronized void handleCancelAck() {
163: cancelsProcessed++;
164: notify();
165: }
166: }
|