Run change hooks and ref-updated events after indexing is done.

The change hooks and ref-updated events were run parallel to the
change (re)indexing. This meant that an event-stream sent events
to the clients before the change indexing was finished. If a client
queried for that change immediately after receiving the event it
happened that the response was not-found as the indexing wasn't yet
done.

Although we haven't had issues with a ref-updated event processors,
firing this event will also wait for the indexing task to finish
as we never know if a ref-updated event processor may trigger a
change query.

Change-Id: Iff17c5aeb9675f3991f938d31ef5048ef5b3b956
This commit is contained in:
Saša Živkov
2014-08-01 16:33:31 +02:00
committed by Hugo Arès
parent 70b4f8f703
commit 22e43cc823
10 changed files with 52 additions and 53 deletions

View File

@@ -119,13 +119,13 @@ public class Abandon implements RestModifyView<ChangeResource, AbandonInput>,
} catch (Exception e) { } catch (Exception e) {
log.error("Cannot email update for change " + change.getChangeId(), e); log.error("Cannot email update for change " + change.getChangeId(), e);
} }
indexFuture.checkedGet();
hooks.doChangeAbandonedHook(change, hooks.doChangeAbandonedHook(change,
caller.getAccount(), caller.getAccount(),
db.patchSets().get(change.currentPatchSetId()), db.patchSets().get(change.currentPatchSetId()),
Strings.emptyToNull(input.message), Strings.emptyToNull(input.message),
db); db);
ChangeInfo result = json.format(change); ChangeInfo result = json.format(change);
indexFuture.checkedGet();
return result; return result;
} }

View File

@@ -189,12 +189,6 @@ public class ChangeInserter {
changeMessage.getKey().getParentKey(), db); changeMessage.getKey().getParentKey(), db);
} }
} }
gitRefUpdated.fire(change.getProject(), patchSet.getRefName(),
ObjectId.zeroId(), commit);
if (runHooks) {
hooks.doPatchsetCreatedHook(change, patchSet, db);
}
if (sendMail) { if (sendMail) {
try { try {
@@ -210,6 +204,14 @@ public class ChangeInserter {
} }
} }
f.checkedGet(); f.checkedGet();
gitRefUpdated.fire(change.getProject(), patchSet.getRefName(),
ObjectId.zeroId(), commit);
if (runHooks) {
hooks.doPatchsetCreatedHook(change, patchSet, db);
}
return change; return change;
} }

View File

@@ -18,7 +18,6 @@ import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.SetMultimap; import com.google.common.collect.SetMultimap;
import com.google.common.util.concurrent.CheckedFuture;
import com.google.gerrit.common.ChangeHooks; import com.google.gerrit.common.ChangeHooks;
import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.client.Change;
@@ -306,14 +305,13 @@ public class PatchSetInserter {
} finally { } finally {
db.rollback(); db.rollback();
} }
CheckedFuture<?, IOException> f = mergeabilityChecker.newCheck() mergeabilityChecker.newCheck()
.addChange(updatedChange) .addChange(updatedChange)
.reindex() .reindex()
.runAsync(); .run();
if (runHooks) { if (runHooks) {
hooks.doPatchsetCreatedHook(updatedChange, patchSet, db); hooks.doPatchsetCreatedHook(updatedChange, patchSet, db);
} }
f.checkedGet();
return updatedChange; return updatedChange;
} }

View File

@@ -156,8 +156,7 @@ public class PostReview implements RestModifyView<RevisionResource, ReviewInput>
} else { } else {
indexWrite = Futures.<Void, IOException> immediateCheckedFuture(null); indexWrite = Futures.<Void, IOException> immediateCheckedFuture(null);
} }
if (message != null) { if (message != null && input.notify.compareTo(NotifyHandling.NONE) > 0) {
if (input.notify.compareTo(NotifyHandling.NONE) > 0) {
email.create( email.create(
input.notify, input.notify,
change, change,
@@ -166,12 +165,13 @@ public class PostReview implements RestModifyView<RevisionResource, ReviewInput>
message, message,
comments).sendAsync(); comments).sendAsync();
} }
fireCommentAddedHook(revision);
}
Output output = new Output(); Output output = new Output();
output.labels = input.labels; output.labels = input.labels;
indexWrite.checkedGet(); indexWrite.checkedGet();
if (message != null) {
fireCommentAddedHook(revision);
}
return output; return output;
} }

View File

@@ -245,24 +245,23 @@ public class PostReviewers implements RestModifyView<ChangeResource, AddReviewer
ImmutableList.of(psa))); ImmutableList.of(psa)));
} }
accountLoaderFactory.create(true).fill(result.reviewers); accountLoaderFactory.create(true).fill(result.reviewers);
postAdd(rsrc.getChange(), added); emailReviewers(rsrc.getChange(), added);
indexFuture.checkedGet(); indexFuture.checkedGet();
if (!added.isEmpty()) {
PatchSet patchSet = dbProvider.get().patchSets().get(rsrc.getChange().currentPatchSetId());
for (PatchSetApproval psa : added) {
Account account = accountCache.get(psa.getAccountId()).getAccount();
hooks.doReviewerAddedHook(rsrc.getChange(), account, patchSet, dbProvider.get());
}
}
} }
private void postAdd(Change change, List<PatchSetApproval> added) private void emailReviewers(Change change, List<PatchSetApproval> added)
throws OrmException, EmailException { throws OrmException, EmailException {
if (added.isEmpty()) { if (added.isEmpty()) {
return; return;
} }
// Execute hook for added reviewers
//
PatchSet patchSet = dbProvider.get().patchSets().get(change.currentPatchSetId());
for (PatchSetApproval psa : added) {
Account account = accountCache.get(psa.getAccountId()).getAccount();
hooks.doReviewerAddedHook(change, account, patchSet, dbProvider.get());
}
// Email the reviewers // Email the reviewers
// //
// The user knows they added themselves, don't bother emailing them. // The user knows they added themselves, don't bother emailing them.

View File

@@ -94,12 +94,13 @@ public class Publish implements RestModifyView<RevisionResource, Input>,
|| updatedChange.getStatus() == Change.Status.NEW) { || updatedChange.getStatus() == Change.Status.NEW) {
CheckedFuture<?, IOException> indexFuture = CheckedFuture<?, IOException> indexFuture =
indexer.indexAsync(updatedChange.getId()); indexer.indexAsync(updatedChange.getId());
hooks.doDraftPublishedHook(updatedChange, updatedPatchSet, dbProvider.get());
sender.send(rsrc.getNotes(), update, sender.send(rsrc.getNotes(), update,
rsrc.getChange().getStatus() == Change.Status.DRAFT, rsrc.getChange().getStatus() == Change.Status.DRAFT,
rsrc.getUser(), updatedChange, updatedPatchSet, rsrc.getUser(), updatedChange, updatedPatchSet,
rsrc.getControl().getLabelTypes()); rsrc.getControl().getLabelTypes());
indexFuture.checkedGet(); indexFuture.checkedGet();
hooks.doDraftPublishedHook(updatedChange, updatedPatchSet,
dbProvider.get());
} }
} catch (PatchSetInfoNotAvailableException e) { } catch (PatchSetInfoNotAvailableException e) {
throw new ResourceNotFoundException(e.getMessage()); throw new ResourceNotFoundException(e.getMessage());

View File

@@ -15,7 +15,6 @@
package com.google.gerrit.server.change; package com.google.gerrit.server.change;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.google.common.util.concurrent.CheckedFuture;
import com.google.gerrit.common.ChangeHooks; import com.google.gerrit.common.ChangeHooks;
import com.google.gerrit.extensions.restapi.AuthException; import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.DefaultInput; import com.google.gerrit.extensions.restapi.DefaultInput;
@@ -109,11 +108,9 @@ class PutTopic implements RestModifyView<ChangeResource, Input>,
} finally { } finally {
db.rollback(); db.rollback();
} }
CheckedFuture<?, IOException> indexFuture = indexer.index(db, change);
indexer.indexAsync(change.getId());
hooks.doTopicChangedHook(change, currentUser.getAccount(), hooks.doTopicChangedHook(change, currentUser.getAccount(),
oldTopicName, db); oldTopicName, db);
indexFuture.checkedGet();
} }
return Strings.isNullOrEmpty(newTopicName) return Strings.isNullOrEmpty(newTopicName)
? Response.<String>none() ? Response.<String>none()

View File

@@ -120,13 +120,13 @@ public class Restore implements RestModifyView<ChangeResource, RestoreInput>,
} catch (Exception e) { } catch (Exception e) {
log.error("Cannot email update for change " + change.getChangeId(), e); log.error("Cannot email update for change " + change.getChangeId(), e);
} }
f.checkedGet();
hooks.doChangeRestoredHook(change, hooks.doChangeRestoredHook(change,
caller.getAccount(), caller.getAccount(),
db.patchSets().get(change.currentPatchSetId()), db.patchSets().get(change.currentPatchSetId()),
Strings.emptyToNull(input.message), Strings.emptyToNull(input.message),
dbProvider.get()); dbProvider.get());
ChangeInfo result = json.format(change); ChangeInfo result = json.format(change);
f.checkedGet();
return result; return result;
} }

View File

@@ -840,6 +840,7 @@ public class MergeOp {
db.commit(); db.commit();
sendMergedEmail(c, submitter); sendMergedEmail(c, submitter);
indexer.index(db, c);
if (submitter != null) { if (submitter != null) {
try { try {
hooks.doChangeMergedHook(c, hooks.doChangeMergedHook(c,
@@ -852,7 +853,6 @@ public class MergeOp {
} finally { } finally {
db.rollback(); db.rollback();
} }
indexer.index(db, c);
} }
private Change setMergedPatchSet(Change.Id changeId, final PatchSet.Id merged) private Change setMergedPatchSet(Change.Id changeId, final PatchSet.Id merged)
@@ -1065,6 +1065,14 @@ public class MergeOp {
} }
})); }));
if (indexFuture != null) {
try {
indexFuture.checkedGet();
} catch (IOException e) {
log.error("Failed to index new change message", e);
}
}
if (submitter != null) { if (submitter != null) {
try { try {
hooks.doMergeFailedHook(c, hooks.doMergeFailedHook(c,
@@ -1074,13 +1082,6 @@ public class MergeOp {
log.error("Cannot run hook for merge failed " + c.getId(), ex); log.error("Cannot run hook for merge failed " + c.getId(), ex);
} }
} }
if (indexFuture != null) {
try {
indexFuture.checkedGet();
} catch (IOException e) {
log.error("Failed to index new change message", e);
}
}
} }
private void abandonAllOpenChanges() { private void abandonAllOpenChanges() {

View File

@@ -2002,13 +2002,6 @@ public class ReceiveCommits {
.addChange(change) .addChange(change)
.reindex() .reindex()
.runAsync(); .runAsync();
gitRefUpdated.fire(project.getNameKey(), newPatchSet.getRefName(),
ObjectId.zeroId(), newCommit);
hooks.doPatchsetCreatedHook(change, newPatchSet, db);
if (mergedIntoRef != null) {
hooks.doChangeMergedHook(
change, currentUser.getAccount(), newPatchSet, db);
}
workQueue.getDefaultQueue() workQueue.getDefaultQueue()
.submit(requestScopePropagator.wrap(new Runnable() { .submit(requestScopePropagator.wrap(new Runnable() {
@Override @Override
@@ -2037,6 +2030,14 @@ public class ReceiveCommits {
})); }));
f.checkedGet(); f.checkedGet();
gitRefUpdated.fire(project.getNameKey(), newPatchSet.getRefName(),
ObjectId.zeroId(), newCommit);
hooks.doPatchsetCreatedHook(change, newPatchSet, db);
if (mergedIntoRef != null) {
hooks.doChangeMergedHook(
change, currentUser.getAccount(), newPatchSet, db);
}
if (magicBranch != null && magicBranch.isSubmit()) { if (magicBranch != null && magicBranch.isSubmit()) {
submit(changeCtl, newPatchSet); submit(changeCtl, newPatchSet);
} }