Merge changes I6984e3c9,Id5689dc5,Ie25b44c5,I51dcca79,I23b9f69c * changes: Don't index missing accounts AccountCache: Remove unused getIfPresent ExternalIdsConsistencyChecker: Use AccountCache#getOrNull to check if account exists AccountCache: Add getOrNull method that returns null for missing account AccountCache: Document get and getIfPresent methods
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountCache.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountCache.java index c28021c..0a154c9b 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountCache.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountCache.java
@@ -14,14 +14,33 @@ package com.google.gerrit.server.account; +import com.google.gerrit.common.Nullable; import com.google.gerrit.reviewdb.client.Account; import java.io.IOException; /** Caches important (but small) account state to avoid database hits. */ public interface AccountCache { + /** + * Returns an {@code AccountState} instance for the given account ID. If not cached yet the + * account is loaded. Returns an empty {@code AccountState} instance to represent a missing + * account. + * + * @param accountId ID of the account that should be retrieved + * @return {@code AccountState} instance for the given account ID, if no account with this ID + * exists an empty {@code AccountState} instance is returned to represent the missing account + */ AccountState get(Account.Id accountId); - AccountState getIfPresent(Account.Id accountId); + /** + * Returns an {@code AccountState} instance for the given account ID. If not cached yet the + * account is loaded. Returns {@code null} if the account is missing. + * + * @param accountId ID of the account that should be retrieved + * @return {@code AccountState} instance for the given account ID, if no account with this ID + * exists {@code null} is returned + */ + @Nullable + AccountState getOrNull(Account.Id accountId); AccountState getByUsername(String username);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountCacheImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountCacheImpl.java index 866a423..12fc938 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountCacheImpl.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountCacheImpl.java
@@ -19,6 +19,7 @@ import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableSet; +import com.google.gerrit.common.Nullable; import com.google.gerrit.common.TimeUtil; import com.google.gerrit.extensions.client.GeneralPreferencesInfo; import com.google.gerrit.reviewdb.client.Account; @@ -62,7 +63,8 @@ return new CacheModule() { @Override protected void configure() { - cache(BYID_NAME, Account.Id.class, AccountState.class).loader(ByIdLoader.class); + cache(BYID_NAME, Account.Id.class, new TypeLiteral<Optional<AccountState>>() {}) + .loader(ByIdLoader.class); cache(BYUSER_NAME, String.class, new TypeLiteral<Optional<Account.Id>>() {}) .loader(ByNameLoader.class); @@ -73,13 +75,13 @@ }; } - private final LoadingCache<Account.Id, AccountState> byId; + private final LoadingCache<Account.Id, Optional<AccountState>> byId; private final LoadingCache<String, Optional<Account.Id>> byName; private final Provider<AccountIndexer> indexer; @Inject AccountCacheImpl( - @Named(BYID_NAME) LoadingCache<Account.Id, AccountState> byId, + @Named(BYID_NAME) LoadingCache<Account.Id, Optional<AccountState>> byId, @Named(BYUSER_NAME) LoadingCache<String, Optional<Account.Id>> byUsername, Provider<AccountIndexer> indexer) { this.byId = byId; @@ -90,7 +92,7 @@ @Override public AccountState get(Account.Id accountId) { try { - return byId.get(accountId); + return byId.get(accountId).orElse(missing(accountId)); } catch (ExecutionException e) { log.warn("Cannot load AccountState for " + accountId, e); return missing(accountId); @@ -98,15 +100,21 @@ } @Override - public AccountState getIfPresent(Account.Id accountId) { - return byId.getIfPresent(accountId); + @Nullable + public AccountState getOrNull(Account.Id accountId) { + try { + return byId.get(accountId).orElse(null); + } catch (ExecutionException e) { + log.warn("Cannot load AccountState for " + accountId, e); + return null; + } } @Override public AccountState getByUsername(String username) { try { Optional<Account.Id> id = byName.get(username); - return id != null && id.isPresent() ? byId.get(id.get()) : null; + return id != null && id.isPresent() ? getOrNull(id.get()) : null; } catch (ExecutionException e) { log.warn("Cannot load AccountState for " + username, e); return null; @@ -144,7 +152,7 @@ account, anon, Collections.emptySet(), new HashMap<ProjectWatchKey, Set<NotifyType>>()); } - static class ByIdLoader extends CacheLoader<Account.Id, AccountState> { + static class ByIdLoader extends CacheLoader<Account.Id, Optional<AccountState>> { private final SchemaFactory<ReviewDb> schema; private final GroupCache groupCache; private final GeneralPreferencesLoader loader; @@ -169,23 +177,25 @@ } @Override - public AccountState load(Account.Id key) throws Exception { + public Optional<AccountState> load(Account.Id key) throws Exception { try (ReviewDb db = schema.open()) { - final AccountState state = load(db, key); - String user = state.getUserName(); + Optional<AccountState> state = load(db, key); + if (!state.isPresent()) { + return state; + } + String user = state.get().getUserName(); if (user != null) { - byName.put(user, Optional.of(state.getAccount().getId())); + byName.put(user, Optional.of(state.get().getAccount().getId())); } return state; } } - private AccountState load(final ReviewDb db, final Account.Id who) + private Optional<AccountState> load(final ReviewDb db, final Account.Id who) throws OrmException, IOException, ConfigInvalidException { Account account = db.accounts().get(who); if (account == null) { - // Account no longer exists? They are anonymous. - return missing(who); + return Optional.empty(); } Set<AccountGroup.UUID> internalGroups = new HashSet<>(); @@ -205,11 +215,12 @@ account.setGeneralPreferences(GeneralPreferencesInfo.defaults()); } - return new AccountState( - account, - internalGroups, - externalIds.byAccount(who), - watchConfig.get().getProjectWatches(who)); + return Optional.of( + new AccountState( + account, + internalGroups, + externalIds.byAccount(who), + watchConfig.get().getProjectWatches(who))); } }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/externalids/ExternalIdsConsistencyChecker.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/externalids/ExternalIdsConsistencyChecker.java index 928349d..f74210f 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/account/externalids/ExternalIdsConsistencyChecker.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/externalids/ExternalIdsConsistencyChecker.java
@@ -120,7 +120,7 @@ private List<ConsistencyProblemInfo> validateExternalId(ExternalId extId) { List<ConsistencyProblemInfo> problems = new ArrayList<>(); - if (accountCache.getIfPresent(extId.accountId()) == null) { + if (accountCache.getOrNull(extId.accountId()) == null) { addError( String.format( "External ID '%s' belongs to account that doesn't exist: %s",
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/account/AccountIndexerImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/account/AccountIndexerImpl.java index 58dbd34..8796360 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/index/account/AccountIndexerImpl.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/account/AccountIndexerImpl.java
@@ -64,8 +64,13 @@ @Override public void index(Account.Id id) throws IOException { - for (Index<?, AccountState> i : getWriteIndexes()) { - i.replace(byIdCache.get(id)); + for (Index<Account.Id, AccountState> i : getWriteIndexes()) { + AccountState accountState = byIdCache.getOrNull(id); + if (accountState != null) { + i.replace(accountState); + } else { + i.delete(id); + } } fireAccountIndexedEvent(id.get()); }
diff --git a/gerrit-server/src/test/java/com/google/gerrit/testutil/FakeAccountCache.java b/gerrit-server/src/test/java/com/google/gerrit/testutil/FakeAccountCache.java index d81d441..066b7b1 100644 --- a/gerrit-server/src/test/java/com/google/gerrit/testutil/FakeAccountCache.java +++ b/gerrit-server/src/test/java/com/google/gerrit/testutil/FakeAccountCache.java
@@ -15,6 +15,7 @@ package com.google.gerrit.testutil; import com.google.common.collect.ImmutableSet; +import com.google.gerrit.common.Nullable; import com.google.gerrit.common.TimeUtil; import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.server.account.AccountCache; @@ -34,7 +35,7 @@ @Override public synchronized AccountState get(Account.Id accountId) { - AccountState state = getIfPresent(accountId); + AccountState state = byId.get(accountId); if (state != null) { return state; } @@ -42,7 +43,8 @@ } @Override - public synchronized AccountState getIfPresent(Account.Id accountId) { + @Nullable + public synchronized AccountState getOrNull(Account.Id accountId) { return byId.get(accountId); }