use of javax.annotation.CheckForNull in project jackrabbit-oak by apache.
the class RDBDocumentStore method internalCreate.
@CheckForNull
private <T extends Document> boolean internalCreate(Collection<T> collection, List<UpdateOp> updates) {
final Stopwatch watch = startWatch();
List<String> ids = new ArrayList<String>(updates.size());
boolean success = true;
try {
// try up to CHUNKSIZE ops in one transaction
for (List<UpdateOp> chunks : Lists.partition(updates, CHUNKSIZE)) {
List<T> docs = new ArrayList<T>();
for (UpdateOp update : chunks) {
ids.add(update.getId());
maintainUpdateStats(collection, update.getId());
UpdateUtils.assertUnconditional(update);
T doc = collection.newDocument(this);
addUpdateCounters(update);
UpdateUtils.applyChanges(doc, update);
if (!update.getId().equals(doc.getId())) {
throw new DocumentStoreException("ID mismatch - UpdateOp: " + update.getId() + ", ID property: " + doc.getId());
}
docs.add(doc);
}
boolean done = insertDocuments(collection, docs);
if (done) {
if (collection == Collection.NODES) {
for (T doc : docs) {
nodesCache.putIfAbsent((NodeDocument) doc);
}
}
} else {
success = false;
}
}
return success;
} catch (DocumentStoreException ex) {
return false;
} finally {
stats.doneCreate(watch.elapsed(TimeUnit.NANOSECONDS), collection, ids, success);
}
}
use of javax.annotation.CheckForNull in project jackrabbit-oak by apache.
the class RDBDocumentStore method readDocumentUncached.
@CheckForNull
private <T extends Document> T readDocumentUncached(Collection<T> collection, String id, NodeDocument cachedDoc) {
Connection connection = null;
RDBTableMetaData tmd = getTable(collection);
final Stopwatch watch = startWatch();
boolean docFound = true;
try {
long lastmodcount = -1, lastmodified = -1;
if (cachedDoc != null) {
lastmodcount = modcountOf(cachedDoc);
lastmodified = modifiedOf(cachedDoc);
}
connection = this.ch.getROConnection();
RDBRow row = db.read(connection, tmd, id, lastmodcount, lastmodified);
connection.commit();
if (row == null) {
docFound = false;
return null;
} else {
if (lastmodcount == row.getModcount() && lastmodified == row.getModified() && lastmodified >= 1) {
// we can re-use the cached document
cachedDoc.markUpToDate(System.currentTimeMillis());
return castAsT(cachedDoc);
} else {
return convertFromDBObject(collection, row);
}
}
} catch (Exception ex) {
throw new DocumentStoreException(ex);
} finally {
this.ch.closeConnection(connection);
stats.doneFindUncached(watch.elapsed(TimeUnit.NANOSECONDS), collection, id, docFound, false);
}
}
use of javax.annotation.CheckForNull in project jackrabbit-oak by apache.
the class RDBDocumentStoreJDBC method read.
@CheckForNull
public RDBRow read(Connection connection, RDBTableMetaData tmd, String id, long lastmodcount, long lastmodified) throws SQLException {
boolean useCaseStatement = lastmodcount != -1 && lastmodified >= 1;
StringBuffer sql = new StringBuffer();
sql.append("select MODIFIED, MODCOUNT, CMODCOUNT, HASBINARY, DELETEDONCE, ");
if (useCaseStatement) {
// the case statement causes the actual row data not to be
// sent in case we already have it
sql.append("case when (MODCOUNT = ? and MODIFIED = ?) then null else DATA end as DATA, ");
sql.append("case when (MODCOUNT = ? and MODIFIED = ?) then null else BDATA end as BDATA ");
} else {
// either we don't have a previous version of the document
// or the database does not support CASE in SELECT
sql.append("DATA, BDATA ");
}
sql.append("from " + tmd.getName() + " where ID = ?");
PreparedStatement stmt = connection.prepareStatement(sql.toString());
ResultSet rs = null;
try {
int si = 1;
if (useCaseStatement) {
stmt.setLong(si++, lastmodcount);
stmt.setLong(si++, lastmodified);
stmt.setLong(si++, lastmodcount);
stmt.setLong(si++, lastmodified);
}
setIdInStatement(tmd, stmt, si, id);
rs = stmt.executeQuery();
if (rs.next()) {
long modified = readLongFromResultSet(rs, 1);
long modcount = readLongFromResultSet(rs, 2);
long cmodcount = readLongFromResultSet(rs, 3);
Long hasBinary = readLongOrNullFromResultSet(rs, 4);
Boolean deletedOnce = readBooleanOrNullFromResultSet(rs, 5);
String data = rs.getString(6);
byte[] bdata = rs.getBytes(7);
return new RDBRow(id, hasBinary, deletedOnce, modified, modcount, cmodcount, data, bdata);
} else {
return null;
}
} catch (SQLException ex) {
LOG.debug("attempting to read " + id + " (id length is " + id.length() + ")", ex);
// gracefully
if ("22001".equals(ex.getSQLState())) {
try {
connection.rollback();
} catch (SQLException ex2) {
LOG.debug("failed to rollback", ex2);
}
return null;
} else {
throw (ex);
}
} finally {
closeResultSet(rs);
closeStatement(stmt);
}
}
use of javax.annotation.CheckForNull in project jackrabbit-oak by apache.
the class MongoDocumentStore method createOrUpdate.
/**
* Try to apply all the {@link UpdateOp}s with at least MongoDB requests as
* possible. The return value is the list of the old documents (before
* applying changes). The mechanism is as follows:
*
* <ol>
* <li>For each UpdateOp try to read the assigned document from the cache.
* Add them to {@code oldDocs}.</li>
* <li>Prepare a list of all UpdateOps that doesn't have their documents and
* read them in one find() call. Add results to {@code oldDocs}.</li>
* <li>Prepare a bulk update. For each remaining UpdateOp add following
* operation:
* <ul>
* <li>Find document with the same id and the same mod_count as in the
* {@code oldDocs}.</li>
* <li>Apply changes from the UpdateOps.</li>
* </ul>
* </li>
* <li>Execute the bulk update.</li>
* </ol>
*
* If some other process modifies the target documents between points 2 and
* 3, the mod_count will be increased as well and the bulk update will fail
* for the concurrently modified docs. The method will then remove the
* failed documents from the {@code oldDocs} and restart the process from
* point 2. It will stop after 3rd iteration.
*/
@SuppressWarnings("unchecked")
@CheckForNull
@Override
public <T extends Document> List<T> createOrUpdate(Collection<T> collection, List<UpdateOp> updateOps) {
log("createOrUpdate", updateOps);
Map<String, UpdateOp> operationsToCover = new LinkedHashMap<String, UpdateOp>();
List<UpdateOp> duplicates = new ArrayList<UpdateOp>();
Map<UpdateOp, T> results = new LinkedHashMap<UpdateOp, T>();
final Stopwatch watch = startWatch();
try {
for (UpdateOp updateOp : updateOps) {
UpdateUtils.assertUnconditional(updateOp);
UpdateOp clone = updateOp.copy();
if (operationsToCover.containsKey(updateOp.getId())) {
duplicates.add(clone);
} else {
operationsToCover.put(updateOp.getId(), clone);
}
results.put(clone, null);
}
Map<String, T> oldDocs = new HashMap<String, T>();
if (collection == Collection.NODES) {
oldDocs.putAll((Map<String, T>) getCachedNodes(operationsToCover.keySet()));
}
for (int i = 0; i <= bulkRetries; i++) {
if (operationsToCover.size() <= 2) {
// in bulk mode wouldn't result in any performance gain
break;
}
for (List<UpdateOp> partition : Lists.partition(Lists.newArrayList(operationsToCover.values()), bulkSize)) {
Map<UpdateOp, T> successfulUpdates = bulkUpdate(collection, partition, oldDocs);
results.putAll(successfulUpdates);
operationsToCover.values().removeAll(successfulUpdates.keySet());
}
}
// if there are some changes left, we'll apply them one after another
Iterator<UpdateOp> it = Iterators.concat(operationsToCover.values().iterator(), duplicates.iterator());
while (it.hasNext()) {
UpdateOp op = it.next();
it.remove();
T oldDoc = createOrUpdate(collection, op);
if (oldDoc != null) {
results.put(op, oldDoc);
}
}
} catch (MongoException e) {
throw handleException(e, collection, Iterables.transform(updateOps, new Function<UpdateOp, String>() {
@Override
public String apply(UpdateOp input) {
return input.getId();
}
}));
} finally {
stats.doneCreateOrUpdate(watch.elapsed(TimeUnit.NANOSECONDS), collection, Lists.transform(updateOps, new Function<UpdateOp, String>() {
@Override
public String apply(UpdateOp input) {
return input.getId();
}
}));
}
List<T> resultList = new ArrayList<T>(results.values());
log("createOrUpdate returns", resultList);
return resultList;
}
use of javax.annotation.CheckForNull in project jackrabbit-oak by apache.
the class RDBDocumentStore method internalUpdate.
@CheckForNull
private <T extends Document> void internalUpdate(Collection<T> collection, List<String> ids, UpdateOp update) {
if (isAppendableUpdate(update, true) && !requiresPreviousState(update)) {
Operation modOperation = update.getChanges().get(MODIFIEDKEY);
long modified = getModifiedFromOperation(modOperation);
boolean modifiedIsConditional = modOperation == null || modOperation.type != UpdateOp.Operation.Type.SET;
String appendData = ser.asString(update);
for (List<String> chunkedIds : Lists.partition(ids, CHUNKSIZE)) {
if (collection == Collection.NODES) {
for (String key : chunkedIds) {
nodesCache.invalidate(key);
}
}
Connection connection = null;
RDBTableMetaData tmd = getTable(collection);
boolean success = false;
try {
Stopwatch watch = startWatch();
connection = this.ch.getRWConnection();
success = db.batchedAppendingUpdate(connection, tmd, chunkedIds, modified, modifiedIsConditional, appendData);
connection.commit();
//Internally 'db' would make multiple calls and number of those
//remote calls would not be captured
stats.doneUpdate(watch.elapsed(TimeUnit.NANOSECONDS), collection, chunkedIds.size());
} catch (SQLException ex) {
success = false;
this.ch.rollbackConnection(connection);
} finally {
this.ch.closeConnection(connection);
}
if (success) {
if (collection == Collection.NODES) {
for (String id : chunkedIds) {
nodesCache.invalidate(id);
}
}
} else {
for (String id : chunkedIds) {
UpdateOp up = update.copy();
up = up.shallowCopy(id);
internalCreateOrUpdate(collection, up, false, true);
}
}
}
} else {
Stopwatch watch = startWatch();
for (String id : ids) {
UpdateOp up = update.copy();
up = up.shallowCopy(id);
internalCreateOrUpdate(collection, up, false, true);
}
stats.doneUpdate(watch.elapsed(TimeUnit.NANOSECONDS), collection, ids.size());
}
}
Aggregations