Search in sources :

Example 6 with Operation

use of org.apache.jackrabbit.oak.plugins.document.UpdateOp.Operation in project jackrabbit-oak by apache.

the class RDBDocumentSerializer method asString.

/**
     * Serializes the changes in the {@link UpdateOp} into a JSON array; each
     * entry is another JSON array holding operation, key, revision, and value.
     */
public String asString(UpdateOp update) {
    StringBuilder sb = new StringBuilder("[");
    boolean needComma = false;
    for (Map.Entry<Key, Operation> change : update.getChanges().entrySet()) {
        Operation op = change.getValue();
        Key key = change.getKey();
        // exclude properties that are serialized into special columns
        if (columnProperties.contains(key.getName()) && null == key.getRevision())
            continue;
        if (needComma) {
            sb.append(",");
        }
        sb.append("[");
        if (op.type == UpdateOp.Operation.Type.INCREMENT) {
            sb.append("\"+\",");
        } else if (op.type == UpdateOp.Operation.Type.SET || op.type == UpdateOp.Operation.Type.SET_MAP_ENTRY) {
            sb.append("\"=\",");
        } else if (op.type == UpdateOp.Operation.Type.MAX) {
            sb.append("\"M\",");
        } else if (op.type == UpdateOp.Operation.Type.REMOVE || op.type == UpdateOp.Operation.Type.REMOVE_MAP_ENTRY) {
            sb.append("\"*\",");
        } else {
            throw new DocumentStoreException("Can't serialize " + update.toString() + " for JSON append");
        }
        appendJsonString(sb, key.getName());
        sb.append(",");
        Revision rev = key.getRevision();
        if (rev != null) {
            appendJsonString(sb, rev.toString());
            sb.append(",");
        }
        appendJsonValue(sb, op.value);
        sb.append("]");
        needComma = true;
    }
    return sb.append("]").toString();
}
Also used : DocumentStoreException(org.apache.jackrabbit.oak.plugins.document.DocumentStoreException) Revision(org.apache.jackrabbit.oak.plugins.document.Revision) Operation(org.apache.jackrabbit.oak.plugins.document.UpdateOp.Operation) Map(java.util.Map) TreeMap(java.util.TreeMap) Key(org.apache.jackrabbit.oak.plugins.document.UpdateOp.Key)

Example 7 with Operation

use of org.apache.jackrabbit.oak.plugins.document.UpdateOp.Operation in project jackrabbit-oak by apache.

the class RDBDocumentStore method updateDocument.

private <T extends Document> boolean updateDocument(@Nonnull Collection<T> collection, @Nonnull T document, @Nonnull UpdateOp update, Long oldmodcount) {
    Connection connection = null;
    RDBTableMetaData tmd = getTable(collection);
    String data = null;
    try {
        connection = this.ch.getRWConnection();
        Number hasBinary = (Number) document.get(NodeDocument.HAS_BINARY_FLAG);
        Boolean deletedOnce = (Boolean) document.get(NodeDocument.DELETED_ONCE);
        Long modcount = (Long) document.get(MODCOUNT);
        Long cmodcount = (Long) document.get(COLLISIONSMODCOUNT);
        boolean success = false;
        boolean shouldRetry = true;
        // every 16th update is a full rewrite
        if (isAppendableUpdate(update, false) && modcount % 16 != 0) {
            String appendData = ser.asString(update);
            if (appendData.length() < tmd.getDataLimitInOctets() / CHAR2OCTETRATIO) {
                try {
                    Operation modOperation = update.getChanges().get(MODIFIEDKEY);
                    long modified = getModifiedFromOperation(modOperation);
                    boolean modifiedIsConditional = modOperation == null || modOperation.type != UpdateOp.Operation.Type.SET;
                    success = db.appendingUpdate(connection, tmd, document.getId(), modified, modifiedIsConditional, hasBinary, deletedOnce, modcount, cmodcount, oldmodcount, appendData);
                    // if we get here, a retry is not going to help (the SQL
                    // operation succeeded but simply did not select a row
                    // that could be updated, likely because of the check on
                    // MODCOUNT
                    shouldRetry = false;
                    connection.commit();
                } catch (SQLException ex) {
                    continueIfStringOverflow(ex);
                    this.ch.rollbackConnection(connection);
                    success = false;
                }
            }
        }
        if (!success && shouldRetry) {
            data = ser.asString(document);
            Object m = document.get(MODIFIED);
            long modified = (m instanceof Long) ? ((Long) m).longValue() : 0;
            success = db.update(connection, tmd, document.getId(), modified, hasBinary, deletedOnce, modcount, cmodcount, oldmodcount, data);
            connection.commit();
        }
        return success;
    } catch (SQLException ex) {
        this.ch.rollbackConnection(connection);
        String addDiags = "";
        if (RDBJDBCTools.matchesSQLState(ex, "22", "72")) {
            byte[] bytes = asBytes(data);
            addDiags = String.format(" (DATA size in Java characters: %d, in octets: %d, computed character limit: %d)", data.length(), bytes.length, tmd.getDataLimitInOctets() / CHAR2OCTETRATIO);
        }
        String message = String.format("Update for %s failed%s", document.getId(), addDiags);
        LOG.debug(message, ex);
        throw handleException(message, ex, collection, document.getId());
    } finally {
        this.ch.closeConnection(connection);
    }
}
Also used : SQLException(java.sql.SQLException) Connection(java.sql.Connection) Operation(org.apache.jackrabbit.oak.plugins.document.UpdateOp.Operation)

Example 8 with Operation

use of org.apache.jackrabbit.oak.plugins.document.UpdateOp.Operation in project jackrabbit-oak by apache.

the class MongoDocumentStore method createUpdate.

/**
     * Creates a MongoDB update object from the given UpdateOp.
     *
     * @param updateOp the update op.
     * @param includeId whether to include the SET id operation
     * @return the DBObject.
     */
@Nonnull
private static DBObject createUpdate(UpdateOp updateOp, boolean includeId) {
    BasicDBObject setUpdates = new BasicDBObject();
    BasicDBObject maxUpdates = new BasicDBObject();
    BasicDBObject incUpdates = new BasicDBObject();
    BasicDBObject unsetUpdates = new BasicDBObject();
    // always increment modCount
    updateOp.increment(Document.MOD_COUNT, 1);
    if (includeId) {
        setUpdates.append(Document.ID, updateOp.getId());
    }
    // other updates
    for (Entry<Key, Operation> entry : updateOp.getChanges().entrySet()) {
        Key k = entry.getKey();
        Operation op = entry.getValue();
        switch(op.type) {
            case SET:
            case SET_MAP_ENTRY:
                {
                    setUpdates.append(k.toString(), op.value);
                    break;
                }
            case MAX:
                {
                    maxUpdates.append(k.toString(), op.value);
                    break;
                }
            case INCREMENT:
                {
                    incUpdates.append(k.toString(), op.value);
                    break;
                }
            case REMOVE:
            case REMOVE_MAP_ENTRY:
                {
                    unsetUpdates.append(k.toString(), "1");
                    break;
                }
        }
    }
    BasicDBObject update = new BasicDBObject();
    if (!setUpdates.isEmpty()) {
        update.append("$set", setUpdates);
    }
    if (!maxUpdates.isEmpty()) {
        update.append("$max", maxUpdates);
    }
    if (!incUpdates.isEmpty()) {
        update.append("$inc", incUpdates);
    }
    if (!unsetUpdates.isEmpty()) {
        update.append("$unset", unsetUpdates);
    }
    return update;
}
Also used : BasicDBObject(com.mongodb.BasicDBObject) BulkWriteOperation(com.mongodb.BulkWriteOperation) Operation(org.apache.jackrabbit.oak.plugins.document.UpdateOp.Operation) Key(org.apache.jackrabbit.oak.plugins.document.UpdateOp.Key) Nonnull(javax.annotation.Nonnull)

Example 9 with Operation

use of org.apache.jackrabbit.oak.plugins.document.UpdateOp.Operation in project jackrabbit-oak by apache.

the class MongoDocumentStore method create.

@Override
public <T extends Document> boolean create(Collection<T> collection, List<UpdateOp> updateOps) {
    log("create", updateOps);
    List<T> docs = new ArrayList<T>();
    DBObject[] inserts = new DBObject[updateOps.size()];
    List<String> ids = Lists.newArrayListWithCapacity(updateOps.size());
    for (int i = 0; i < updateOps.size(); i++) {
        inserts[i] = new BasicDBObject();
        UpdateOp update = updateOps.get(i);
        inserts[i].put(Document.ID, update.getId());
        UpdateUtils.assertUnconditional(update);
        T target = collection.newDocument(this);
        UpdateUtils.applyChanges(target, update);
        docs.add(target);
        ids.add(updateOps.get(i).getId());
        for (Entry<Key, Operation> entry : update.getChanges().entrySet()) {
            Key k = entry.getKey();
            Operation op = entry.getValue();
            switch(op.type) {
                case SET:
                case MAX:
                case INCREMENT:
                    {
                        inserts[i].put(k.toString(), op.value);
                        break;
                    }
                case SET_MAP_ENTRY:
                    {
                        Revision r = k.getRevision();
                        if (r == null) {
                            throw new IllegalStateException("SET_MAP_ENTRY must not have null revision");
                        }
                        DBObject value = (DBObject) inserts[i].get(k.getName());
                        if (value == null) {
                            value = new RevisionEntry(r, op.value);
                            inserts[i].put(k.getName(), value);
                        } else if (value.keySet().size() == 1) {
                            String key = value.keySet().iterator().next();
                            Object val = value.get(key);
                            value = new BasicDBObject(key, val);
                            value.put(r.toString(), op.value);
                            inserts[i].put(k.getName(), value);
                        } else {
                            value.put(r.toString(), op.value);
                        }
                        break;
                    }
                case REMOVE:
                case REMOVE_MAP_ENTRY:
                    // nothing to do for new entries
                    break;
            }
        }
        if (!inserts[i].containsField(Document.MOD_COUNT)) {
            inserts[i].put(Document.MOD_COUNT, 1L);
            target.put(Document.MOD_COUNT, 1L);
        }
    }
    DBCollection dbCollection = getDBCollection(collection);
    final Stopwatch watch = startWatch();
    boolean insertSuccess = false;
    try {
        try {
            dbCollection.insert(inserts);
            if (collection == Collection.NODES) {
                for (T doc : docs) {
                    nodesCache.putIfAbsent((NodeDocument) doc);
                    updateLocalChanges((NodeDocument) doc);
                }
            }
            insertSuccess = true;
            return true;
        } catch (MongoException e) {
            return false;
        }
    } finally {
        stats.doneCreate(watch.elapsed(TimeUnit.NANOSECONDS), collection, ids, insertSuccess);
    }
}
Also used : MongoException(com.mongodb.MongoException) UpdateOp(org.apache.jackrabbit.oak.plugins.document.UpdateOp) ArrayList(java.util.ArrayList) Stopwatch(com.google.common.base.Stopwatch) BulkWriteOperation(com.mongodb.BulkWriteOperation) Operation(org.apache.jackrabbit.oak.plugins.document.UpdateOp.Operation) DBObject(com.mongodb.DBObject) BasicDBObject(com.mongodb.BasicDBObject) BasicDBObject(com.mongodb.BasicDBObject) DBCollection(com.mongodb.DBCollection) Revision(org.apache.jackrabbit.oak.plugins.document.Revision) DBObject(com.mongodb.DBObject) BasicDBObject(com.mongodb.BasicDBObject) Key(org.apache.jackrabbit.oak.plugins.document.UpdateOp.Key)

Example 10 with Operation

use of org.apache.jackrabbit.oak.plugins.document.UpdateOp.Operation in project jackrabbit-oak by apache.

the class CommitRootUpdateTest method exceptionOnUpdate.

@Test
public void exceptionOnUpdate() throws Exception {
    final AtomicBoolean throwAfterUpdate = new AtomicBoolean(false);
    MemoryDocumentStore store = new MemoryDocumentStore() {

        @Override
        public <T extends Document> T findAndUpdate(Collection<T> collection, UpdateOp update) {
            T doc = super.findAndUpdate(collection, update);
            if (isFinalCommitRootUpdate(update) && throwAfterUpdate.compareAndSet(true, false)) {
                throw new RuntimeException("communication failure");
            }
            return doc;
        }

        private boolean isFinalCommitRootUpdate(UpdateOp update) {
            boolean finalUpdate = true;
            for (Map.Entry<Key, Operation> op : update.getChanges().entrySet()) {
                String name = op.getKey().getName();
                if (NodeDocument.isRevisionsEntry(name) || NodeDocument.MODIFIED_IN_SECS.equals(name)) {
                    continue;
                }
                finalUpdate = false;
                break;
            }
            return finalUpdate;
        }
    };
    DocumentNodeStore ns = builderProvider.newBuilder().setDocumentStore(store).setAsyncDelay(0).getNodeStore();
    NodeBuilder b = ns.getRoot().builder();
    b.child("foo");
    b.child("bar");
    merge(ns, b);
    throwAfterUpdate.set(true);
    boolean success = false;
    Commit c = ns.newCommit(ns.getHeadRevision(), null);
    try {
        c.addNode(new DocumentNodeState(ns, "/foo/node", c.getBaseRevision()));
        c.addNode(new DocumentNodeState(ns, "/bar/node", c.getBaseRevision()));
        c.apply();
        success = true;
    } finally {
        if (success) {
            ns.done(c, false, CommitInfo.EMPTY);
        } else {
            ns.canceled(c);
        }
    }
    NodeState root = ns.getRoot();
    assertTrue(root.getChildNode("foo").getChildNode("node").exists());
    assertTrue(root.getChildNode("bar").getChildNode("node").exists());
    assertFalse(throwAfterUpdate.get());
}
Also used : NodeState(org.apache.jackrabbit.oak.spi.state.NodeState) MemoryDocumentStore(org.apache.jackrabbit.oak.plugins.document.memory.MemoryDocumentStore) Operation(org.apache.jackrabbit.oak.plugins.document.UpdateOp.Operation) NodeBuilder(org.apache.jackrabbit.oak.spi.state.NodeBuilder) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Map(java.util.Map) Key(org.apache.jackrabbit.oak.plugins.document.UpdateOp.Key) Test(org.junit.Test)

Aggregations

Operation (org.apache.jackrabbit.oak.plugins.document.UpdateOp.Operation)14 Key (org.apache.jackrabbit.oak.plugins.document.UpdateOp.Key)12 Map (java.util.Map)7 Test (org.junit.Test)6 MemoryDocumentStore (org.apache.jackrabbit.oak.plugins.document.memory.MemoryDocumentStore)4 NodeBuilder (org.apache.jackrabbit.oak.spi.state.NodeBuilder)4 TreeMap (java.util.TreeMap)3 Stopwatch (com.google.common.base.Stopwatch)2 BasicDBObject (com.mongodb.BasicDBObject)2 BulkWriteOperation (com.mongodb.BulkWriteOperation)2 Connection (java.sql.Connection)2 SQLException (java.sql.SQLException)2 SortedMap (java.util.SortedMap)2 Nonnull (javax.annotation.Nonnull)2 CommitFailedException (org.apache.jackrabbit.oak.api.CommitFailedException)2 Revision (org.apache.jackrabbit.oak.plugins.document.Revision)2 UpdateOp (org.apache.jackrabbit.oak.plugins.document.UpdateOp)2 NodeState (org.apache.jackrabbit.oak.spi.state.NodeState)2 DBCollection (com.mongodb.DBCollection)1 DBObject (com.mongodb.DBObject)1