[exo-jcr-commits] exo-jcr SVN: r4307 - in jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc: optimisation and 1 other directories.

do-not-reply at jboss.org do-not-reply at jboss.org
Wed Apr 27 03:54:11 EDT 2011


Author: tolusha
Date: 2011-04-27 03:54:11 -0400 (Wed, 27 Apr 2011)
New Revision: 4307

Modified:
   jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/JDBCStorageConnection.java
   jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/SQLExceptionHandler.java
   jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/CQJDBCStorageConnection.java
   jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/MultiDbJDBCConnection.java
   jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/SingleDbJDBCConnection.java
Log:
EXOJCR-1111: Reduce the total amount of queries needed to update a property

Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/JDBCStorageConnection.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/JDBCStorageConnection.java	2011-04-26 13:20:25 UTC (rev 4306)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/JDBCStorageConnection.java	2011-04-27 07:54:11 UTC (rev 4307)
@@ -85,7 +85,7 @@
    /**
     * Helper.
     */
-   class WriteValueHelper extends ValueFileIOHelper
+   protected class WriteValueHelper extends ValueFileIOHelper
    {
       /**
        * {@inheritDoc}

Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/SQLExceptionHandler.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/SQLExceptionHandler.java	2011-04-26 13:20:25 UTC (rev 4306)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/SQLExceptionHandler.java	2011-04-27 07:54:11 UTC (rev 4307)
@@ -352,7 +352,7 @@
     * @throws InvalidItemStateException
     *           if <code>InvalidItemStateException</code> should be thrown
     */
-   protected String handleUpdateException(SQLException e, ItemData item) throws RepositoryException,
+   public String handleUpdateException(SQLException e, ItemData item) throws RepositoryException,
       InvalidItemStateException
    {
       String message = "[" + containerName + "] EDIT " + (item.isNode() ? "NODE. " : "PROPERTY. ");

Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/CQJDBCStorageConnection.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/CQJDBCStorageConnection.java	2011-04-26 13:20:25 UTC (rev 4306)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/CQJDBCStorageConnection.java	2011-04-27 07:54:11 UTC (rev 4307)
@@ -18,8 +18,10 @@
  */
 package org.exoplatform.services.jcr.impl.storage.jdbc.optimisation;
 
+import org.exoplatform.commons.utils.PrivilegedFileHelper;
 import org.exoplatform.services.jcr.access.AccessControlEntry;
 import org.exoplatform.services.jcr.access.AccessControlList;
+import org.exoplatform.services.jcr.dataflow.ItemState;
 import org.exoplatform.services.jcr.dataflow.persistent.PersistedNodeData;
 import org.exoplatform.services.jcr.dataflow.persistent.PersistedPropertyData;
 import org.exoplatform.services.jcr.datamodel.IllegalACLException;
@@ -31,15 +33,22 @@
 import org.exoplatform.services.jcr.datamodel.QPathEntry;
 import org.exoplatform.services.jcr.datamodel.ValueData;
 import org.exoplatform.services.jcr.impl.Constants;
+import org.exoplatform.services.jcr.impl.dataflow.persistent.StreamPersistedValueData;
+import org.exoplatform.services.jcr.impl.storage.JCRInvalidItemStateException;
 import org.exoplatform.services.jcr.impl.storage.jdbc.JDBCStorageConnection;
 import org.exoplatform.services.jcr.impl.storage.jdbc.PrimaryTypeNotFoundException;
+import org.exoplatform.services.jcr.impl.storage.value.ValueStorageNotFoundException;
 import org.exoplatform.services.jcr.impl.util.io.FileCleaner;
+import org.exoplatform.services.jcr.impl.util.io.SwapFile;
+import org.exoplatform.services.jcr.storage.value.ValueIOChannel;
 import org.exoplatform.services.jcr.storage.value.ValueStoragePluginProvider;
 import org.exoplatform.services.log.ExoLogger;
 import org.exoplatform.services.log.Log;
 
+import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
 import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
@@ -47,6 +56,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -55,6 +65,7 @@
 import java.util.TreeSet;
 
 import javax.jcr.InvalidItemStateException;
+import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
 
 /**
@@ -91,6 +102,21 @@
     */
    protected String FIND_ITEM_QPATH_BY_ID_CQ;
 
+   /**
+    * FIND_PROPERTY_BY_ID.
+    */
+   protected String FIND_PROPERTY_BY_ID;
+
+   /**
+    * DELETE_VALUE_BY_ORDER_NUM.
+    */
+   protected String DELETE_VALUE_BY_ORDER_NUM;
+
+   /**
+    * UPDATE_VALUE.
+    */
+   protected String UPDATE_VALUE;
+   
    protected PreparedStatement findNodesByParentIdCQ;
 
    protected PreparedStatement findPropertiesByParentIdCQ;
@@ -99,6 +125,12 @@
 
    protected PreparedStatement findItemQPathByIdentifierCQ;
 
+   protected PreparedStatement findPropertyById;
+   
+   protected PreparedStatement deleteValueDataByOrderNum;
+   
+   protected PreparedStatement updateValue;
+
    /**
      * JDBCStorageConnection constructor.
      * 
@@ -190,11 +222,198 @@
          }
       }
    }
+   
 
    /**
     * {@inheritDoc}
     */
    @Override
+   public void update(PropertyData data) throws RepositoryException, UnsupportedOperationException,
+      InvalidItemStateException, IllegalStateException
+   {
+      checkIfOpened();
+      ResultSet rs = null;
+      try
+      {
+         String cid = getInternalId(data.getIdentifier());
+         // update type
+         if (updatePropertyByIdentifier(data.getPersistedVersion(), data.getType(), cid) <= 0)
+            throw new JCRInvalidItemStateException("(update) Property not found " + data.getQPath().getAsString() + " "
+               + data.getIdentifier() + ". Probably was deleted by another session ", data.getIdentifier(),
+               ItemState.UPDATED);
+
+         rs = findPropertyById(cid);
+         Set<String> storageDescs = new HashSet<String>();
+         int totalOldValues = 0;
+         int prevType = -1;
+         while (rs.next())
+         {
+            if (prevType == -1)
+            {
+               prevType = rs.getInt(COLUMN_PTYPE);
+            }
+            totalOldValues++;
+            final String storageId = rs.getString(COLUMN_VSTORAGE_DESC);
+            if (!rs.wasNull())
+            {
+               storageDescs.add(storageId);
+            }
+         }
+         // update reference
+         try
+         {
+            if (prevType == PropertyType.REFERENCE)
+            {
+               deleteReference(cid);
+            }
+
+            if (data.getType() == PropertyType.REFERENCE)
+            {
+               addReference(data);
+            }
+         }
+         catch (IOException e)
+         {
+            throw new RepositoryException("Can't update REFERENCE property (" + data.getQPath() + " "
+               + data.getIdentifier() + ") value: " + e.getMessage(), e);
+         }
+
+         deleteValues(cid, data, storageDescs, totalOldValues);
+         addOrUpdateValues(cid, data, totalOldValues);
+      }
+      catch (IOException e)
+      {
+         if (LOG.isDebugEnabled())
+            LOG.error("Property update. IO error: " + e, e);
+         throw new RepositoryException("Error of Property Value update " + e, e);
+      }
+      catch (SQLException e)
+      {
+         if (LOG.isDebugEnabled())
+            LOG.error("Property update. Database error: " + e, e);
+         exceptionHandler.handleUpdateException(e, data);
+      }
+      finally
+      {
+         if (rs != null)
+         {
+            try
+            {
+               rs.close();
+            }
+            catch (SQLException e)
+            {
+               LOG.error("Can't close the ResultSet: " + e);
+            }
+         }
+      }
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   protected void addValues(String cid, PropertyData data) throws IOException, SQLException, RepositoryException
+   {
+      addOrUpdateValues(cid, data, 0);
+   }
+
+   protected void addOrUpdateValues(String cid, PropertyData data, int totalOldValues) throws IOException,
+      RepositoryException, SQLException
+   {
+      List<ValueData> vdata = data.getValues();
+
+      for (int i = 0; i < vdata.size(); i++)
+      {
+         ValueData vd = vdata.get(i);
+         ValueIOChannel channel = valueStorageProvider.getApplicableChannel(data, i);
+         InputStream stream;
+         int streamLength;
+         String storageId;
+         if (channel == null)
+         {
+            // prepare write of Value in database
+            if (vd.isByteArray())
+            {
+               byte[] dataBytes = vd.getAsByteArray();
+               stream = new ByteArrayInputStream(dataBytes);
+               streamLength = dataBytes.length;
+            }
+            else
+            {
+               StreamPersistedValueData streamData = (StreamPersistedValueData)vd;
+
+               SwapFile swapFile = SwapFile.get(swapDirectory, cid + i + "." + data.getPersistedVersion());
+               try
+               {
+                  writeValueHelper.writeStreamedValue(swapFile, streamData);
+               }
+               finally
+               {
+                  swapFile.spoolDone();
+               }
+
+               long vlen = PrivilegedFileHelper.length(swapFile);
+               if (vlen <= Integer.MAX_VALUE)
+               {
+                  streamLength = (int)vlen;
+               }
+               else
+               {
+                  throw new RepositoryException("Value data large of allowed by JDBC (Integer.MAX_VALUE) " + vlen
+                     + ". Property " + data.getQPath().getAsString());
+               }
+
+               stream = streamData.getAsStream();
+            }
+            storageId = null;
+         }
+         else
+         {
+            // write Value in external VS
+            channel.write(data.getIdentifier(), vd);
+            valueChanges.add(channel);
+            storageId = channel.getStorageId();
+            stream = null;
+            streamLength = 0;
+         }
+         if (i < totalOldValues)
+         {
+            updateValueData(cid, i, stream, streamLength, storageId);
+         }
+         else
+         {
+            addValueData(cid, i, stream, streamLength, storageId);
+         }
+      }
+   }
+
+   private void deleteValues(String cid, PropertyData pdata, Set<String> storageDescs, int totalOldValues) throws ValueStorageNotFoundException, IOException, SQLException
+   {
+      for (String storageId : storageDescs)
+      {
+         final ValueIOChannel channel = valueStorageProvider.getChannel(storageId);
+         try
+         {
+            channel.delete(pdata.getIdentifier());
+            valueChanges.add(channel);
+         }
+         finally
+         {
+            channel.close();
+         }            
+      }
+      if (pdata.getValues().size() < totalOldValues)
+      {
+         // Remove the extra values
+         deleteValueDataByOrderNum(cid, pdata.getValues().size());
+      }
+   }
+   
+   /**
+    * {@inheritDoc}
+    */
+   @Override
    public List<PropertyData> getChildPropertiesData(NodeData parent) throws RepositoryException, IllegalStateException
    {
       checkIfOpened();
@@ -666,6 +885,21 @@
          {
             findItemQPathByIdentifierCQ.close();
          }
+         
+         if (findPropertyById != null)
+         {
+            findPropertyById.close();
+         }
+
+         if (deleteValueDataByOrderNum != null)
+         {
+            deleteValueDataByOrderNum.close();
+         }
+
+         if (updateValue != null)
+         {
+            updateValue.close();
+         }
       }
       catch (SQLException e)
       {
@@ -680,4 +914,11 @@
    protected abstract ResultSet findChildPropertiesByParentIdentifierCQ(String parentIdentifier) throws SQLException;
 
    protected abstract ResultSet findNodeMainPropertiesByParentIdentifierCQ(String parentIdentifier) throws SQLException;
+   
+   protected abstract ResultSet findPropertyById(String id) throws SQLException;
+   
+   protected abstract int deleteValueDataByOrderNum(String id, int orderNum) throws SQLException;
+
+   protected abstract int updateValueData(String cid, int i, InputStream stream, int streamLength, String storageId)
+      throws SQLException;
 }

Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/MultiDbJDBCConnection.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/MultiDbJDBCConnection.java	2011-04-26 13:20:25 UTC (rev 4306)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/MultiDbJDBCConnection.java	2011-04-27 07:54:11 UTC (rev 4307)
@@ -189,6 +189,11 @@
             + " join (select I.ID, I.PARENT_ID, I.NAME, I.VERSION, I.I_INDEX, I.N_ORDER_NUM from JCR_MITEM I"
             + " where I.I_CLASS=1 AND I.ID > ? order by I.ID LIMIT ? OFFSET ?) J on P.PARENT_ID = J.ID"
             + " where P.I_CLASS=2 and V.PROPERTY_ID=P.ID  order by J.ID";
+
+      FIND_PROPERTY_BY_ID =
+         "select I.P_TYPE, V.STORAGE_DESC from JCR_MITEM I, JCR_MVALUE V where I.ID = ? and V.PROPERTY_ID = I.ID";
+      DELETE_VALUE_BY_ORDER_NUM = "delete from JCR_MVALUE where PROPERTY_ID=? and ORDER_NUM >= ?";
+      UPDATE_VALUE = "update JCR_MVALUE set DATA=?, STORAGE_DESC=? where PROPERTY_ID=? and ORDER_NUM=?";
    }
 
    /**
@@ -628,6 +633,55 @@
       return findItemQPathByIdentifierCQ.executeQuery();
    }
 
+   protected int deleteValueDataByOrderNum(String id, int orderNum) throws SQLException
+   {
+      if (deleteValueDataByOrderNum == null)
+         deleteValueDataByOrderNum = dbConnection.prepareStatement(DELETE_VALUE_BY_ORDER_NUM);
+      else
+         deleteValueDataByOrderNum.clearParameters();
+
+      deleteValueDataByOrderNum.setString(1, id);
+      deleteValueDataByOrderNum.setInt(2, orderNum);
+      return deleteValueDataByOrderNum.executeUpdate();
+   }
+
+   protected ResultSet findPropertyById(String id) throws SQLException
+   {
+      if (findPropertyById == null)
+         findPropertyById = dbConnection.prepareStatement(FIND_PROPERTY_BY_ID);
+      else
+         findPropertyById.clearParameters();
+
+      findPropertyById.setString(1, id);
+      return findPropertyById.executeQuery();
+   }
+
+   protected int updateValueData(String cid, int orderNumber, InputStream stream, int streamLength, String storageDesc)
+      throws SQLException
+   {
+
+      if (updateValue == null)
+         updateValue = dbConnection.prepareStatement(UPDATE_VALUE);
+      else
+         updateValue.clearParameters();
+
+      if (stream == null)
+      {
+         // [PN] store vd reference to external storage etc.
+         updateValue.setNull(1, Types.BINARY);
+         updateValue.setString(2, storageDesc);
+      }
+      else
+      {
+         updateValue.setBinaryStream(1, stream, streamLength);
+         updateValue.setNull(2, Types.VARCHAR);
+      }
+
+      updateValue.setString(3, cid);
+      updateValue.setInt(4, orderNumber);
+      return updateValue.executeUpdate();
+   }
+
    /**
     * {@inheritDoc}
     */

Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/SingleDbJDBCConnection.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/SingleDbJDBCConnection.java	2011-04-26 13:20:25 UTC (rev 4306)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/storage/jdbc/optimisation/db/SingleDbJDBCConnection.java	2011-04-27 07:54:11 UTC (rev 4307)
@@ -196,6 +196,11 @@
             + " join (select I.ID, I.PARENT_ID, I.NAME, I.VERSION, I.I_INDEX, I.N_ORDER_NUM from JCR_SITEM I"
             + " where I.CONTAINER_NAME=? AND I.I_CLASS=1 AND I.ID > ? order by I.ID LIMIT ? OFFSET ?) J on P.PARENT_ID = J.ID"
             + " where P.I_CLASS=2 and P.CONTAINER_NAME=? and V.PROPERTY_ID=P.ID  order by J.ID";
+
+      FIND_PROPERTY_BY_ID =
+         "select I.P_TYPE, V.STORAGE_DESC from JCR_SITEM I, JCR_SVALUE V where I.CONTAINER_NAME=? and I.ID = ? and V.PROPERTY_ID = I.ID";
+      DELETE_VALUE_BY_ORDER_NUM = "delete from JCR_SVALUE where PROPERTY_ID=? and ORDER_NUM >= ?";
+      UPDATE_VALUE = "update JCR_SVALUE set DATA=?, STORAGE_DESC=? where PROPERTY_ID=? and ORDER_NUM=?";
    }
 
    /**
@@ -673,4 +678,57 @@
 
       return findNodesAndProperties.executeQuery();
    }
+    
+   @Override
+   protected int deleteValueDataByOrderNum(String id, int orderNum) throws SQLException
+   {
+      if (deleteValueDataByOrderNum == null)
+         deleteValueDataByOrderNum = dbConnection.prepareStatement(DELETE_VALUE_BY_ORDER_NUM);
+      else
+         deleteValueDataByOrderNum.clearParameters();
+
+      deleteValueDataByOrderNum.setString(1, id);
+      deleteValueDataByOrderNum.setInt(2, orderNum);
+      return deleteValueDataByOrderNum.executeUpdate();
+   }
+   
+   @Override
+   protected ResultSet findPropertyById(String id) throws SQLException
+   {
+      if (findPropertyById == null)
+         findPropertyById = dbConnection.prepareStatement(FIND_PROPERTY_BY_ID);
+      else
+         findPropertyById.clearParameters();
+
+      findPropertyById.setString(1, containerName);
+      findPropertyById.setString(2, id);
+      return findPropertyById.executeQuery();
+   }
+   
+   @Override
+   protected int updateValueData(String cid, int orderNumber, InputStream stream, int streamLength, String storageDesc)
+      throws SQLException
+   {
+
+      if (updateValue == null)
+         updateValue = dbConnection.prepareStatement(UPDATE_VALUE);
+      else
+         updateValue.clearParameters();
+
+      if (stream == null)
+      {
+         // [PN] store vd reference to external storage etc.
+         updateValue.setNull(1, Types.BINARY);
+         updateValue.setString(2, storageDesc);
+      }
+      else
+      {
+         updateValue.setBinaryStream(1, stream, streamLength);
+         updateValue.setNull(2, Types.VARCHAR);
+      }
+
+      updateValue.setString(3, cid);
+      updateValue.setInt(4, orderNumber);
+      return updateValue.executeUpdate();
+   }  
 }



More information about the exo-jcr-commits mailing list