checkNotNull(store);
checkNotNull(lock);
// get a copy of the map while holding the lock
lock.lock();
MapFactory tmpFactory = null;
Map<String, Revision> pending;
try {
if (map.size() > IN_MEMORY_SIZE_LIMIT) {
tmpFactory = MapFactory.createFactory();
pending = tmpFactory.create(PathComparator.INSTANCE);
} else {
pending = Maps.newTreeMap(PathComparator.INSTANCE);
}
pending.putAll(map);
} finally {
lock.unlock();
}
try {
UpdateOp updateOp = null;
Revision lastRev = null;
PeekingIterator<String> paths = Iterators.peekingIterator(
pending.keySet().iterator());
int i = 0;
ArrayList<String> pathList = new ArrayList<String>();
while (paths.hasNext()) {
String p = paths.peek();
Revision r = pending.get(p);
int size = pathList.size();
if (updateOp == null) {
// create UpdateOp
Commit commit = new Commit(store, null, r);
updateOp = commit.getUpdateOperationForNode(p);
NodeDocument.setLastRev(updateOp, r);
lastRev = r;
pathList.add(p);
paths.next();
i++;
} else if (r.equals(lastRev)) {
// use multi update when possible
pathList.add(p);
paths.next();
i++;
}
// call update if any of the following is true:
// - this is the second-to-last or last path (update last path, the
// root document, individually)
// - revision is not equal to last revision (size of ids didn't change)
// - the update limit is reached
if (i + 2 > pending.size()
|| size == pathList.size()
|| pathList.size() >= BACKGROUND_MULTI_UPDATE_LIMIT) {
List<String> ids = new ArrayList<String>();
for (String path : pathList) {
ids.add(Utils.getIdFromPath(path));
}
store.getDocumentStore().update(NODES, ids, updateOp);
for (String path : pathList) {
map.remove(path, lastRev);
}
pathList.clear();
updateOp = null;
lastRev = null;
}
}
} finally {
if (tmpFactory != null) {
tmpFactory.dispose();
}
}
}