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:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user