Bug #39572 Commit during scan can fail "half silent"
Submitted: 22 Sep 2008 2:56 Modified: 18 Oct 2009 19:09
Reporter: Gustaf Thorslund Email Updates:
Status: Not a Bug Impact on me:
None 
Category:MySQL Cluster: NDB API Severity:S3 (Non-critical)
Version:mysql-5.1-telco-6.3, 6.2 OS:Linux (Ubuntu Hardy x86_64)
Assigned to: Jonas Oreland CPU Architecture:Any
Tags: mysql-5.1-telco-6.3.17

[22 Sep 2008 2:56] Gustaf Thorslund
Description:
Sometimes when doing deletes during a scan operation the execute(Commit) return -1 but looking at the error there is none available.

myTrans->execute(Commit) -> -1
ScanOp: Error in ndbapi_scan.cpp, line: 360, status: 0, classification: 0, code: 0, message: No error.
Trans: Error in ndbapi_scan.cpp, line: 362, status: 0, classification: 0, code: 0, message: No error.
Ndb: Error in ndbapi_scan.cpp, line: 364, status: 0, classification: 0, code: 0, message: No error.

How to repeat:
Make the ndbapi_scan example more verbose.

Testing have been done on a 16 node cluster with NoOfReplicas=2 running on localhost.

Suggested fix:
Make sure the error shows up somewhere in the NdbOperation, NdbTransaction or Ndb object.
[22 Sep 2008 3:03] Gustaf Thorslund
More verbose ndbapi_scan.cpp and 10 test runs

Attachment: bug_39572_testcase.tar.gz (application/x-gzip, text), 6.03 KiB.

[22 Sep 2008 3:10] Gustaf Thorslund
Appears as anything done after the failed commit will fail too. So something did really go wrong.

From run.2.txt bug_39572_testcase.tar.gz:
-->
Going to delete all pink cars!
deletedRows = 1
deletedRows = 2
myTrans->execute(Commit) -> 0
deletedRows = 3
deletedRows = 4
deletedRows = 5
myTrans->execute(Commit) -> -1
ScanOp: Error in ndbapi_scan.cpp, line: 360, status: 0, classification: 0, code: 0, message: No error.
Trans: Error in ndbapi_scan.cpp, line: 362, status: 0, classification: 0, code: 0, message: No error.
Ndb: Error in ndbapi_scan.cpp, line: 364, status: 0, classification: 0, code: 0, message: No error.
myTrans->restart() -> 0
No error
9       BMW     Black
3       Mercedes        Blue
6       BMW     Black
12      Toyota  Pink
11      Toyota  Pink
14      Toyota  Pink
1       Mercedes        Blue
0       Mercedes        Blue
4       Mercedes        Blue
7       BMW     Black
5       BMW     Black
8       BMW     Black
2       Mercedes        Blue
scan_print: Success!
-->

How hard should it be to remove a Pink Toyota anyway?
[22 Sep 2008 3:13] Gustaf Thorslund
16 node localhost configuration used

Attachment: config.ini (application/octet-stream, text), 1.65 KiB.

[23 Sep 2008 4:28] Gustaf Thorslund
Two small changes that got the code compile and work:
--- ../bug_39572_testcase/ndbapi_scan.cpp       2008-09-22 04:57:57.958779148 +0200
+++ ndbapi_scan.cpp     2008-09-22 09:31:03.018774373 +0200
@@ -365,8 +365,9 @@
        }
       }
 
-      if(check == -1)
+      if(1 || check == -1)
       {
+       std::cout << "check = " << check << std::endl;
        /**
         * Create a new transaction, while keeping scan open
         */
@@ -389,7 +390,7 @@
        }
        else if (err.status != NdbError::Success)
        {
-         APIERROR(myTrans->getNdbError);
+         APIERROR(myTrans->getNdbError());
        }
       }
       /**

So some comments on the code:

	/**
	 * nextResult(false) means that the records 
	 * cached in the NDBAPI are modified before
	 * fetching more rows from NDB.
	 */    
      } while((check = myScanOp->nextResult(false)) == 0); // [1]
      
      /**
       * Commit when all cached tuple have been marked for deletion
       */    
      if(check != -1) // [2]
      {
	check = myTrans->execute(NdbTransaction::Commit);
	std::cout << "myTrans->execute(Commit) -> " << check << std::endl;
	if(check == -1) // Something went wrong, let's check what
	{
	  std::cout << "ScanOp: ";
	  PRINT_API_ERROR(myScanOp->getNdbError());
	  std::cout << "Trans: ";
	  PRINT_API_ERROR(myTrans->getNdbError());
	  std::cout << "Ndb: ";
	  PRINT_API_ERROR(myNdb->getNdbError());
	}
      }

      if(1 || check == -1) // [3]
      {
	std::cout << "check = " << check << std::endl;
	/**
	 * Create a new transaction, while keeping scan open
	 */
	check = myTrans->restart(); // [4]
	std::cout << "myTrans->restart() -> " << check << std::endl;
      }

[1] We will exit this loop if there was no other tuple received. The
    possible return values are:

   * @return 
   * -  -1: if unsuccessful,<br>
   * -   0: if another tuple was received, and<br> 
   * -   1: if there are no more tuples to scan.
   * -   2: if there are no more cached records in NdbApi
   */
  int nextResult(bool fetchAllowed = true, bool forceSend = false);

    so anything except 0.

[2] We commit the transaction unless the scan was unsuccessful so
    that's ok. But we will reset the value of 'check'.

[3],[4] The only reason we can't really restart the transaction is if
	the commit failed, see bug#39573 and the source for
	NdbTransaction.hpp:

   *  @note This method can only be called _directly_ after commit
   *        and only if commit is successful
   */
  int restart();

   Restarting the scan don't really make any sense to me if there are
   no more tuples to scan (return value 1 in [1]) but we have lost
   track of that information in this step.

So the reason for this "half silent" failure appears to be that the
transaction was not restarted before next scan. So a little bit of a
programming error, but still strange that there are no error code or
message. Just a commit that fail.
[15 Oct 2009 5:36] Jonas Oreland
the restart() method is scheduled for removal,
i've updated the examples not to use it.

i really feel like closing this as not a bug, with the comment rtfm.
but, setting to NeedFeedback
[15 Oct 2009 5:51] Gustaf Thorslund
Jonas,

Sure! Go ahead and do what you feel is right. !bg or duplicate of bug#38163.

/Gustaf
[18 Oct 2009 19:09] Jonas Oreland