use of com.google.gerrit.git.LockFailureException in project gerrit by GerritCodeReview.
the class DeleteRef method deleteSingleRef.
/**
* Deletes a single ref from the repository.
*
* @param projectState the {@code ProjectState} of the project containing the target ref.
* @param ref the ref to be deleted.
* @param prefix the prefix of the ref.
*/
public void deleteSingleRef(ProjectState projectState, String ref, @Nullable String prefix) throws IOException, ResourceConflictException, AuthException, PermissionBackendException {
if (prefix != null && !ref.startsWith(R_REFS)) {
ref = prefix + ref;
}
projectState.checkStatePermitsWrite();
permissionBackend.currentUser().project(projectState.getNameKey()).ref(ref).check(RefPermission.DELETE);
try (Repository repository = repoManager.openRepository(projectState.getNameKey())) {
RefUpdate.Result result;
RefUpdate u = repository.updateRef(ref);
u.setExpectedOldObjectId(repository.exactRef(ref).getObjectId());
u.setNewObjectId(ObjectId.zeroId());
u.setForceUpdate(true);
refDeletionValidator.validateRefOperation(projectState.getName(), identifiedUser.get(), u, /* pushOptions */
ImmutableListMultimap.of());
result = u.delete();
switch(result) {
case NEW:
case NO_CHANGE:
case FAST_FORWARD:
case FORCED:
referenceUpdated.fire(projectState.getNameKey(), u, ReceiveCommand.Type.DELETE, identifiedUser.get().state());
break;
case REJECTED_CURRENT_BRANCH:
logger.atFine().log("Cannot delete current branch %s: %s", ref, result.name());
throw new ResourceConflictException("cannot delete current branch");
case LOCK_FAILURE:
throw new LockFailureException(String.format("Cannot delete %s", ref), u);
case IO_FAILURE:
case NOT_ATTEMPTED:
case REJECTED:
case RENAMED:
case REJECTED_MISSING_OBJECT:
case REJECTED_OTHER_REASON:
default:
throw new StorageException(String.format("Cannot delete %s: %s", ref, result.name()));
}
}
}
use of com.google.gerrit.git.LockFailureException in project gerrit by GerritCodeReview.
the class VersionedMetaData method openUpdate.
/**
* Open a batch of updates to the same metadata ref.
*
* <p>This allows making multiple commits to a single metadata ref, at the end of which is a
* single ref update. For batching together updates to multiple refs (each consisting of one or
* more commits against their respective refs), create the {@link MetaDataUpdate} with a {@link
* BatchRefUpdate}.
*
* <p>A ref update produced by this {@link BatchMetaDataUpdate} is only committed if there is no
* associated {@link BatchRefUpdate}. As a result, the configured ref updated event is not fired
* if there is an associated batch.
*
* <p>If object inserter, reader and revwalk are provided, then the updates are not flushed,
* allowing callers the flexibility to flush only once after several updates.
*
* @param update helper info about the update.
* @param objInserter Shared object inserter.
* @param objReader Shared object reader.
* @param revWalk Shared rev walk.
* @throws IOException if the update failed.
*/
public BatchMetaDataUpdate openUpdate(MetaDataUpdate update, ObjectInserter objInserter, ObjectReader objReader, RevWalk revWalk) throws IOException {
final Repository db = update.getRepository();
inserter = objInserter == null ? db.newObjectInserter() : objInserter;
reader = objReader == null ? inserter.newReader() : objReader;
final RevWalk rw = revWalk == null ? new RevWalk(reader) : revWalk;
final RevTree tree = revision != null ? rw.parseTree(revision) : null;
newTree = readTree(tree);
return new BatchMetaDataUpdate() {
RevCommit src = revision;
AnyObjectId srcTree = tree;
@Override
public void write(CommitBuilder commit) throws IOException {
write(VersionedMetaData.this, commit);
}
private boolean doSave(VersionedMetaData config, CommitBuilder commit) throws IOException {
DirCache nt = config.newTree;
ObjectReader r = config.reader;
ObjectInserter i = config.inserter;
RevCommit c = config.revision;
try {
config.newTree = newTree;
config.reader = reader;
config.inserter = inserter;
config.revision = src;
return config.onSave(commit);
} catch (ConfigInvalidException e) {
throw new IOException("Cannot update " + getRefName() + " in " + db.getDirectory() + ": " + e.getMessage(), e);
} finally {
config.newTree = nt;
config.reader = r;
config.inserter = i;
config.revision = c;
}
}
@Override
public void write(VersionedMetaData config, CommitBuilder commit) throws IOException {
checkSameRef(config);
if (!doSave(config, commit)) {
return;
}
ObjectId res = newTree.writeTree(inserter);
if (res.equals(srcTree) && !update.allowEmpty() && (commit.getTreeId() == null)) {
// If there are no changes to the content, don't create the commit.
return;
}
// the tree for the updated DirCache.
if (commit.getTreeId() == null) {
commit.setTreeId(res);
} else {
// In this case, the caller populated the tree without using DirCache.
res = commit.getTreeId();
}
if (src != null) {
commit.addParentId(src);
}
if (update.insertChangeId()) {
commit.setMessage(ChangeIdUtil.insertId(commit.getMessage(), CommitMessageUtil.generateChangeId()));
}
src = rw.parseCommit(inserter.insert(commit));
srcTree = res;
}
private void checkSameRef(VersionedMetaData other) {
String thisRef = VersionedMetaData.this.getRefName();
String otherRef = other.getRefName();
checkArgument(otherRef.equals(thisRef), "cannot add %s for %s to %s on %s", other.getClass().getSimpleName(), otherRef, BatchMetaDataUpdate.class.getSimpleName(), thisRef);
}
@Override
public RevCommit createRef(String refName) throws IOException {
if (Objects.equals(src, revision)) {
return revision;
}
return updateRef(ObjectId.zeroId(), src, refName);
}
@Override
public RevCommit commit() throws IOException {
return commitAt(revision);
}
@Override
public RevCommit commitAt(ObjectId expected) throws IOException {
if (Objects.equals(src, expected)) {
return revision;
}
return updateRef(MoreObjects.firstNonNull(expected, ObjectId.zeroId()), src, getRefName());
}
@Override
public void close() {
newTree = null;
if (revWalk == null) {
rw.close();
}
if (objInserter == null && inserter != null) {
inserter.close();
inserter = null;
}
if (objReader == null && reader != null) {
reader.close();
reader = null;
}
}
private RevCommit updateRef(AnyObjectId oldId, AnyObjectId newId, String refName) throws IOException {
BatchRefUpdate bru = update.getBatch();
if (bru != null) {
bru.addCommand(new ReceiveCommand(oldId.toObjectId(), newId.toObjectId(), refName));
if (objInserter == null) {
inserter.flush();
}
revision = rw.parseCommit(newId);
return revision;
}
RefUpdate ru = db.updateRef(refName);
ru.setExpectedOldObjectId(oldId);
ru.setNewObjectId(newId);
ru.setRefLogIdent(update.getCommitBuilder().getAuthor());
String message = update.getCommitBuilder().getMessage();
if (message == null) {
message = "meta data update";
}
try (BufferedReader reader = new BufferedReader(new StringReader(message))) {
// read the subject line and use it as reflog message
ru.setRefLogMessage("commit: " + reader.readLine(), true);
}
logger.atFine().log("Saving commit '%s' on project '%s'", message.trim(), projectName);
inserter.flush();
RefUpdate.Result result = ru.update();
switch(result) {
case NEW:
case FAST_FORWARD:
revision = rw.parseCommit(ru.getNewObjectId());
update.fireGitRefUpdatedEvent(ru);
logger.atFine().log("Saved commit '%s' as revision '%s' on project '%s'", message.trim(), revision.name(), projectName);
return revision;
case LOCK_FAILURE:
throw new LockFailureException(errorMsg(ru, db.getDirectory()), ru);
case FORCED:
case IO_FAILURE:
case NOT_ATTEMPTED:
case NO_CHANGE:
case REJECTED:
case REJECTED_CURRENT_BRANCH:
case RENAMED:
case REJECTED_MISSING_OBJECT:
case REJECTED_OTHER_REASON:
default:
throw new GitUpdateFailureException(errorMsg(ru, db.getDirectory()), ru);
}
}
};
}
use of com.google.gerrit.git.LockFailureException in project gerrit by GerritCodeReview.
the class MergeOp method integrateIntoHistory.
private void integrateIntoHistory(ChangeSet cs, SubmissionExecutor submissionExecutor) throws RestApiException, UpdateException {
checkArgument(!cs.furtherHiddenChanges(), "cannot integrate hidden changes into history");
logger.atFine().log("Beginning merge attempt on %s", cs);
Map<BranchNameKey, BranchBatch> toSubmit = new HashMap<>();
ListMultimap<BranchNameKey, ChangeData> cbb;
try {
cbb = cs.changesByBranch();
} catch (StorageException e) {
throw new StorageException("Error reading changes to submit", e);
}
Set<BranchNameKey> branches = cbb.keySet();
for (BranchNameKey branch : branches) {
OpenRepo or = openRepo(branch.project());
if (or != null) {
toSubmit.put(branch, validateChangeList(or, cbb.get(branch)));
}
}
// Done checks that don't involve running submit strategies.
commitStatus.maybeFailVerbose();
try {
SubscriptionGraph subscriptionGraph = subscriptionGraphFactory.compute(branches, orm);
SubmoduleCommits submoduleCommits = submoduleCommitsFactory.create(orm);
UpdateOrderCalculator updateOrderCalculator = new UpdateOrderCalculator(subscriptionGraph);
List<SubmitStrategy> strategies = getSubmitStrategies(toSubmit, updateOrderCalculator, submoduleCommits, subscriptionGraph, dryrun);
this.allProjects = updateOrderCalculator.getProjectsInOrder();
List<BatchUpdate> batchUpdates = orm.batchUpdates(allProjects);
// Group batch updates by project
Map<Project.NameKey, BatchUpdate> batchUpdatesByProject = batchUpdates.stream().collect(Collectors.toMap(b -> b.getProject(), Function.identity()));
for (Map.Entry<Change.Id, ChangeData> entry : cs.changesById().entrySet()) {
Project.NameKey project = entry.getValue().project();
Change.Id changeId = entry.getKey();
ChangeData cd = entry.getValue();
batchUpdatesByProject.get(project).addOp(changeId, storeSubmitRequirementsOpFactory.create(cd.submitRequirementsIncludingLegacy().values(), cd));
}
try {
submissionExecutor.setAdditionalBatchUpdateListeners(ImmutableList.of(new SubmitStrategyListener(submitInput, strategies, commitStatus)));
submissionExecutor.execute(batchUpdates);
} finally {
// If the BatchUpdate fails it can be that merging some of the changes was actually
// successful. This is why we must to collect the updated changes also when an
// exception was thrown.
strategies.forEach(s -> updatedChanges.putAll(s.getUpdatedChanges()));
// Do not leave executed BatchUpdates in the OpenRepos
if (!dryrun) {
orm.resetUpdates(ImmutableSet.copyOf(this.allProjects));
}
}
} catch (NoSuchProjectException e) {
throw new ResourceNotFoundException(e.getMessage());
} catch (IOException e) {
throw new StorageException(e);
} catch (SubmoduleConflictException e) {
throw new IntegrationConflictException(e.getMessage(), e);
} catch (UpdateException e) {
if (e.getCause() instanceof LockFailureException) {
// as to be unnoticeable, assuming RetryHelper is retrying sufficiently.
throw e;
}
// inner IntegrationConflictException to a ResourceConflictException.
if (e.getCause() instanceof IntegrationConflictException) {
throw (IntegrationConflictException) e.getCause();
}
throw new MergeUpdateException(genericMergeError(cs), e);
}
}
Aggregations