You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by mr...@apache.org on 2015/04/23 10:29:58 UTC

svn commit: r1675555 - in /jackrabbit/oak/trunk/oak-core/src: main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStore.java test/java/org/apache/jackrabbit/oak/plugins/document/BasicDocumentStoreTest.java

Author: mreutegg
Date: Thu Apr 23 08:29:58 2015
New Revision: 1675555

URL: http://svn.apache.org/r1675555
Log:
OAK-2804: Conditional remove on DocumentStore

RDBDocumentStore now supports conditions on remove, but limited to _modified field

Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStore.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/BasicDocumentStoreTest.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStore.java?rev=1675555&r1=1675554&r2=1675555&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStore.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStore.java Thu Apr 23 08:29:58 2015
@@ -36,6 +36,7 @@ import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -75,6 +76,7 @@ import com.google.common.base.Objects;
 import com.google.common.cache.Cache;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
 import com.google.common.util.concurrent.Striped;
 
 /**
@@ -1171,8 +1173,28 @@ public class RDBDocumentStore implements
 
     private <T extends Document> int delete(Collection<T> collection,
                                             Map<String, Map<Key, Condition>> toRemove) {
-        // TODO: implement
-        throw new UnsupportedOperationException("not yet implemented");
+        int numDeleted = 0;
+        String tableName = getTable(collection);
+        Map<String, Map<Key, Condition>> subMap = Maps.newHashMap();
+        Iterator<Entry<String, Map<Key, Condition>>> it = toRemove.entrySet().iterator();
+        while (it.hasNext()) {
+            Entry<String, Map<Key, Condition>> entry = it.next();
+            subMap.put(entry.getKey(), entry.getValue());
+            if (subMap.size() == 64 || !it.hasNext()) {
+                Connection connection = null;
+                try {
+                    connection = this.ch.getRWConnection();
+                    numDeleted += dbDelete(connection, tableName, subMap);
+                    connection.commit();
+                } catch (Exception ex) {
+                    throw DocumentStoreException.convert(ex);
+                } finally {
+                    this.ch.closeConnection(connection);
+                }
+                subMap.clear();
+            }
+        }
+        return numDeleted;
     }
 
     private <T extends Document> boolean updateDocument(@Nonnull Collection<T> collection, @Nonnull T document,
@@ -1656,6 +1678,51 @@ public class RDBDocumentStore implements
         } finally {
             stmt.close();
         }
+    }
+
+    private int dbDelete(Connection connection, String tableName,
+                         Map<String, Map<Key, Condition>> toDelete)
+            throws SQLException, DocumentStoreException {
+        String or = "";
+        StringBuilder whereClause = new StringBuilder();
+        for (Entry<String, Map<Key, Condition>> entry : toDelete.entrySet()) {
+            whereClause.append(or);
+            or = " or ";
+            whereClause.append("ID=?");
+            for (Entry<Key, Condition> c : entry.getValue().entrySet()) {
+                if (!c.getKey().getName().equals(MODIFIED)) {
+                    throw new DocumentStoreException(
+                            "Unsupported condition: " + c);
+                }
+                whereClause.append(" and MODIFIED");
+                if (c.getValue().type == Condition.Type.EQUALS
+                        && c.getValue().value instanceof Long) {
+                    whereClause.append("=?");
+                } else if (c.getValue().type == Condition.Type.EXISTS) {
+                    whereClause.append(" is not null");
+                } else {
+                    throw new DocumentStoreException(
+                            "Unsupported condition: " + c);
+                }
+            }
+        }
+
+        PreparedStatement stmt= connection.prepareStatement(
+                "delete from " + tableName + " where " + whereClause);
+        try {
+            int i = 1;
+            for (Entry<String, Map<Key, Condition>> entry : toDelete.entrySet()) {
+                setIdInStatement(stmt, i++, entry.getKey());
+                for (Entry<Key, Condition> c : entry.getValue().entrySet()) {
+                    if (c.getValue().type == Condition.Type.EQUALS) {
+                        stmt.setLong(i++, (Long) c.getValue().value);
+                    }
+                }
+            }
+            return stmt.executeUpdate();
+        } finally {
+            stmt.close();
+        }
     }
 
     @Override

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/BasicDocumentStoreTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/BasicDocumentStoreTest.java?rev=1675555&r1=1675554&r2=1675555&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/BasicDocumentStoreTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/BasicDocumentStoreTest.java Thu Apr 23 08:29:58 2015
@@ -37,6 +37,12 @@ import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
 
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+import org.apache.jackrabbit.oak.plugins.document.UpdateOp.Condition;
+import org.apache.jackrabbit.oak.plugins.document.UpdateOp.Key;
+import org.apache.jackrabbit.oak.plugins.document.util.Utils;
 import org.junit.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -428,8 +434,7 @@ public class BasicDocumentStoreTest exte
             cnt += 1;
         }
 
-        LOG.info("document creation with property of size " + size + " and batch size " + amount + " for " + super.dsname + " was "
-                + cnt + " in " + duration + "ms (" + (cnt / (duration / 1000f)) + "/s)");
+        LOG.info("document creation with property of size " + size + " and batch size " + amount + " for " + super.dsname + " was " + cnt + " in " + duration + "ms (" + (cnt / (duration / 1000f)) + "/s)");
     }
 
     @Test
@@ -644,8 +649,7 @@ public class BasicDocumentStoreTest exte
             assertTrue(m.keySet().equals(expectedRevs));
         }
 
-        LOG.info("document updates with property of size " + size + (growing ? " (growing)" : "") + " for " + super.dsname
-                + " was " + cnt + " in " + duration + "ms (" + (cnt / (duration / 1000f)) + "/s)");
+        LOG.info("document updates with property of size " + size + (growing ? " (growing)" : "") + " for " + super.dsname + " was " + cnt + " in " + duration + "ms (" + (cnt / (duration / 1000f)) + "/s)");
     }
 
     private static String generateString(int length, boolean ascii) {
@@ -983,4 +987,53 @@ public class BasicDocumentStoreTest exte
         Map<String, String> desc = ds.getMetadata();
         assertNotNull(desc.get("type"));
     }
+
+    @Test
+    public void removeWithCondition() throws Exception {
+        List<UpdateOp> docs = Lists.newArrayList();
+        docs.add(newDocument("/foo", 100));
+        removeMe.add(Utils.getIdFromPath("/foo"));
+        docs.add(newDocument("/bar", 200));
+        removeMe.add(Utils.getIdFromPath("/bar"));
+        docs.add(newDocument("/baz", 300));
+        removeMe.add(Utils.getIdFromPath("/baz"));
+        ds.create(Collection.NODES, docs);
+
+        for (UpdateOp op : docs) {
+            assertNotNull(ds.find(Collection.NODES, op.getId()));
+        }
+
+        Map<String, Map<Key, Condition>> toRemove = Maps.newHashMap();
+        removeDocument(toRemove, "/foo", 100); // matches
+        removeDocument(toRemove, "/bar", 300); // modified differs
+        removeDocument(toRemove, "/qux", 100); // does not exist
+        removeDocument(toRemove, "/baz", 300); // matches
+
+        int removed = ds.remove(Collection.NODES, toRemove);
+
+        assertEquals(2, removed);
+        assertNotNull(ds.find(Collection.NODES, Utils.getIdFromPath("/bar")));
+        for (NodeDocument doc : Utils.getAllDocuments(ds)) {
+            if (!doc.getPath().equals("/bar")) {
+                fail("document must not exist: " + doc.getId());
+            }
+        }
+    }
+
+    private UpdateOp newDocument(String path, long modified) {
+        String id = Utils.getIdFromPath(path);
+        UpdateOp op = new UpdateOp(id, true);
+        op.set(NodeDocument.MODIFIED_IN_SECS, modified);
+        op.set(Document.ID, id);
+        return op;
+    }
+
+    private void removeDocument(Map<String, Map<Key, Condition>> toRemove,
+                                String path,
+                                long modified) {
+        toRemove.put(Utils.getIdFromPath(path),
+                Collections.singletonMap(
+                        new Key(NodeDocument.MODIFIED_IN_SECS, null),
+                        Condition.newEqualsCondition(modified)));
+    }
 }