db-derby-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Army <a...@golux.com>
Subject [PATCH] DERBY-5 "Quick fix"
Date Sun, 31 Oct 2004 16:14:00 GMT

Attached are some changes that I am proposing as a "quick fix" to Derby-5.

The idea is fairly straightforward: at the beginning of every DSS request that we read in
the 
DRDAConnThread.processCommand() method, we "mark" our position in the DSS reply buffer.  Then,
if we encounter any 
exceptions while processing the DSS request(s), we catch the exception, "clear" the write
buffer back to the "marked" 
location, and then write whatever error indication is expected by DRDA protocol (which is
usually just an SQLCARD).  I 
added two methods to DDMWriter for this: one to mark the location, the other to "clear" back
to the mark.

I call this a "quick fix" because it does NOT handle the potential scenario where, after we
"mark" the write buffer, the 
buffer fills up and thus is sent, and then _after_ sending, we get an error that requires
use to "clear back to mark". 
Obviously, since we already sent the marked location across the wire, we can't "clear" back
to it--so this patch won't work.

The reason I'm hoping that this "quick fix" is acceptable is because the current code (with
the "clearBuffer" call that 
is causing Derby-5) doesn't handle the above-mentioned scenario, either--so all in all, we'd
be better off with this 
patch than we were before, even though there's some more complicated work to be done.

Hopefully this can resolve any immediate failures that might be caused by Derby-5--and especially,
Derby-5 failures that 
were hidden until last week but were exposed by my patch for Derby-35.

Comments/feedback/concerns are, of course, always welcomed...

Thanks,
Army

----

Index: DDMWriter.java
===================================================================
--- DDMWriter.java	(revision 56039)
+++ DDMWriter.java	(working copy)
@@ -90,7 +90,13 @@

  	// Whether or not the current DSS is a continuation DSS.
  	private boolean isContinuationDss;
-	
+
+	// In situations where we want to "mark" a buffer location so that
+	// we can "back-out" of a write to handle errors, this holds the
+	// location within the "bytes" array of the start of the header
+	// that immediately precedes the mark.
+	private int lastDSSBeforeMark;
+
  	// Constructors
  	DDMWriter (int minSize, CcsidManager ccsidManager, DRDAConnThread agent, DssTrace dssTrace)
  	{
@@ -101,6 +107,7 @@
  		this.previousCorrId = DssConstants.CORRELATION_ID_UNKNOWN;
  		this.previousChainByte = DssConstants.DSS_NOCHAIN;
  		this.isContinuationDss = false;
+		this.lastDSSBeforeMark = -1;
  		reset(dssTrace);
  	}

@@ -113,6 +120,7 @@
  		this.previousCorrId = DssConstants.CORRELATION_ID_UNKNOWN;
  		this.previousChainByte = DssConstants.DSS_NOCHAIN;
  		this.isContinuationDss = false;
+		this.lastDSSBeforeMark = -1;
  		reset(dssTrace);
  	}

@@ -1812,5 +1820,58 @@

  	}

+	/**
+	 * Takes note of the location of the most recently completed
+	 * DSS in the buffer, and then returns the current offset.
+	 * This method is used in conjunction with "clearDSSesBackToMark"
+	 * to allow for DRDAConnThread to "back-out" DSSes in the
+	 * event of errors.
+	 */
+	protected int markDSSClearPoint()
+	{
+
+		lastDSSBeforeMark = prevHdrLocation;
+		return getOffset();
+
+	}
+
+	/**
+	 * Does a logical "clear" of everything written to the buffer after
+	 * the received mark.  It's assumed that this method will be used
+	 * in error cases when we've started writing one or more DSSes,
+	 * but then hit an error and need to back out.  After backing out,
+	 * we'll always need to write _something_ back to the client to
+	 * indicate an error (typically, we just write an SQLCARD) but what
+	 * exactly gets written is handled in DRDAConnThread.  Here, we
+	 * just do the necessary prep so that whatever comes next will
+	 * succeed.
+	 */
+	protected void clearDSSesBackToMark(int mark)
+	{
+
+		// Logical clear.
+		setOffset(mark);
+
+		// Because we've just cleared out the most recently-
+		// written DSSes, we have to make sure the next thing
+		// we write will have the correct correlation id.  We
+		// do this by setting the value of 'nextCorrelationID'
+		// based on the chaining byte from the last remaining
+		// DSS (where "remaining" means that it still exists
+		// in the buffer after the clear).
+		if (lastDSSBeforeMark == -1)
+		// we cleared out the entire buffer; reset corr id.
+			nextCorrelationID = 1;
+		else {
+		// last remaining DSS had chaining, so we set "nextCorrelationID"
+		// to be 1 greater than whatever the last remaining DSS had as
+		// its correlation id.
+ 			nextCorrelationID = 1 + (int)
+				(((bytes[lastDSSBeforeMark + 4] & 0xff) << 8) +
+				(bytes[lastDSSBeforeMark + 5] & 0xff));
+		}
+
+	}
+
  }

Index: DRDAConnThread.java
===================================================================
--- DRDAConnThread.java	(revision 56039)
+++ DRDAConnThread.java	(working copy)
@@ -558,6 +558,7 @@
  		{
  			correlationID = reader.readDssHeader();
  			int codePoint = reader.readLengthAndCodePoint();
+			int writerMark = writer.markDSSClearPoint();
  			switch(codePoint)
  			{
  				case CodePoint.CNTQRY:
@@ -581,7 +582,7 @@
   						{
  							// if we got a SQLException we need to clean up and
   							// close the statement Beetle 4758
-							writer.clearBuffer();
+							writer.clearDSSesBackToMark(writerMark);
   							if (! stmt.rsIsClosed())
   							{
   								try {
@@ -626,6 +627,7 @@
  							null, updateCount, true, true);
  					} catch (SQLException e)
  					{
+						writer.clearDSSesBackToMark(writerMark);
  						writeSQLCARDs(e, 0);
  						errorInChain(e);
  					}
@@ -643,6 +645,7 @@
  					}
  					catch (SQLException e)
  					{
+						writer.clearDSSesBackToMark(writerMark);
  						writeSQLCARDs(e, 0);
  						errorInChain(e);
  					}
@@ -663,6 +666,7 @@

  					} catch (SQLException e)
  					{
+						writer.clearDSSesBackToMark(writerMark);
  						writeSQLCARDs(e, 0, true);
  						PRPSQLSTTfailed = true;
  						errorInChain(e);
@@ -702,13 +706,9 @@
  					}
  					catch (SQLException e)
  					{
+						writer.clearDSSesBackToMark(writerMark);
  						try {
  							// Try to cleanup if we hit an error.
-							// We me have written all or part of
-							// OPNQRYRM and/or QRYDSC before hitting
-							// the error, so we have to clear the write
-							// buffer and ONLY write the OPNQLFRM.
-							writer.clearBuffer();
  							if (ps != null)
  								ps.close();
  							writeOPNQFLRM(e);
@@ -735,6 +735,7 @@
  					}
  					catch (SQLException e)
  					{
+						writer.clearDSSesBackToMark(writerMark);
  						// Even in case of error, we have to write the ENDUOWRM.
  						writeENDUOWRM(COMMIT);
  						writeSQLCARDs(e, 0);
@@ -756,6 +757,7 @@
  					}
  					catch (SQLException e)
  					{
+						writer.clearDSSesBackToMark(writerMark);
  						// Even in case of error, we have to write the ENDUOWRM.
  						writeENDUOWRM(ROLLBACK);
  						writeSQLCARDs(e, 0);
@@ -770,6 +772,7 @@
  					}
  					catch (SQLException e)
  					{
+						writer.clearDSSesBackToMark(writerMark);
  						writeSQLCARDs(e, 0);
  						errorInChain(e);
  					}
@@ -811,6 +814,7 @@
  						
  					} catch (SQLException e)
  					{
+						writer.clearDSSesBackToMark(writerMark);
  						server.consoleExceptionPrint(e);
  						try {
  							writeSQLDARD(database.getCurrentStatement(), true, e);
@@ -835,6 +839,7 @@
  							curStmt.rsSuspend();
  					} catch (SQLException e)
  					{
+						writer.clearDSSesBackToMark(writerMark);
  						if (SanityManager.DEBUG)
  						{
  							server.consoleExceptionPrint(e);

Mime
View raw message