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)));
+ }
}