use of com.google.gerrit.reviewdb.server.ReviewDb 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 com.google.gerrit.reviewdb.server.ReviewDb in project gerrit by GerritCodeReview.
the class Schema_131 method migrateData.
@Override
protected void migrateData(ReviewDb db, UpdateUI ui) throws OrmException {
SortedSet<Project.NameKey> repoList = repoManager.list();
SortedSet<Project.NameKey> repoUpgraded = new TreeSet<>();
ui.message("\tMigrating " + repoList.size() + " repositories ...");
for (Project.NameKey projectName : repoList) {
try (Repository git = repoManager.openRepository(projectName);
MetaDataUpdate md = new MetaDataUpdate(GitReferenceUpdated.DISABLED, projectName, git)) {
ProjectConfig config = ProjectConfig.read(md);
if (config.hasLegacyPermissions()) {
md.getCommitBuilder().setAuthor(serverUser);
md.getCommitBuilder().setCommitter(serverUser);
md.setMessage(COMMIT_MSG);
config.commit(md);
repoUpgraded.add(projectName);
}
} catch (ConfigInvalidException | IOException ex) {
throw new OrmException("Cannot migrate project " + projectName, ex);
}
}
ui.message("\tMigration completed: " + repoUpgraded.size() + " repositories updated:");
ui.message("\t" + repoUpgraded.stream().map(n -> n.get()).collect(joining(" ")));
}
use of com.google.gerrit.reviewdb.server.ReviewDb in project gerrit by GerritCodeReview.
the class Submit method getDescription.
@Override
public UiAction.Description getDescription(RevisionResource resource) {
Change change = resource.getChange();
String topic = change.getTopic();
ReviewDb db = dbProvider.get();
ChangeData cd = changeDataFactory.create(db, resource.getControl());
boolean visible;
try {
visible = change.getStatus().isOpen() && resource.isCurrent() && !resource.getPatchSet().isDraft() && resource.permissions().test(ChangePermission.SUBMIT);
MergeOp.checkSubmitRule(cd);
} catch (ResourceConflictException e) {
visible = false;
} catch (PermissionBackendException e) {
log.error("Error checking if change is submittable", e);
throw new OrmRuntimeException("Could not check submit permission", e);
} catch (OrmException e) {
log.error("Error checking if change is submittable", e);
throw new OrmRuntimeException("Could not determine problems for the change", e);
}
if (!visible) {
return new UiAction.Description().setLabel("").setTitle("").setVisible(false);
}
ChangeSet cs;
try {
cs = mergeSuperSet.get().completeChangeSet(db, cd.change(), resource.getControl().getUser());
} catch (OrmException | IOException e) {
throw new OrmRuntimeException("Could not determine complete set of changes to be submitted", e);
}
int topicSize = 0;
if (!Strings.isNullOrEmpty(topic)) {
topicSize = getChangesByTopic(topic).size();
}
boolean treatWithTopic = submitWholeTopic && !Strings.isNullOrEmpty(topic) && topicSize > 1;
String submitProblems = problemsForSubmittingChangeset(cd, cs, resource.getUser());
Boolean enabled;
try {
// Recheck mergeability rather than using value stored in the index,
// which may be stale.
// TODO(dborowitz): This is ugly; consider providing a way to not read
// stored fields from the index in the first place.
// cd.setMergeable(null);
// That was done in unmergeableChanges which was called by
// problemsForSubmittingChangeset, so now it is safe to read from
// the cache, as it yields the same result.
enabled = cd.isMergeable();
} catch (OrmException e) {
throw new OrmRuntimeException("Could not determine mergeability", e);
}
if (submitProblems != null) {
return new UiAction.Description().setLabel(treatWithTopic ? submitTopicLabel : (cs.size() > 1) ? labelWithParents : label).setTitle(submitProblems).setVisible(true).setEnabled(false);
}
if (treatWithTopic) {
Map<String, String> params = ImmutableMap.of("topicSize", String.valueOf(topicSize), "submitSize", String.valueOf(cs.size()));
return new UiAction.Description().setLabel(submitTopicLabel).setTitle(Strings.emptyToNull(submitTopicTooltip.replace(params))).setVisible(true).setEnabled(Boolean.TRUE.equals(enabled));
}
RevId revId = resource.getPatchSet().getRevision();
Map<String, String> params = ImmutableMap.of("patchSet", String.valueOf(resource.getPatchSet().getPatchSetId()), "branch", change.getDest().getShortName(), "commit", ObjectId.fromString(revId.get()).abbreviate(7).name(), "submitSize", String.valueOf(cs.size()));
ParameterizedString tp = cs.size() > 1 ? titlePatternWithAncestors : titlePattern;
return new UiAction.Description().setLabel(cs.size() > 1 ? labelWithParents : label).setTitle(Strings.emptyToNull(tp.replace(params))).setVisible(true).setEnabled(Boolean.TRUE.equals(enabled));
}
use of com.google.gerrit.reviewdb.server.ReviewDb in project gerrit by GerritCodeReview.
the class Submit method mergeChange.
public Change mergeChange(BatchUpdate.Factory updateFactory, RevisionResource rsrc, IdentifiedUser submitter, SubmitInput input) throws OrmException, RestApiException, IOException {
Change change = rsrc.getChange();
if (!change.getStatus().isOpen()) {
throw new ResourceConflictException("change is " + ChangeUtil.status(change));
} else if (!ProjectUtil.branchExists(repoManager, change.getDest())) {
throw new ResourceConflictException(String.format("destination branch \"%s\" not found.", change.getDest().get()));
} else if (!rsrc.getPatchSet().getId().equals(change.currentPatchSetId())) {
// TODO Allow submitting non-current revision by changing the current.
throw new ResourceConflictException(String.format("revision %s is not current revision", rsrc.getPatchSet().getRevision().get()));
}
try (MergeOp op = mergeOpFactory.create(updateFactory)) {
ReviewDb db = dbProvider.get();
op.merge(db, change, submitter, true, input, false);
try {
change = changeNotesFactory.createChecked(db, change.getProject(), change.getId()).getChange();
} catch (NoSuchChangeException e) {
throw new ResourceConflictException("change is deleted");
}
}
switch(change.getStatus()) {
case MERGED:
return change;
case NEW:
ChangeMessage msg = getConflictMessage(rsrc);
if (msg != null) {
throw new ResourceConflictException(msg.getMessage());
}
//$FALL-THROUGH$
case ABANDONED:
case DRAFT:
default:
throw new ResourceConflictException("change is " + ChangeUtil.status(change));
}
}
use of com.google.gerrit.reviewdb.server.ReviewDb in project gerrit by GerritCodeReview.
the class Rebase method findBaseRev.
private ObjectId findBaseRev(Repository repo, RevWalk rw, RevisionResource rsrc, RebaseInput input) throws RestApiException, OrmException, IOException, NoSuchChangeException {
Branch.NameKey destRefKey = rsrc.getChange().getDest();
if (input == null || input.base == null) {
return rebaseUtil.findBaseRevision(rsrc.getPatchSet(), destRefKey, repo, rw);
}
Change change = rsrc.getChange();
String str = input.base.trim();
if (str.equals("")) {
// Remove existing dependency to other patch set.
Ref destRef = repo.exactRef(destRefKey.get());
if (destRef == null) {
throw new ResourceConflictException("can't rebase onto tip of branch " + destRefKey.get() + "; branch doesn't exist");
}
return destRef.getObjectId();
}
@SuppressWarnings("resource") ReviewDb db = dbProvider.get();
Base base = rebaseUtil.parseBase(rsrc, str);
if (base == null) {
throw new ResourceConflictException("base revision is missing: " + str);
}
PatchSet.Id baseId = base.patchSet().getId();
if (!base.control().isPatchVisible(base.patchSet(), db)) {
throw new AuthException("base revision not accessible: " + str);
} else if (change.getId().equals(baseId.getParentKey())) {
throw new ResourceConflictException("cannot rebase change onto itself");
}
Change baseChange = base.control().getChange();
if (!baseChange.getProject().equals(change.getProject())) {
throw new ResourceConflictException("base change is in wrong project: " + baseChange.getProject());
} else if (!baseChange.getDest().equals(change.getDest())) {
throw new ResourceConflictException("base change is targeting wrong branch: " + baseChange.getDest());
} else if (baseChange.getStatus() == Status.ABANDONED) {
throw new ResourceConflictException("base change is abandoned: " + baseChange.getKey());
} else if (isMergedInto(rw, rsrc.getPatchSet(), base.patchSet())) {
throw new ResourceConflictException("base change " + baseChange.getKey() + " is a descendant of the current change - recursion not allowed");
}
return ObjectId.fromString(base.patchSet().getRevision().get());
}
Aggregations