Source:
<code>public Change insert() throws OrmException, IOException { ReviewDb db = dbProvider.get(); db.changes().beginTransaction(change.getId()); try { ChangeUtil.insertAncestors(db, patchSet.getId(), commit); db.patchSets().insert(Collections.singleton(patchSet)); db.changes().insert(Collections.singleton(change)); ChangeUtil.updateTrackingIds(db, change, trackingFooters, commit.getFooterLines()); LabelTypes labelTypes = refControl.getProjectControl().getLabelTypes(); approvalsUtil.addReviewers(db, labelTypes, change, patchSet, patchSetInfo, reviewers, Collections.<Account.Id> emptySet()); db.commit(); } finally { db.rollback(); } if (changeMessage != null) { db.changeMessages().insert(Collections.singleton(changeMessage)); } <START> mergeabilityChecker.update(change); CheckedFuture<?, IOException> indexFuture = indexer.indexAsync(change); <END> gitRefUpdated.fire(change.getProject(), patchSet.getRefName(), ObjectId.zeroId(), commit); if (runHooks) { hooks.doPatchsetCreatedHook(change, patchSet, db); } if (sendMail) { try { CreateChangeSender cm = createChangeSenderFactory.create(change); cm.setFrom(change.getOwner()); cm.setPatchSet(patchSet, patchSetInfo); cm.addReviewers(reviewers); cm.addExtraCC(extraCC); cm.send(); } catch (Exception err) { log.error("Cannot send email for new change " + change.getId(), err); } } indexFuture.checkedGet(); return change; }</code><technical_language>This change is brand new. mergeabilityChecker observed a difference in mergeability field written out update. updated index. index is updating in another thread. This is of places composable futures handy. want is get a ListenableFuture<Boolean> mergeability.update(change). supplies true if index updated, false if not. attach a listener future updates index if boolean false (index updated). slightly defers index update, removes race index update win. In gerrit-review system I correct win, expense of some additional CPU time. in Lucene based index I idea. I racy stale mergeability flag win</technical_language>

Target:
public Change insert() throws OrmException, IOException { ReviewDb db = dbProvider.get(); db.changes().beginTransaction(change.getId()); try { ChangeUtil.insertAncestors(db, patchSet.getId(), commit); db.patchSets().insert(Collections.singleton(patchSet)); db.changes().insert(Collections.singleton(change)); ChangeUtil.updateTrackingIds(db, change, trackingFooters, commit.getFooterLines()); LabelTypes labelTypes = refControl.getProjectControl().getLabelTypes(); approvalsUtil.addReviewers(db, labelTypes, change, patchSet, patchSetInfo, reviewers, Collections.<Account.Id> emptySet()); db.commit(); } finally { db.rollback(); } if (changeMessage != null) { db.changeMessages().insert(Collections.singleton(changeMessage)); } final CheckedFuture<Boolean, IOException> mergeableFuture = mergeabilityChecker.updateAsync(change); mergeableFuture.addListener(new Runnable() { @Override public void run() { try { if (!mergeableFuture.checkedGet()) { indexer.index(change); } } catch (IOException e) { log.error("Failed to update mergeable flag for change " + change.getChangeId(), e); throw new RuntimeException(e); } } }, MoreExecutors.sameThreadExecutor()); gitRefUpdated.fire(change.getProject(), patchSet.getRefName(), ObjectId.zeroId(), commit); if (runHooks) { hooks.doPatchsetCreatedHook(change, patchSet, db); } if (sendMail) { try { CreateChangeSender cm = createChangeSenderFactory.create(change); cm.setFrom(change.getOwner()); cm.setPatchSet(patchSet, patchSetInfo); cm.addReviewers(reviewers); cm.addExtraCC(extraCC); cm.send(); } catch (Exception err) { log.error("Cannot send email for new change " + change.getId(), err); } } try { mergeableFuture.checkedGet(); } catch (IOException e) { indexer.index(change); throw e; } return change; }