Test that read-modify-write is atomic on account updates
When updating an account the account updater gets the current AccountState provided so that based on this account state it can be decided which update should be done. If a concurrent request updates the account after the account updater is invoked it is expected that the account update fails with LockFailure because the HEAD of the user branch was updated and no longer matches the revision from which the account was read. The LockFailure then causes a retry of the account update and the account updater is invoked again, this time with a new AccountState that includes the modifications that were done by the concurrent update. This way the full read-modify-write sequence is atomic on account updates. Change-Id: Ia570cd2e99557bf942c1571eae3ef72dd07663dd Signed-off-by: Edwin Kempin <ekempin@google.com>
This commit is contained in:
@@ -285,8 +285,13 @@ public class AccountsUpdate {
|
||||
private final ExternalIdNotesLoader extIdNotesLoader;
|
||||
private final PersonIdent committerIdent;
|
||||
private final PersonIdent authorIdent;
|
||||
|
||||
// Invoked after reading the account config.
|
||||
private final Runnable afterReadRevision;
|
||||
|
||||
// Invoked after updating the account but before committing the changes.
|
||||
private final Runnable beforeCommit;
|
||||
|
||||
private AccountsUpdate(
|
||||
GitRepositoryManager repoManager,
|
||||
GitReferenceUpdated gitRefUpdated,
|
||||
@@ -309,6 +314,7 @@ public class AccountsUpdate {
|
||||
extIdNotesLoader,
|
||||
committerIdent,
|
||||
authorIdent,
|
||||
Runnables.doNothing(),
|
||||
Runnables.doNothing());
|
||||
}
|
||||
|
||||
@@ -324,7 +330,8 @@ public class AccountsUpdate {
|
||||
ExternalIdNotesLoader extIdNotesLoader,
|
||||
PersonIdent committerIdent,
|
||||
PersonIdent authorIdent,
|
||||
Runnable afterReadRevision) {
|
||||
Runnable afterReadRevision,
|
||||
Runnable beforeCommit) {
|
||||
this.repoManager = checkNotNull(repoManager, "repoManager");
|
||||
this.gitRefUpdated = checkNotNull(gitRefUpdated, "gitRefUpdated");
|
||||
this.currentUser = currentUser;
|
||||
@@ -336,7 +343,8 @@ public class AccountsUpdate {
|
||||
this.extIdNotesLoader = checkNotNull(extIdNotesLoader, "extIdNotesLoader");
|
||||
this.committerIdent = checkNotNull(committerIdent, "committerIdent");
|
||||
this.authorIdent = checkNotNull(authorIdent, "authorIdent");
|
||||
this.afterReadRevision = afterReadRevision;
|
||||
this.afterReadRevision = checkNotNull(afterReadRevision, "afterReadRevision");
|
||||
this.beforeCommit = checkNotNull(beforeCommit, "beforeCommit");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -491,6 +499,8 @@ public class AccountsUpdate {
|
||||
}
|
||||
|
||||
private void commit(Repository allUsersRepo, UpdatedAccount updatedAccount) throws IOException {
|
||||
beforeCommit.run();
|
||||
|
||||
BatchRefUpdate batchRefUpdate = allUsersRepo.getRefDatabase().newBatchUpdate();
|
||||
if (updatedAccount.isCreated()) {
|
||||
commitNewAccountConfig(
|
||||
|
Reference in New Issue
Block a user