use of org.eclipse.jgit.transport.ReceiveCommand in project gerrit by GerritCodeReview.
the class ReviewDbBatchUpdate method executeNoteDbUpdates.
private void executeNoteDbUpdates(List<ChangeTask> tasks) throws ResourceConflictException, IOException {
// Aggregate together all NoteDb ref updates from the ops we executed,
// possibly in parallel. Each task had its own NoteDbUpdateManager instance
// with its own thread-local copy of the repo(s), but each of those was just
// used for staging updates and was never executed.
//
// Use a new BatchRefUpdate as the original batchRefUpdate field is intended
// for use only by the updateRepo phase.
//
// See the comments in NoteDbUpdateManager#execute() for why we execute the
// updates on the change repo first.
logDebug("Executing NoteDb updates for {} changes", tasks.size());
try {
initRepository();
BatchRefUpdate changeRefUpdate = repoView.getRepository().getRefDatabase().newBatchUpdate();
boolean hasAllUsersCommands = false;
try (ObjectInserter ins = repoView.getRepository().newObjectInserter()) {
int objs = 0;
for (ChangeTask task : tasks) {
if (task.noteDbResult == null) {
logDebug("No-op update to {}", task.id);
continue;
}
for (ReceiveCommand cmd : task.noteDbResult.changeCommands()) {
changeRefUpdate.addCommand(cmd);
}
for (InsertedObject obj : task.noteDbResult.changeObjects()) {
objs++;
ins.insert(obj.type(), obj.data().toByteArray());
}
hasAllUsersCommands |= !task.noteDbResult.allUsersCommands().isEmpty();
}
logDebug("Collected {} objects and {} ref updates to change repo", objs, changeRefUpdate.getCommands().size());
executeNoteDbUpdate(getRevWalk(), ins, changeRefUpdate);
}
if (hasAllUsersCommands) {
try (Repository allUsersRepo = repoManager.openRepository(allUsers);
RevWalk allUsersRw = new RevWalk(allUsersRepo);
ObjectInserter allUsersIns = allUsersRepo.newObjectInserter()) {
int objs = 0;
BatchRefUpdate allUsersRefUpdate = allUsersRepo.getRefDatabase().newBatchUpdate();
for (ChangeTask task : tasks) {
for (ReceiveCommand cmd : task.noteDbResult.allUsersCommands()) {
allUsersRefUpdate.addCommand(cmd);
}
for (InsertedObject obj : task.noteDbResult.allUsersObjects()) {
allUsersIns.insert(obj.type(), obj.data().toByteArray());
}
}
logDebug("Collected {} objects and {} ref updates to All-Users", objs, allUsersRefUpdate.getCommands().size());
executeNoteDbUpdate(allUsersRw, allUsersIns, allUsersRefUpdate);
}
} else {
logDebug("No All-Users updates");
}
} catch (IOException e) {
if (tasks.stream().allMatch(t -> t.storage == PrimaryStorage.REVIEW_DB)) {
// Ignore all errors trying to update NoteDb at this point. We've already written the
// NoteDbChangeStates to ReviewDb, which means if any state is out of date it will be
// rebuilt the next time it is needed.
//
// Always log even without RequestId.
log.debug("Ignoring NoteDb update error after ReviewDb write", e);
// Otherwise, we can't prove it's safe to ignore the error, either because some change had
// NOTE_DB primary, or a task failed before determining the primary storage.
} else if (e instanceof LockFailureException) {
// although it happened too late for us to produce anything but a generic error message.
throw new ResourceConflictException("Updating change failed due to conflicting write", e);
}
throw e;
}
}
use of org.eclipse.jgit.transport.ReceiveCommand in project gerrit by GerritCodeReview.
the class ReviewDbBatchUpdate method executeNoteDbUpdate.
private void executeNoteDbUpdate(RevWalk rw, ObjectInserter ins, BatchRefUpdate bru) throws IOException {
if (bru.getCommands().isEmpty()) {
logDebug("No commands, skipping flush and ref update");
return;
}
ins.flush();
bru.setAllowNonFastForwards(true);
bru.execute(rw, NullProgressMonitor.INSTANCE);
for (ReceiveCommand cmd : bru.getCommands()) {
// TODO(dborowitz): LOCK_FAILURE for NoteDb primary should be retried.
if (cmd.getResult() != ReceiveCommand.Result.OK) {
throw new IOException("Update failed: " + bru);
}
}
}
use of org.eclipse.jgit.transport.ReceiveCommand in project gerrit by GerritCodeReview.
the class UnfusedNoteDbBatchUpdate method executeRefUpdates.
// TODO(dborowitz): Don't execute non-change ref updates separately when fusing phases.
private void executeRefUpdates(boolean dryrun) throws IOException, RestApiException {
if (getRefUpdates().isEmpty()) {
logDebug("No ref updates to execute");
return;
}
// May not be opened if the caller added ref updates but no new objects.
initRepository();
batchRefUpdate = repoView.getRepository().getRefDatabase().newBatchUpdate();
batchRefUpdate.setPushCertificate(pushCert);
batchRefUpdate.setRefLogMessage(refLogMessage, true);
batchRefUpdate.setAllowNonFastForwards(true);
repoView.getCommands().addTo(batchRefUpdate);
logDebug("Executing batch of {} ref updates", batchRefUpdate.getCommands().size());
if (dryrun) {
return;
}
// that might have access to unflushed objects.
try (RevWalk updateRw = new RevWalk(repoView.getRepository())) {
batchRefUpdate.execute(updateRw, NullProgressMonitor.INSTANCE);
}
boolean ok = true;
for (ReceiveCommand cmd : batchRefUpdate.getCommands()) {
if (cmd.getResult() != ReceiveCommand.Result.OK) {
ok = false;
break;
}
}
if (!ok) {
throw new RestApiException("BatchRefUpdate failed: " + batchRefUpdate);
}
}
use of org.eclipse.jgit.transport.ReceiveCommand in project gerrit by GerritCodeReview.
the class NoteDbUpdateManager method addRewrites.
private static void addRewrites(ListMultimap<String, NoteDbRewriter> rewriters, OpenRepo openRepo) throws OrmException, IOException {
for (Map.Entry<String, Collection<NoteDbRewriter>> entry : rewriters.asMap().entrySet()) {
String refName = entry.getKey();
ObjectId oldTip = openRepo.cmds.get(refName).orElse(ObjectId.zeroId());
if (oldTip.equals(ObjectId.zeroId())) {
throw new OrmException(String.format("Ref %s is empty", refName));
}
ObjectId currTip = oldTip;
try {
for (NoteDbRewriter noteDbRewriter : entry.getValue()) {
ObjectId nextTip = noteDbRewriter.rewriteCommitHistory(openRepo.rw, openRepo.tempIns, currTip);
if (nextTip != null) {
currTip = nextTip;
}
}
} catch (ConfigInvalidException e) {
throw new OrmException("Cannot rewrite commit history", e);
}
if (!oldTip.equals(currTip)) {
openRepo.cmds.add(new ReceiveCommand(oldTip, currTip, refName));
}
}
}
use of org.eclipse.jgit.transport.ReceiveCommand in project gerrit by GerritCodeReview.
the class NoteDbUpdateManager method getDraftIds.
private Table<Change.Id, Account.Id, ObjectId> getDraftIds() {
Table<Change.Id, Account.Id, ObjectId> draftIds = HashBasedTable.create();
if (allUsersRepo == null) {
return draftIds;
}
for (ReceiveCommand cmd : allUsersRepo.getCommandsSnapshot()) {
String r = cmd.getRefName();
if (r.startsWith(REFS_DRAFT_COMMENTS)) {
Change.Id changeId = Change.Id.fromRefPart(r.substring(REFS_DRAFT_COMMENTS.length()));
Account.Id accountId = Account.Id.fromRefSuffix(r);
checkDraftRef(accountId != null && changeId != null, r);
draftIds.put(changeId, accountId, cmd.getNewId());
}
}
return draftIds;
}
Aggregations