Leverage accounts cache for authentication based on username
When looking up the external-id for an authentication request
based on username (gerrit: and username: schemes), we can actually
use the accounts cache indexed by username to retrieve the
corresponding external_id, avoiding to hit the DB every time.
Potentially the number of DB calls avoided can be huge when
authentication is triggered on HTTP-based API or Git protocol.
Change-Id: Ia656120013352d76e97d12c9bf3b9efbda186e0f
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountManager.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountManager.java
index 7940219..d7b9342 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountManager.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountManager.java
@@ -38,6 +38,7 @@
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -106,7 +107,7 @@
try {
try (ReviewDb db = schema.open()) {
AccountExternalId.Key key = id(who);
- AccountExternalId id = db.accountExternalIds().get(key);
+ AccountExternalId id = getAccountExternalId(db, key);
if (id == null) {
// New account, automatically create and return.
//
@@ -130,6 +131,32 @@
}
}
+ private AccountExternalId getAccountExternalId(ReviewDb db,
+ AccountExternalId.Key key) throws OrmException {
+ String keyValue = key.get();
+ String keyScheme = keyValue.substring(0, keyValue.indexOf(':') + 1);
+
+ // We don't have at the moment an account_by_external_id cache
+ // but by using the accounts cache we get the list of external_ids
+ // without having to query the DB every time
+ if (keyScheme.equals(AccountExternalId.SCHEME_GERRIT)
+ || keyScheme.equals(AccountExternalId.SCHEME_USERNAME)) {
+ String username = keyValue.substring(keyScheme.length());
+ Collection<AccountExternalId> externalIds =
+ byIdCache.getByUsername(username).getExternalIds();
+ for (AccountExternalId accountExternalId : externalIds) {
+ if (accountExternalId.isScheme(keyScheme)) {
+ return accountExternalId;
+ }
+ }
+
+ log.warn(
+ "Cannot find account external id for user {} in cache, possibly a stale entry",
+ username);
+ }
+ return db.accountExternalIds().get(key);
+ }
+
private void update(ReviewDb db, AuthRequest who, AccountExternalId extId)
throws OrmException, NameAlreadyUsedException, InvalidUserNameException {
IdentifiedUser user = userFactory.create(extId.getAccountId());
@@ -324,7 +351,7 @@
who = realm.link(db, to, who);
AccountExternalId.Key key = id(who);
- AccountExternalId extId = db.accountExternalIds().get(key);
+ AccountExternalId extId = getAccountExternalId(db, key);
if (extId != null) {
if (!extId.getAccountId().equals(to)) {
throw new AccountException("Identity in use by another account");
@@ -415,7 +442,7 @@
who = realm.unlink(db, from, who);
AccountExternalId.Key key = id(who);
- AccountExternalId extId = db.accountExternalIds().get(key);
+ AccountExternalId extId = getAccountExternalId(db, key);
if (extId != null) {
if (!extId.getAccountId().equals(from)) {
throw new AccountException("Identity in use by another account");