Add schema migration to delete user branches for which no account exists

Before change I4fde3560c we didn't delete the user branch when an
account was deleted. This means we may have collected some orphaned user
branches and the schema migration cleans them up. After change
I4fde3560c we should not get any new orphaned user branches, so this is
a one time cleanup.

Change-Id: I1d592ba7a724da8b910888832dbbe9059b2a788c
Signed-off-by: Edwin Kempin <ekempin@google.com>
This commit is contained in:
Edwin Kempin
2017-04-13 14:32:34 +02:00
parent 85d3341678
commit 2f96635ca4
3 changed files with 96 additions and 16 deletions

View File

@@ -225,22 +225,27 @@ public class AccountsUpdate {
private void deleteUserBranch(Account.Id accountId) throws IOException {
try (Repository repo = repoManager.openRepository(allUsersName)) {
String refName = RefNames.refsUsers(accountId);
Ref ref = repo.exactRef(refName);
if (ref == null) {
return;
}
deleteUserBranch(repo, committerIdent, accountId);
}
}
RefUpdate ru = repo.updateRef(refName);
ru.setExpectedOldObjectId(ref.getObjectId());
ru.setNewObjectId(ObjectId.zeroId());
ru.setForceUpdate(true);
ru.setRefLogIdent(committerIdent);
ru.setRefLogMessage("Delete Account", true);
Result result = ru.delete();
if (result != Result.FORCED) {
throw new IOException(String.format("Failed to delete ref %s: %s", refName, result.name()));
}
public static void deleteUserBranch(
Repository repo, PersonIdent refLogIdent, Account.Id accountId) throws IOException {
String refName = RefNames.refsUsers(accountId);
Ref ref = repo.exactRef(refName);
if (ref == null) {
return;
}
RefUpdate ru = repo.updateRef(refName);
ru.setExpectedOldObjectId(ref.getObjectId());
ru.setNewObjectId(ObjectId.zeroId());
ru.setForceUpdate(true);
ru.setRefLogIdent(refLogIdent);
ru.setRefLogMessage("Delete Account", true);
Result result = ru.delete();
if (result != Result.FORCED) {
throw new IOException(String.format("Failed to delete ref %s: %s", refName, result.name()));
}
}
}

View File

@@ -35,7 +35,7 @@ import java.util.concurrent.TimeUnit;
/** A version of the database schema. */
public abstract class SchemaVersion {
/** The current schema version. */
public static final Class<Schema_146> C = Schema_146.class;
public static final Class<Schema_147> C = Schema_147.class;
public static int getBinaryVersion() {
return guessVersion(C);

View File

@@ -0,0 +1,75 @@
// Copyright (C) 2017 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.server.schema;
import static java.util.stream.Collectors.toSet;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.account.AccountsUpdate;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Objects;
import java.util.Set;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Repository;
/** Delete user branches for which no account exists. */
public class Schema_147 extends SchemaVersion {
private final GitRepositoryManager repoManager;
private final AllUsersName allUsersName;
private final PersonIdent serverIdent;
@Inject
Schema_147(
Provider<Schema_146> prior,
GitRepositoryManager repoManager,
AllUsersName allUsersName,
@GerritPersonIdent PersonIdent serverIdent) {
super(prior);
this.repoManager = repoManager;
this.allUsersName = allUsersName;
this.serverIdent = serverIdent;
}
@Override
protected void migrateData(ReviewDb db, UpdateUI ui) throws OrmException, SQLException {
try (Repository repo = repoManager.openRepository(allUsersName)) {
Set<Account.Id> accountIdsFromReviewDb =
db.accounts().all().toList().stream().map(a -> a.getId()).collect(toSet());
Set<Account.Id> accountIdsFromUserBranches =
repo.getRefDatabase()
.getRefs(RefNames.REFS_USERS)
.values()
.stream()
.map(r -> Account.Id.fromRef(r.getName()))
.filter(Objects::nonNull)
.collect(toSet());
accountIdsFromUserBranches.removeAll(accountIdsFromReviewDb);
for (Account.Id accountId : accountIdsFromUserBranches) {
AccountsUpdate.deleteUserBranch(repo, serverIdent, accountId);
}
} catch (IOException e) {
throw new OrmException("Failed to delete user branches for non-existing accounts.", e);
}
}
}