Search in sources :

Example 1 with LockFailureException

use of com.google.gerrit.server.git.LockFailureException in project gerrit by GerritCodeReview.

the class ExternalIdsUpdate method commit.

/** Commits updates to the external IDs. */
public static ObjectId commit(Repository repo, RevWalk rw, ObjectInserter ins, ObjectId rev, NoteMap noteMap, String commitMessage, PersonIdent committerIdent, PersonIdent authorIdent) throws IOException {
    CommitBuilder cb = new CommitBuilder();
    cb.setMessage(commitMessage);
    cb.setTreeId(noteMap.writeTree(ins));
    cb.setAuthor(authorIdent);
    cb.setCommitter(committerIdent);
    if (!rev.equals(ObjectId.zeroId())) {
        cb.setParentId(rev);
    } else {
        // Ref is currently nonexistent, commit has no parents.
        cb.setParentIds();
    }
    if (cb.getTreeId() == null) {
        if (rev.equals(ObjectId.zeroId())) {
            // No parent, assume empty tree.
            cb.setTreeId(emptyTree(ins));
        } else {
            RevCommit p = rw.parseCommit(rev);
            // Copy tree from parent.
            cb.setTreeId(p.getTree());
        }
    }
    ObjectId commitId = ins.insert(cb);
    ins.flush();
    RefUpdate u = repo.updateRef(RefNames.REFS_EXTERNAL_IDS);
    u.setRefLogIdent(committerIdent);
    u.setRefLogMessage("Update external IDs", false);
    u.setExpectedOldObjectId(rev);
    u.setNewObjectId(commitId);
    RefUpdate.Result res = u.update();
    switch(res) {
        case NEW:
        case FAST_FORWARD:
        case NO_CHANGE:
        case RENAMED:
        case FORCED:
            break;
        case LOCK_FAILURE:
            throw new LockFailureException("Updating external IDs failed with " + res);
        case IO_FAILURE:
        case NOT_ATTEMPTED:
        case REJECTED:
        case REJECTED_CURRENT_BRANCH:
        default:
            throw new IOException("Updating external IDs failed with " + res);
    }
    return rw.parseCommit(commitId);
}
Also used : ObjectId(org.eclipse.jgit.lib.ObjectId) CommitBuilder(org.eclipse.jgit.lib.CommitBuilder) IOException(java.io.IOException) LockFailureException(com.google.gerrit.server.git.LockFailureException) RevCommit(org.eclipse.jgit.revwalk.RevCommit) RefUpdate(org.eclipse.jgit.lib.RefUpdate)

Example 2 with LockFailureException

use of com.google.gerrit.server.git.LockFailureException in project gerrit by GerritCodeReview.

the class ExternalIdIT method failAfterRetryerGivesUp.

@Test
public void failAfterRetryerGivesUp() throws Exception {
    ExternalId.Key[] extIdsKeys = { ExternalId.Key.create("foo", "foo"), ExternalId.Key.create("bar", "bar"), ExternalId.Key.create("baz", "baz") };
    final AtomicInteger bgCounter = new AtomicInteger(0);
    ExternalIdsUpdate update = new ExternalIdsUpdate(repoManager, allUsers, metricMaker, externalIds, new DisabledExternalIdCache(), serverIdent.get(), serverIdent.get(), () -> {
        try {
            extIdsUpdate.create().insert(ExternalId.create(extIdsKeys[bgCounter.getAndAdd(1)], admin.id));
        } catch (IOException | ConfigInvalidException | OrmException e) {
        // Ignore, the successful insertion of the external ID is asserted later
        }
    }, RetryerBuilder.<RefsMetaExternalIdsUpdate>newBuilder().retryIfException(e -> e instanceof LockFailureException).withStopStrategy(StopStrategies.stopAfterAttempt(extIdsKeys.length)).build());
    assertThat(bgCounter.get()).isEqualTo(0);
    try {
        update.insert(ExternalId.create(ExternalId.Key.create("abc", "abc"), admin.id));
        fail("expected LockFailureException");
    } catch (LockFailureException e) {
    // Ignore, expected
    }
    assertThat(bgCounter.get()).isEqualTo(extIdsKeys.length);
    for (ExternalId.Key extIdKey : extIdsKeys) {
        assertThat(externalIds.get(extIdKey)).isNotNull();
    }
}
Also used : AllUsersName(com.google.gerrit.server.config.AllUsersName) TypeToken(com.google.gson.reflect.TypeToken) OrmException(com.google.gwtorm.server.OrmException) ObjectInserter(org.eclipse.jgit.lib.ObjectInserter) OBJ_BLOB(org.eclipse.jgit.lib.Constants.OBJ_BLOB) GlobalCapability(com.google.gerrit.common.data.GlobalCapability) Retryer(com.github.rholder.retry.Retryer) RetryerBuilder(com.github.rholder.retry.RetryerBuilder) Inject(com.google.inject.Inject) RestResponse(com.google.gerrit.acceptance.RestResponse) REGISTERED_USERS(com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS) BlockStrategy(com.github.rholder.retry.BlockStrategy) RevWalk(org.eclipse.jgit.revwalk.RevWalk) Config(org.eclipse.jgit.lib.Config) SCHEME_USERNAME(com.google.gerrit.server.account.externalids.ExternalId.SCHEME_USERNAME) ConsistencyProblemInfo(com.google.gerrit.extensions.api.config.ConsistencyCheckInfo.ConsistencyProblemInfo) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Locale(java.util.Locale) AuthException(com.google.gerrit.extensions.restapi.AuthException) Assert.fail(org.junit.Assert.fail) SCHEME_UUID(com.google.gerrit.server.account.externalids.ExternalId.SCHEME_UUID) NoteMap(org.eclipse.jgit.notes.NoteMap) CheckAccountExternalIdsInput(com.google.gerrit.extensions.api.config.ConsistencyCheckInput.CheckAccountExternalIdsInput) ImmutableSet(com.google.common.collect.ImmutableSet) Collection(java.util.Collection) Permission(com.google.gerrit.common.data.Permission) ConsistencyCheckInfo(com.google.gerrit.extensions.api.config.ConsistencyCheckInfo) Set(java.util.Set) ExternalIds(com.google.gerrit.server.account.externalids.ExternalIds) List(java.util.List) StopStrategies(com.github.rholder.retry.StopStrategies) RefNames(com.google.gerrit.reviewdb.client.RefNames) PushResult(org.eclipse.jgit.transport.PushResult) AbstractDaemonTest(com.google.gerrit.acceptance.AbstractDaemonTest) MetricMaker(com.google.gerrit.metrics.MetricMaker) ExternalIdsUpdate(com.google.gerrit.server.account.externalids.ExternalIdsUpdate) GitUtil.fetch(com.google.gerrit.acceptance.GitUtil.fetch) Iterables(com.google.common.collect.Iterables) Status(org.eclipse.jgit.transport.RemoteRefUpdate.Status) ConfigInvalidException(org.eclipse.jgit.errors.ConfigInvalidException) InMemoryRepository(org.eclipse.jgit.internal.storage.dfs.InMemoryRepository) OrmDuplicateKeyException(com.google.gwtorm.server.OrmDuplicateKeyException) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) RefsMetaExternalIdsUpdate(com.google.gerrit.server.account.externalids.ExternalIdsUpdate.RefsMetaExternalIdsUpdate) LockFailureException(com.google.gerrit.server.git.LockFailureException) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) DisabledExternalIdCache(com.google.gerrit.server.account.externalids.DisabledExternalIdCache) ImmutableList(com.google.common.collect.ImmutableList) AccountExternalIdInfo(com.google.gerrit.extensions.common.AccountExternalIdInfo) Account(com.google.gerrit.reviewdb.client.Account) ConsistencyCheckInput(com.google.gerrit.extensions.api.config.ConsistencyCheckInput) GitUtil.pushHead(com.google.gerrit.acceptance.GitUtil.pushHead) TestRepository(org.eclipse.jgit.junit.TestRepository) Sandboxed(com.google.gerrit.acceptance.Sandboxed) UTF_8(java.nio.charset.StandardCharsets.UTF_8) ExternalIdReader(com.google.gerrit.server.account.externalids.ExternalIdReader) IOException(java.io.IOException) Test(org.junit.Test) Truth.assertThat(com.google.common.truth.Truth.assertThat) SCHEME_MAILTO(com.google.gerrit.server.account.externalids.ExternalId.SCHEME_MAILTO) MutableInteger(org.eclipse.jgit.util.MutableInteger) ObjectId(org.eclipse.jgit.lib.ObjectId) TransportException(org.eclipse.jgit.api.errors.TransportException) Collectors.toList(java.util.stream.Collectors.toList) RemoteRefUpdate(org.eclipse.jgit.transport.RemoteRefUpdate) ExternalId(com.google.gerrit.server.account.externalids.ExternalId) Collections(java.util.Collections) Repository(org.eclipse.jgit.lib.Repository) ConfigInvalidException(org.eclipse.jgit.errors.ConfigInvalidException) RefsMetaExternalIdsUpdate(com.google.gerrit.server.account.externalids.ExternalIdsUpdate.RefsMetaExternalIdsUpdate) ExternalIdsUpdate(com.google.gerrit.server.account.externalids.ExternalIdsUpdate) RefsMetaExternalIdsUpdate(com.google.gerrit.server.account.externalids.ExternalIdsUpdate.RefsMetaExternalIdsUpdate) ExternalId(com.google.gerrit.server.account.externalids.ExternalId) IOException(java.io.IOException) LockFailureException(com.google.gerrit.server.git.LockFailureException) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) OrmException(com.google.gwtorm.server.OrmException) DisabledExternalIdCache(com.google.gerrit.server.account.externalids.DisabledExternalIdCache) AbstractDaemonTest(com.google.gerrit.acceptance.AbstractDaemonTest) Test(org.junit.Test)

Example 3 with LockFailureException

use of com.google.gerrit.server.git.LockFailureException 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;
    }
}
Also used : AllUsersName(com.google.gerrit.server.config.AllUsersName) ChangeControl(com.google.gerrit.server.project.ChangeControl) RequestId(com.google.gerrit.server.util.RequestId) OrmException(com.google.gwtorm.server.OrmException) ObjectInserter(org.eclipse.jgit.lib.ObjectInserter) Inject(com.google.inject.Inject) ReceiveCommand(org.eclipse.jgit.transport.ReceiveCommand) LoggerFactory(org.slf4j.LoggerFactory) CheckedFuture(com.google.common.util.concurrent.CheckedFuture) PrimaryStorage(com.google.gerrit.server.notedb.NoteDbChangeState.PrimaryStorage) Assisted(com.google.inject.assistedinject.Assisted) RevWalk(org.eclipse.jgit.revwalk.RevWalk) Config(org.eclipse.jgit.lib.Config) InsertedObject(com.google.gerrit.server.git.InsertedObject) ChangeIndexer(com.google.gerrit.server.index.change.ChangeIndexer) Map(java.util.Map) NoteDbUpdateManager(com.google.gerrit.server.notedb.NoteDbUpdateManager) Timer1(com.google.gerrit.metrics.Timer1) GerritServerConfig(com.google.gerrit.server.config.GerritServerConfig) TimeZone(java.util.TimeZone) Timestamp(java.sql.Timestamp) Collection(java.util.Collection) NullProgressMonitor(org.eclipse.jgit.lib.NullProgressMonitor) Preconditions.checkState(com.google.common.base.Preconditions.checkState) PersonIdent(org.eclipse.jgit.lib.PersonIdent) List(java.util.List) Nullable(com.google.gerrit.common.Nullable) ReviewDbWrapper(com.google.gerrit.reviewdb.server.ReviewDbWrapper) BatchRefUpdate(org.eclipse.jgit.lib.BatchRefUpdate) MetricMaker(com.google.gerrit.metrics.MetricMaker) NotesMigration(com.google.gerrit.server.notedb.NotesMigration) ListeningExecutorService(com.google.common.util.concurrent.ListeningExecutorService) Singleton(com.google.inject.Singleton) MoreExecutors(com.google.common.util.concurrent.MoreExecutors) ReviewDb(com.google.gerrit.reviewdb.server.ReviewDb) ListenableFuture(com.google.common.util.concurrent.ListenableFuture) Change(com.google.gerrit.reviewdb.client.Change) NANOSECONDS(java.util.concurrent.TimeUnit.NANOSECONDS) Stopwatch(com.google.common.base.Stopwatch) MismatchedStateException(com.google.gerrit.server.notedb.NoteDbUpdateManager.MismatchedStateException) Callable(java.util.concurrent.Callable) LockFailureException(com.google.gerrit.server.git.LockFailureException) ArrayList(java.util.ArrayList) ImmutableList(com.google.common.collect.ImmutableList) Description(com.google.gerrit.metrics.Description) Field(com.google.gerrit.metrics.Field) Comparator.comparing(java.util.Comparator.comparing) RestApiException(com.google.gerrit.extensions.restapi.RestApiException) Project(com.google.gerrit.reviewdb.client.Project) CurrentUser(com.google.gerrit.server.CurrentUser) Logger(org.slf4j.Logger) Preconditions.checkNotNull(com.google.common.base.Preconditions.checkNotNull) Units(com.google.gerrit.metrics.Description.Units) Throwables(com.google.common.base.Throwables) ChangeNotes(com.google.gerrit.server.notedb.ChangeNotes) IOException(java.io.IOException) SchemaFactory(com.google.gwtorm.server.SchemaFactory) NoteDbChangeState(com.google.gerrit.server.notedb.NoteDbChangeState) ExecutionException(java.util.concurrent.ExecutionException) Collectors.toList(java.util.stream.Collectors.toList) Futures(com.google.common.util.concurrent.Futures) ChangeUpdate(com.google.gerrit.server.notedb.ChangeUpdate) GitRepositoryManager(com.google.gerrit.server.git.GitRepositoryManager) TreeMap(java.util.TreeMap) ResourceConflictException(com.google.gerrit.extensions.restapi.ResourceConflictException) PatchSet(com.google.gerrit.reviewdb.client.PatchSet) Collections(java.util.Collections) GerritPersonIdent(com.google.gerrit.server.GerritPersonIdent) GitReferenceUpdated(com.google.gerrit.server.extensions.events.GitReferenceUpdated) Repository(org.eclipse.jgit.lib.Repository) ReceiveCommand(org.eclipse.jgit.transport.ReceiveCommand) InsertedObject(com.google.gerrit.server.git.InsertedObject) IOException(java.io.IOException) RevWalk(org.eclipse.jgit.revwalk.RevWalk) LockFailureException(com.google.gerrit.server.git.LockFailureException) Repository(org.eclipse.jgit.lib.Repository) ResourceConflictException(com.google.gerrit.extensions.restapi.ResourceConflictException) ObjectInserter(org.eclipse.jgit.lib.ObjectInserter) BatchRefUpdate(org.eclipse.jgit.lib.BatchRefUpdate)

Example 4 with LockFailureException

use of com.google.gerrit.server.git.LockFailureException in project gerrit by GerritCodeReview.

the class NoteDbUpdateManager method checkResults.

/**
   * Check results of all commands in the update batch, reducing to a single exception if there was
   * a failure.
   *
   * <p>Throws {@link LockFailureException} if at least one command failed with {@code
   * LOCK_FAILURE}, and the entire transaction was aborted, i.e. any non-{@code LOCK_FAILURE}
   * results, if there were any, failed with "transaction aborted".
   *
   * <p>In particular, if the underlying ref database does not {@link
   * org.eclipse.jgit.lib.RefDatabase#performsAtomicTransactions() perform atomic transactions},
   * then a combination of {@code LOCK_FAILURE} on one ref and {@code OK} or another result on other
   * refs will <em>not</em> throw {@code LockFailureException}.
   *
   * @param bru batch update; should already have been executed.
   * @throws LockFailureException if the transaction was aborted due to lock failure.
   * @throws IOException if any result was not {@code OK}.
   */
@VisibleForTesting
static void checkResults(BatchRefUpdate bru) throws LockFailureException, IOException {
    int lockFailure = 0;
    int aborted = 0;
    int failure = 0;
    for (ReceiveCommand cmd : bru.getCommands()) {
        if (cmd.getResult() != ReceiveCommand.Result.OK) {
            failure++;
        }
        if (cmd.getResult() == ReceiveCommand.Result.LOCK_FAILURE) {
            lockFailure++;
        } else if (cmd.getResult() == ReceiveCommand.Result.REJECTED_OTHER_REASON && JGitText.get().transactionAborted.equals(cmd.getMessage())) {
            aborted++;
        }
    }
    if (lockFailure + aborted == bru.getCommands().size()) {
        throw new LockFailureException("Update aborted with one or more lock failures: " + bru);
    } else if (failure > 0) {
        throw new IOException("Update failed: " + bru);
    }
}
Also used : ReceiveCommand(org.eclipse.jgit.transport.ReceiveCommand) IOException(java.io.IOException) LockFailureException(com.google.gerrit.server.git.LockFailureException) VisibleForTesting(com.google.common.annotations.VisibleForTesting)

Aggregations

LockFailureException (com.google.gerrit.server.git.LockFailureException)4 IOException (java.io.IOException)4 ImmutableList (com.google.common.collect.ImmutableList)2 MetricMaker (com.google.gerrit.metrics.MetricMaker)2 AllUsersName (com.google.gerrit.server.config.AllUsersName)2 ObjectId (org.eclipse.jgit.lib.ObjectId)2 ReceiveCommand (org.eclipse.jgit.transport.ReceiveCommand)2 BlockStrategy (com.github.rholder.retry.BlockStrategy)1 Retryer (com.github.rholder.retry.Retryer)1 RetryerBuilder (com.github.rholder.retry.RetryerBuilder)1 StopStrategies (com.github.rholder.retry.StopStrategies)1 VisibleForTesting (com.google.common.annotations.VisibleForTesting)1 Preconditions.checkNotNull (com.google.common.base.Preconditions.checkNotNull)1 Preconditions.checkState (com.google.common.base.Preconditions.checkState)1 Stopwatch (com.google.common.base.Stopwatch)1 Throwables (com.google.common.base.Throwables)1 ImmutableSet (com.google.common.collect.ImmutableSet)1 Iterables (com.google.common.collect.Iterables)1 Truth.assertThat (com.google.common.truth.Truth.assertThat)1 CheckedFuture (com.google.common.util.concurrent.CheckedFuture)1