use of org.apache.jackrabbit.oak.plugins.document.cache.ModificationStamp in project jackrabbit-oak by apache.
the class RDBDocumentStore method internalQuery.
private <T extends Document> List<T> internalQuery(Collection<T> collection, String fromKey, String toKey, List<String> excludeKeyPatterns, List<QueryCondition> conditions, int limit) {
Connection connection = null;
RDBTableMetaData tmd = getTable(collection);
for (QueryCondition cond : conditions) {
if (!INDEXEDPROPERTIES.contains(cond.getPropertyName())) {
String message = "indexed property " + cond.getPropertyName() + " not supported, query was '" + cond + "'; supported properties are " + INDEXEDPROPERTIES;
LOG.info(message);
throw new DocumentStoreException(message);
}
}
final Stopwatch watch = startWatch();
int resultSize = 0;
try (CacheChangesTracker tracker = obtainTracker(collection, fromKey, toKey)) {
long now = System.currentTimeMillis();
connection = this.ch.getROConnection();
String from = collection == Collection.NODES && NodeDocument.MIN_ID_VALUE.equals(fromKey) ? null : fromKey;
String to = collection == Collection.NODES && NodeDocument.MAX_ID_VALUE.equals(toKey) ? null : toKey;
// OAK-6839: only populate the cache with *new* entries if the query
// isn't open-ended (something done by GC processes)
boolean populateCache = to != null;
List<RDBRow> dbresult = db.query(connection, tmd, from, to, excludeKeyPatterns, conditions, limit);
connection.commit();
int size = dbresult.size();
List<T> result = new ArrayList<T>(size);
for (int i = 0; i < size; i++) {
// free RDBRow as early as possible
RDBRow row = dbresult.set(i, null);
T doc = getIfCached(collection, row.getId(), row.getModcount());
if (doc == null) {
// parse DB contents into document if and only if it's not
// already in the cache
doc = convertFromDBObject(collection, row);
} else {
// we got a document from the cache, thus collection is NODES
// and a tracker is present
long lastmodified = modifiedOf(doc);
if (lastmodified == row.getModified() && lastmodified >= 1) {
try (CacheLock lock = acquireLockFor(row.getId())) {
if (!tracker.mightBeenAffected(row.getId())) {
// otherwise mark it as fresh
((NodeDocument) doc).markUpToDate(now);
}
}
} else {
// we need a fresh document instance
doc = convertFromDBObject(collection, row);
}
}
result.add(doc);
}
if (collection == Collection.NODES) {
if (populateCache) {
nodesCache.putNonConflictingDocs(tracker, castAsNodeDocumentList(result));
} else {
Map<String, ModificationStamp> invMap = Maps.newHashMap();
for (Document doc : result) {
invMap.put(doc.getId(), new ModificationStamp(modcountOf(doc), modifiedOf(doc)));
}
nodesCache.invalidateOutdated(invMap);
}
}
resultSize = result.size();
return result;
} catch (Exception ex) {
LOG.error("SQL exception on query", ex);
throw asDocumentStoreException(ex, "SQL exception on query");
} finally {
this.ch.closeConnection(connection);
stats.doneQuery(watch.elapsed(TimeUnit.NANOSECONDS), collection, fromKey, toKey, !conditions.isEmpty(), resultSize, -1, false);
}
}
use of org.apache.jackrabbit.oak.plugins.document.cache.ModificationStamp in project jackrabbit-oak by apache.
the class MongoDocumentStore method update.
@Override
public <T extends Document> void update(Collection<T> collection, List<String> keys, UpdateOp updateOp) {
log("update", keys, updateOp);
UpdateUtils.assertUnconditional(updateOp);
DBCollection dbCollection = getDBCollection(collection);
QueryBuilder query = QueryBuilder.start(Document.ID).in(keys);
// make sure we don't modify the original updateOp
updateOp = updateOp.copy();
DBObject update = createUpdate(updateOp, false);
final Stopwatch watch = startWatch();
try {
Map<String, NodeDocument> cachedDocs = Collections.emptyMap();
if (collection == Collection.NODES) {
cachedDocs = Maps.newHashMap();
for (String key : keys) {
cachedDocs.put(key, nodesCache.getIfPresent(key));
}
}
try {
dbCollection.update(query.get(), update, false, true);
if (collection == Collection.NODES) {
Map<String, ModificationStamp> modCounts = getModStamps(filterValues(cachedDocs, notNull()).keySet());
// update cache
for (Entry<String, NodeDocument> entry : cachedDocs.entrySet()) {
// the cachedDocs is not empty, so the collection = NODES
Lock lock = nodeLocks.acquire(entry.getKey());
try {
ModificationStamp postUpdateModStamp = modCounts.get(entry.getKey());
if (postUpdateModStamp != null && entry.getValue() != null && entry.getValue() != NodeDocument.NULL && Long.valueOf(postUpdateModStamp.modCount - 1).equals(entry.getValue().getModCount())) {
// post update modCount is one higher than
// what we currently see in the cache. we can
// replace the cached document
NodeDocument newDoc = applyChanges(Collection.NODES, entry.getValue(), updateOp.shallowCopy(entry.getKey()));
nodesCache.replaceCachedDocument(entry.getValue(), newDoc);
} else {
// make sure concurrently loaded document is
// invalidated
nodesCache.invalidate(entry.getKey());
}
} finally {
lock.unlock();
}
}
}
} catch (MongoException e) {
throw handleException(e, collection, keys);
}
} finally {
stats.doneUpdate(watch.elapsed(TimeUnit.NANOSECONDS), collection, keys.size());
}
}
use of org.apache.jackrabbit.oak.plugins.document.cache.ModificationStamp in project jackrabbit-oak by apache.
the class MongoDocumentStore method getModStamps.
/**
* Returns the {@link Document#MOD_COUNT} and
* {@link NodeDocument#MODIFIED_IN_SECS} values of the documents with the
* given {@code keys}. The returned map will only contain entries for
* existing documents. The default value is -1 if the document does not have
* a modCount field. The same applies to the modified field.
*
* @param keys the keys of the documents.
* @return map with key to modification stamp mapping.
* @throws MongoException if the call fails
*/
@Nonnull
private Map<String, ModificationStamp> getModStamps(Iterable<String> keys) throws MongoException {
// Fetch only the modCount and id
final BasicDBObject fields = new BasicDBObject(Document.ID, 1);
fields.put(Document.MOD_COUNT, 1);
fields.put(NodeDocument.MODIFIED_IN_SECS, 1);
Map<String, ModificationStamp> modCounts = Maps.newHashMap();
nodes.withReadPreference(ReadPreference.primary()).find(Filters.in(Document.ID, keys)).projection(fields).forEach((Block<BasicDBObject>) obj -> {
String id = (String) obj.get(Document.ID);
Long modCount = Utils.asLong((Number) obj.get(Document.MOD_COUNT));
if (modCount == null) {
modCount = -1L;
}
Long modified = Utils.asLong((Number) obj.get(NodeDocument.MODIFIED_IN_SECS));
if (modified == null) {
modified = -1L;
}
modCounts.put(id, new ModificationStamp(modCount, modified));
});
return modCounts;
}
Aggregations