From 8a13236c15cb27e62c4654fc0120aa8896633dd8 Mon Sep 17 00:00:00 2001
From: abobrov <abobrov@localhost>
Date: Thu, 26 Mar 2009 16:44:59 +0000
Subject: [PATCH] - [Issue 3894] possible data corruption issues when writing binary attributes/blobs : move blobs to active state before writing the actual data, use new writeData API, optimize add operation to invoke execute/NoCommit past insert only when necessary ie when batching.

---
 opendj-sdk/opends/src/server/org/opends/server/backends/ndb/EntryContainer.java     |   31 +++++++++++++++++++------------
 opendj-sdk/opends/src/server/org/opends/server/backends/ndb/OperationContainer.java |   25 ++++++++++++++++++++++---
 2 files changed, 41 insertions(+), 15 deletions(-)

diff --git a/opendj-sdk/opends/src/server/org/opends/server/backends/ndb/EntryContainer.java b/opendj-sdk/opends/src/server/org/opends/server/backends/ndb/EntryContainer.java
index 0379c05..196afa7 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/backends/ndb/EntryContainer.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/backends/ndb/EntryContainer.java
@@ -661,7 +661,7 @@
       try
       {
         // Invoke the operation.
-        operation.invokeOperation(txn);
+        operation.invokeOperation(txn, commit);
 
         // One last check before committing.
         if (ldapOperation != null) {
@@ -734,12 +734,13 @@
      * Invoke the operation under the given transaction.
      *
      * @param txn The transaction to be used to perform the operation.
+     * @param willCommit Indicates whether or not the caller will commit.
      * @throws NdbApiException If an error occurs in the NDB database.
      * @throws DirectoryException If a Directory Server error occurs.
      * @throws NDBException If an error occurs in the NDB backend.
      */
-    public abstract void invokeOperation(AbstractTransaction txn)
-        throws NdbApiException, DirectoryException,
+    public abstract void invokeOperation(AbstractTransaction txn,
+      boolean willCommit) throws NdbApiException, DirectoryException,
         CanceledOperationException, NDBException;
 
     /**
@@ -785,11 +786,12 @@
      * Invoke the operation under the given transaction.
      *
      * @param txn The transaction to be used to perform the operation.
+     * @param willCommit Indicates whether or not the caller will commit.
      * @throws NdbApiException If an error occurs in the NDB database.
      * @throws DirectoryException If a Directory Server error occurs.
      * @throws NDBException If an error occurs in the NDB backend.
      */
-    public void invokeOperation(AbstractTransaction txn)
+    public void invokeOperation(AbstractTransaction txn, boolean willCommit)
         throws NdbApiException, DirectoryException, NDBException
     {
       // Check that the parent entry exists.
@@ -816,7 +818,9 @@
       // Insert.
       try {
         dn2id.insert(txn, entry.getDN(), entryID, entry);
-        txn.execute();
+        if (!willCommit) {
+          txn.execute();
+        }
       } catch (NdbApiException ne) {
         if (ne.getErrorObj().getClassification() ==
           NdbError.Classification.ConstraintViolation)
@@ -1129,11 +1133,12 @@
      * Invoke the operation under the given transaction.
      *
      * @param txn The transaction to be used to perform the operation.
+     * @param willCommit Indicates whether or not the caller will commit.
      * @throws NdbApiException If an error occurs in the NDB database.
      * @throws DirectoryException If a Directory Server error occurs.
      * @throws NDBException If an error occurs in the NDB backend.
      */
-    public void invokeOperation(AbstractTransaction txn)
+    public void invokeOperation(AbstractTransaction txn, boolean willCommit)
         throws CanceledOperationException, NdbApiException,
         DirectoryException, NDBException
     {
@@ -1412,12 +1417,13 @@
     /**
      * Invoke the operation under the given transaction.
      *
-     * @param txn The transaction to be used to perform the operation
+     * @param txn The transaction to be used to perform the operation.
+     * @param willCommit Indicates whether or not the caller will commit.
      * @throws NdbApiException If an error occurs in the NDB database.
      * @throws DirectoryException If a Directory Server error occurs.
      * @throws NDBException If an error occurs in the NDB backend.
      */
-    public void invokeOperation(AbstractTransaction txn)
+    public void invokeOperation(AbstractTransaction txn, boolean willCommit)
       throws NdbApiException, DirectoryException, NDBException
     {
       entry = dn2id.get(txn, entryDN, lockMode);
@@ -1510,13 +1516,13 @@
      * Invoke the operation under the given transaction.
      *
      * @param txn The transaction to be used to perform the operation.
+     * @param willCommit Indicates whether or not the caller will commit.
      * @throws NdbApiException If an error occurs in the NDB database.
      * @throws DirectoryException If a Directory Server error occurs.
      * @throws NDBException If an error occurs in the NDB backend.
      */
-    public void invokeOperation(AbstractTransaction txn) throws NdbApiException,
-                                                        DirectoryException,
-                                                        NDBException
+    public void invokeOperation(AbstractTransaction txn, boolean willCommit)
+      throws NdbApiException, DirectoryException, NDBException
     {
       DN entryDN = newEntry.getDN();
       entryID = (Long) oldEntry.getAttachment();
@@ -1645,11 +1651,12 @@
      * Invoke the operation under the given transaction.
      *
      * @param txn The transaction to be used to perform the operation.
+     * @param willCommit Indicates whether or not the caller will commit.
      * @throws NdbApiException If an error occurs in the NDB database.
      * @throws DirectoryException If a Directory Server error occurs.
      * @throws NDBException If an error occurs in the NDB backend.
      */
-    public void invokeOperation(AbstractTransaction txn)
+    public void invokeOperation(AbstractTransaction txn, boolean willCommit)
       throws NdbApiException, DirectoryException,
       CanceledOperationException, NDBException
     {
diff --git a/opendj-sdk/opends/src/server/org/opends/server/backends/ndb/OperationContainer.java b/opendj-sdk/opends/src/server/org/opends/server/backends/ndb/OperationContainer.java
index 3154152..18bc508 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/backends/ndb/OperationContainer.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/backends/ndb/OperationContainer.java
@@ -161,6 +161,8 @@
     Map<ObjectClass, String> ocMap = entry.getObjectClasses();
     Map<AttributeType, List<Attribute>> userAttrMap =
       entry.getUserAttributes();
+    Map<NdbBlob, byte[]> blobMap =
+      new HashMap<NdbBlob, byte[]>(BackendImpl.blobAttributes.size());
     ArrayList<AttributeType> userAttributes =
       new ArrayList<AttributeType>();
 
@@ -252,7 +254,9 @@
               }
               if (BackendImpl.blobAttributes.contains(attrName)) {
                 NdbBlob blob = attrOp.getBlobHandle(attrName);
-                blob.setValue(attrVal.getValue().toByteArray());
+                blob.setValue(new byte[0]);
+                byte[] blobBytes = attrVal.getValue().toByteArray();
+                blobMap.put(blob, blobBytes);
               } else {
                 attrOp.setString(attrName, attrStringVal);
               }
@@ -328,7 +332,9 @@
               }
               if (BackendImpl.blobAttributes.contains(attrName)) {
                 NdbBlob blob = attrOp.getBlobHandle(attrName);
-                blob.setValue(attrVal.getValue().toByteArray());
+                blob.setValue(new byte[0]);
+                byte[] blobBytes = attrVal.getValue().toByteArray();
+                blobMap.put(blob, blobBytes);
               } else {
                 attrOp.setString(attrName, attrStringVal);
               }
@@ -421,7 +427,9 @@
               }
               if (BackendImpl.blobAttributes.contains(attrName)) {
                 NdbBlob blob = attrOp.getBlobHandle(attrName);
-                blob.setValue(attrVal.getValue().toByteArray());
+                blob.setValue(new byte[0]);
+                byte[] blobBytes = attrVal.getValue().toByteArray();
+                blobMap.put(blob, blobBytes);
               } else {
                 attrOp.setString(attrName, attrStringVal);
               }
@@ -477,6 +485,17 @@
       }
     }
 
+    // Move this txn into the active state and write blob data if any.
+    if (!blobMap.isEmpty()) {
+      ndbDATxn.execute(ExecType.NoCommit, AbortOption.AbortOnError, true);
+      Set<Map.Entry<NdbBlob, byte[]>> blobEntrySet = blobMap.entrySet();
+      for (Map.Entry blobEntry : blobEntrySet) {
+        NdbBlob blob = (NdbBlob) blobEntry.getKey();
+        byte[] blobBytes = (byte[]) blobEntry.getValue();
+        blob.writeData(blobBytes);
+      }
+    }
+
     // Update dn2id table.
     NdbTransaction ndbTxn = txn.getNdbTransaction();
     if (overwrite) {

--
Gitblit v1.10.0