Cache effective capabilities to improve lookup performance

Instead of scanning through the AccessSection from All-Projects on
every request, cache most of the lookup work inside of a (mostly)
singleton CapabilityCollection available through the All-Projects
ProjectState.

This allows us to reuse the indexing of which groups have the
Administrate Server capability, making it faster to conclude if
the current user is an administrator.  Since nearly all access
control decisions wind up with an "OR is administrator" this is
an important check to optimize since many of those checks return
false without user-level errors.

Critically, the lookup for queryLimit is improved by only doing
a lookup for the capability requested, rather than all of them.
Web UI navigations need to locate the user's query limit to find the
page size that can be returned to the web UI, but typically these
only need to perform that one capability test and do not need the
other available capabilities.  Deferring lookup of an effective
capability to always be on-demand improves this one very common case.

Change-Id: I2b744f5a6b4adfc017b33072c7f644692383d855
This commit is contained in:
Shawn O. Pearce
2011-06-22 12:25:21 -07:00
parent bc0916318c
commit 106796c589
3 changed files with 180 additions and 75 deletions

View File

@@ -23,6 +23,7 @@ import com.google.gerrit.reviewdb.Project;
import com.google.gerrit.rules.PrologEnvironment;
import com.google.gerrit.rules.RulesCache;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.account.CapabilityCollection;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.ProjectConfig;
@@ -65,6 +66,8 @@ public class ProjectState {
/** Last system time the configuration's revision was examined. */
private volatile long lastCheckTime;
/** If this is all projects, the capabilities used by the server. */
private final CapabilityCollection capabilities;
@Inject
protected ProjectState(
@@ -82,6 +85,9 @@ public class ProjectState {
this.gitMgr = gitMgr;
this.rulesCache = rulesCache;
this.config = config;
this.capabilities = isAllProjects
? new CapabilityCollection(config.getAccessSection(AccessSection.GLOBAL_CAPABILITIES))
: null;
HashSet<AccountGroup.UUID> groups = new HashSet<AccountGroup.UUID>();
AccessSection all = config.getAccessSection(AccessSection.ALL);
@@ -127,6 +133,15 @@ public class ProjectState {
}
}
/**
* @return cached computation of all global capabilities. This should only be
* invoked on the state from {@link ProjectCache#getAllProjects()}.
* Null on any other project.
*/
public CapabilityCollection getCapabilityCollection() {
return capabilities;
}
/** @return Construct a new PrologEnvironment for the calling thread. */
public PrologEnvironment newPrologEnvironment() throws CompileException {
PrologMachineCopy pmc = rulesMachine;