Make PrologEnvironment ~6500% faster

Instead of passing the Injector use a singleton Args object that wraps
up all of the singletons needed in prolog predicates.

This offers less flexibility to plugin predicates but gets rid of a
potential Guice problem.  The claimed performance difference may not
exist, but a warning message is removed on startup.

Change-Id: Iceba5d4fb7f75eb867c6a968e5f43912e2213837
This commit is contained in:
Shawn Pearce
2013-08-05 16:40:04 -07:00
parent 242a604b9f
commit 9b24f90849
7 changed files with 89 additions and 21 deletions

View File

@@ -14,8 +14,15 @@
package com.google.gerrit.rules; package com.google.gerrit.rules;
import com.google.gerrit.server.AnonymousUser;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.patch.PatchListCache;
import com.google.gerrit.server.patch.PatchSetInfoFactory;
import com.google.gerrit.server.project.ProjectCache;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Injector; import com.google.inject.Provider;
import com.google.inject.Singleton;
import com.google.inject.assistedinject.Assisted; import com.google.inject.assistedinject.Assisted;
import com.googlecode.prolog_cafe.lang.BufferingPrologControl; import com.googlecode.prolog_cafe.lang.BufferingPrologControl;
@@ -56,23 +63,22 @@ public class PrologEnvironment extends BufferingPrologControl {
PrologEnvironment create(PrologMachineCopy src); PrologEnvironment create(PrologMachineCopy src);
} }
private final Injector injector; private final Args args;
private final Map<StoredValue<Object>, Object> storedValues; private final Map<StoredValue<Object>, Object> storedValues;
private List<Runnable> cleanup; private List<Runnable> cleanup;
@Inject @Inject
PrologEnvironment(Injector i, @Assisted PrologMachineCopy src) { PrologEnvironment(Args a, @Assisted PrologMachineCopy src) {
super(src); super(src);
injector = i;
setMaxArity(MAX_ARITY); setMaxArity(MAX_ARITY);
setEnabled(EnumSet.allOf(Prolog.Feature.class), false); setEnabled(EnumSet.allOf(Prolog.Feature.class), false);
args = a;
storedValues = new HashMap<StoredValue<Object>, Object>(); storedValues = new HashMap<StoredValue<Object>, Object>();
cleanup = new LinkedList<Runnable>(); cleanup = new LinkedList<Runnable>();
} }
/** Get the global Guice Injector that configured the environment. */ public Args getArgs() {
public Injector getInjector() { return args;
return injector;
} }
/** /**
@@ -139,4 +145,53 @@ public class PrologEnvironment extends BufferingPrologControl {
i.remove(); i.remove();
} }
} }
}
@Singleton
public static class Args {
private final ProjectCache projectCache;
private final GitRepositoryManager repositoryManager;
private final PatchListCache patchListCache;
private final PatchSetInfoFactory patchSetInfoFactory;
private final IdentifiedUser.GenericFactory userFactory;
private final Provider<AnonymousUser> anonymousUser;
@Inject
Args(ProjectCache projectCache,
GitRepositoryManager repositoryManager,
PatchListCache patchListCache,
PatchSetInfoFactory patchSetInfoFactory,
IdentifiedUser.GenericFactory userFactory,
Provider<AnonymousUser> anonymousUser) {
this.projectCache = projectCache;
this.repositoryManager = repositoryManager;
this.patchListCache = patchListCache;
this.patchSetInfoFactory = patchSetInfoFactory;
this.userFactory = userFactory;
this.anonymousUser = anonymousUser;
}
public ProjectCache getProjectCache() {
return projectCache;
}
public GitRepositoryManager getGitRepositoryManager() {
return repositoryManager;
}
public PatchListCache getPatchListCache() {
return patchListCache;
}
public PatchSetInfoFactory getPatchSetInfoFactory() {
return patchSetInfoFactory;
}
public IdentifiedUser.GenericFactory getUserFactory() {
return userFactory;
}
public AnonymousUser getAnonymousUser() {
return anonymousUser.get();
}
}
}

View File

@@ -20,7 +20,15 @@ import com.google.gerrit.server.config.FactoryModule;
public class PrologModule extends FactoryModule { public class PrologModule extends FactoryModule {
@Override @Override
protected void configure() { protected void configure() {
DynamicSet.setOf(binder(), PredicateProvider.class); install(new EnviromentModule());
factory(PrologEnvironment.Factory.class); bind(PrologEnvironment.Args.class);
}
static class EnviromentModule extends FactoryModule {
@Override
protected void configure() {
DynamicSet.setOf(binder(), PredicateProvider.class);
factory(PrologEnvironment.Factory.class);
}
} }
} }

View File

@@ -60,7 +60,7 @@ public final class StoredValues {
PatchSet ps = StoredValues.PATCH_SET.get(engine); PatchSet ps = StoredValues.PATCH_SET.get(engine);
PrologEnvironment env = (PrologEnvironment) engine.control; PrologEnvironment env = (PrologEnvironment) engine.control;
PatchSetInfoFactory patchInfoFactory = PatchSetInfoFactory patchInfoFactory =
env.getInjector().getInstance(PatchSetInfoFactory.class); env.getArgs().getPatchSetInfoFactory();
try { try {
return patchInfoFactory.get(change, ps); return patchInfoFactory.get(change, ps);
} catch (PatchSetInfoNotAvailableException e) { } catch (PatchSetInfoNotAvailableException e) {
@@ -74,7 +74,7 @@ public final class StoredValues {
public PatchList createValue(Prolog engine) { public PatchList createValue(Prolog engine) {
PrologEnvironment env = (PrologEnvironment) engine.control; PrologEnvironment env = (PrologEnvironment) engine.control;
PatchSetInfo psInfo = StoredValues.PATCH_SET_INFO.get(engine); PatchSetInfo psInfo = StoredValues.PATCH_SET_INFO.get(engine);
PatchListCache plCache = env.getInjector().getInstance(PatchListCache.class); PatchListCache plCache = env.getArgs().getPatchListCache();
Change change = StoredValues.CHANGE.get(engine); Change change = StoredValues.CHANGE.get(engine);
Project.NameKey projectKey = change.getProject(); Project.NameKey projectKey = change.getProject();
ObjectId a = null; ObjectId a = null;
@@ -95,8 +95,7 @@ public final class StoredValues {
@Override @Override
public Repository createValue(Prolog engine) { public Repository createValue(Prolog engine) {
PrologEnvironment env = (PrologEnvironment) engine.control; PrologEnvironment env = (PrologEnvironment) engine.control;
GitRepositoryManager gitMgr = GitRepositoryManager gitMgr = env.getArgs().getGitRepositoryManager();
env.getInjector().getInstance(GitRepositoryManager.class);
Change change = StoredValues.CHANGE.get(engine); Change change = StoredValues.CHANGE.get(engine);
Project.NameKey projectKey = change.getProject(); Project.NameKey projectKey = change.getProject();
final Repository repo; final Repository repo;
@@ -122,7 +121,7 @@ public final class StoredValues {
@Override @Override
protected AnonymousUser createValue(Prolog engine) { protected AnonymousUser createValue(Prolog engine) {
PrologEnvironment env = (PrologEnvironment) engine.control; PrologEnvironment env = (PrologEnvironment) engine.control;
return env.getInjector().getInstance(AnonymousUser.class); return env.getArgs().getAnonymousUser();
} }
}; };

View File

@@ -112,7 +112,6 @@ class PRED_current_user_2 extends Predicate.P2 {
} }
private static IdentifiedUser.GenericFactory userFactory(Prolog engine) { private static IdentifiedUser.GenericFactory userFactory(Prolog engine) {
PrologEnvironment env = (PrologEnvironment) engine.control; return ((PrologEnvironment) engine.control).getArgs().getUserFactory();
return env.getInjector().getInstance(IdentifiedUser.GenericFactory.class);
} }
} }

View File

@@ -17,7 +17,6 @@ package gerrit;
import com.google.gerrit.common.data.LabelType; import com.google.gerrit.common.data.LabelType;
import com.google.gerrit.rules.PrologEnvironment; import com.google.gerrit.rules.PrologEnvironment;
import com.google.gerrit.rules.StoredValues; import com.google.gerrit.rules.StoredValues;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectState; import com.google.gerrit.server.project.ProjectState;
import com.googlecode.prolog_cafe.lang.IntegerTerm; import com.googlecode.prolog_cafe.lang.IntegerTerm;
@@ -55,7 +54,7 @@ class PRED_get_legacy_label_types_1 extends Predicate.P1 {
Term a1 = arg1.dereference(); Term a1 = arg1.dereference();
PrologEnvironment env = (PrologEnvironment) engine.control; PrologEnvironment env = (PrologEnvironment) engine.control;
ProjectState state = env.getInjector().getInstance(ProjectCache.class) ProjectState state = env.getArgs().getProjectCache()
.get(StoredValues.CHANGE.get(engine).getDest().getParentKey()); .get(StoredValues.CHANGE.get(engine).getDest().getParentKey());
if (state == null) { if (state == null) {
return engine.fail(); return engine.fail();

View File

@@ -49,7 +49,15 @@ public class GerritCommonTest extends PrologTestCase {
load("gerrit", "gerrit_common_test.pl", new AbstractModule() { load("gerrit", "gerrit_common_test.pl", new AbstractModule() {
@Override @Override
protected void configure() { protected void configure() {
bind(ProjectCache.class).toInstance(projects); bind(PrologEnvironment.Args.class).toInstance(
new PrologEnvironment.Args(
projects,
null,
null,
null,
null,
null
));
} }
}); });
} }

View File

@@ -55,7 +55,7 @@ public abstract class PrologTestCase extends TestCase {
protected void load(String pkg, String prologResource, Module... modules) protected void load(String pkg, String prologResource, Module... modules)
throws CompileException, IOException { throws CompileException, IOException {
ArrayList<Module> moduleList = new ArrayList<Module>(); ArrayList<Module> moduleList = new ArrayList<Module>();
moduleList.add(new PrologModule()); moduleList.add(new PrologModule.EnviromentModule());
moduleList.addAll(Arrays.asList(modules)); moduleList.addAll(Arrays.asList(modules));
envFactory = Guice.createInjector(moduleList) envFactory = Guice.createInjector(moduleList)