Abstract
This section describes how NDB API errors can be detected and mapped onto particular operations.
NDB API errors can be generated in either of two ways:
When an operation is defined
When an operation is executed
Errors raised during operation definition.
Errors generated during operation definition result in a
failure return code from the method called. The actual error
can be determined by examining the relevant
NdbOperation object, or the
operation's
NdbTransaction object.
Errors raised during operation execution.
Errors occurring during operation execution cause the
transaction of which they are a part to be aborted unless the
AO_IgnoreError abort option is set for the
operation.
If you have worked with older versions of the NDB API, you
should be aware that, beginning with MySQL Cluster NDB 6.2.0,
the AbortOption type is a member of
NdbOperation. See
Section 2.3.23.1.1, “The NdbOperation::AbortOption Type”, for more
information.
By default, read operations are run with
AO_IgnoreError, and write operations are run
with AbortOnError, but this can be overridden
by the user. When an error during execution causes a transaction
to be aborted, the execute() method returns a
failure return code. If an error is ignored due to
AO_IgnoreError being set on the operation,
the execute() method returns a success code,
and the user must examine all operations for failure using
NdbOperation::getNdbError().
For this reason, the return value of
getNdbError() should usually be checked, even
if execute() returns success. If the client
application does not keep track of
NdbOperation objects during
execution, then
NdbTransaction::getNextCompletedOperation()
can be used to iterate over them.
You should also be aware that use of
NdbBlob can result in extra
operations being added to the batches executed. This means that,
when iterating over completed operations using
getNextCompletedOperation(), you may
encounter operations related to
NdbBlob objects which were not
defined by your application.
A read whose LockMode is
CommittedRead cannot be
AbortOnError. In this case, it is always be
IgnoreError.
In all cases where operation-specific errors arise, an execution
error with an operation is marked against both the operation and
the associated transaction object. Where there are multiple
operation errors in a single
NdbTransaction::execute() call,
due to operation batching and the use of
AO_IgnoreError, only the first is marked
against the NdbTransaction
object. The remaining errors are recorded against the
corresponding NdbOperation
objects only.
It is also possible for errors to occur during execution—such as a data node failure—which are marked against the transaction object, but not against the underlying operation objects. This is because these errors apply to the transaction as a whole, and not to individual operations within the transaction.
For this reason, applications should use
NdbTransaction::getNdbError()
as the first way to determine whether an
NdbTransaction::execute() call
failed. If the batch of operations being executed included
operations with the AO_IgnoreError abort
option set, then it is possible that there were multiple
failures, and the completed operations should be checked
individually for errors using
NdbOperation::getNdbError().
Implicit NdbTransaction::execute()
calls in scan and BLOB methods.
Scan operations are executed in the same way as other
operations, and also have implicit
execute() calls within the
NdbScanOperation::nextResult()
method. When
NdbScanOperation::nextResult()
indicates failure (that is, if the method returns
-1), the transaction object should be
checked for an error. The
NdbScanOperation may also
contain the error, but only if the error is not
operation-specific.
Some BLOB manipulation methods also have
implicit internal execute() calls, and so can
experience operation execution failures at these points. The
following NdbBlob methods can
generate implicit execute() calls; this means
that they also require checks of the
NdbTransaction object for
errors via
NdbTransaction::getNdbError()
if they return an error code:
setNull()
truncate()
readData()
writeData()
Summary. In general, it is possible for an error to occur during execution (resulting in a failure return code) when calling any of the following methods:
NdbScanOperation::nextResult()
This method does not perform an
implicit execute() call. The
NdbBlob methods can cause
other defined operations to be executed when these methods
are called; however, nextResult() calls
do not do so.
If this happens, the
NdbTransaction::getNdbError()
method should be called to identify the first error that
occurred. When operations are batched, and there are
IgnoreError operations in the batch, there
may be multiple operations with errors in the transaction. These
can be found by using
NdbTransaction::getNextCompletedOperation()
to iterate over the set of completed operations, calling
NdbOperation::getNdbError() for
each operation.
When IgnoreError has been set on any
operations in a batch of operations to be executed, the
NdbTransaction::execute()
method indicates success even where errors have actually
occurred, as long as none of these errors caused a transaction
to be aborted. To determine whether there were any ignored
errors, the transaction error status should be checked using
NdbTransaction::getNdbError().
Only if this indicates success can you be certain that
no errors occurred. If an error code is returned by
this method, and operations were batched, then you should
iterate over all completed operations to find all the operations
with ignored errors.
Example (pseudocode).
We begin by executing a transaction which may have batched
operations and a mix of AO_IgnoreError and
AbortOnError abort options:
int execResult= NdbTransaction.execute(args);
For the number and permitted values of
args, see
Section 2.3.28.2.4, “NdbTransaction::execute()”.
Next, because errors on AO_IgnoreError
operations do not affect execResult—that is, the value
returned by execute()—we check for
errors on the transaction:
NdbError err= NdbTransaction.getNdbError();
if (err.code != 0)
{
An nonzero value for the error code means that an error was raised on the transaction. This could be due to any of the following conditions:
A transaction-wide error, such as a data node failure, that caused the transaction to be aborted
A single operation-specific error, such as a constraint violation, that caused the transaction to be aborted
A single operation-specific ignored error, such as no data found, that did not cause the transaction to be aborted
The first of many operation-specific ignored errors, such as no data found when batching, that did not cause the transaction to be aborted
First of a number of operation-specific ignored errors such as no data found (when batching) before an aborting operation error (transaction aborted)
if (execResult != 0)
{
The transaction has been aborted. The recommended strategy for handling the error in this case is to test the transaction error status and take appropriate action based on its value:
switch (err.status)
{
case value1:
// statement block handling value1 ...
case value2:
// statement block handling value2 ...
// (etc. ...)
case valueN:
// statement block handling valueN ...
}
Since the transaction was aborted, it is generally necessary to iterate over the completed operations (if any) and find the errors raised by each only if you wish to do so for reporting purposes.
}
else
{
The transaction itself was not aborted, but there must be one or more ignored errors. In this case, you should iterate over the operations to determine what happened and handle the cause accordingly.
} }
To handle a
NdbScanOperation::nextResult()
which returns -1, indicating that the
operation failed (omitting cases where the operation was
successful):
int nextrc= NdbScanOperation.nextResult(args);
For the number and permitted values of
args, see
Section 2.3.27.2.6, “NdbScanOperation::nextResult()”.
if (nextrc == -1)
{
First, you should check the
NdbScanOperation object for any
errors:
NdbError err= NdbScanOperation.getNdbError();
if (err.code == 0)
{
No error was found in the scan operation; the error must belong to the transaction as whole.
}
err= NdbTransaction.getNdbError();
Now you can handle the error based on the error status:
switch (err.status)
{
case value1:
// statement block handling value1 ...
case value2:
// statement block handling value2 ...
// (etc. ...)
case valueN:
// statement block handling valueN ...
}
}
For information about NDB API error classification and status
codes, see Section 7.2.3, “NDB Error Classifications”. While
you should not rely on a specific error code or message text in
your NDB API applications—since error codes and messages
are both subject to change over time—it can be useful to
check error codes and messages to help determine why a
particular failure occurred. For more information about these,
see Section 7.2.2, “NDB Error Codes and Messages”. For more about
NdbError and the types of
information which can be obtained from
NdbError objects, see
Section 2.3.18, “The NdbError Structure”.
