Merge changes from topic "no-refs-for-permissions"

* changes:
  Migrate refs/for after all sections and permissions are loaded.
  PUSH_MERGE should evaluate against refs/heads/*
  ADD_PATCH_SET should evaluate against refs/heads/*
  "Submit on Push" option on Submit Perm.
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index a9abd53..ae7dfd54 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -2718,7 +2718,9 @@
 +
 * `ELASTICSEARCH` look into link:#elasticsearch[Elasticsearch section]
 +
-An link:http://www.elasticsearch.org/[Elasticsearch] index is used.
+An link:https://www.elastic.co/products/elasticsearch[Elasticsearch] index is
+used. Refer to the link:#elasticsearch[Elasticsearch section] for further
+configuration details.
 
 +
 By default, `LUCENE`.
@@ -2929,8 +2931,8 @@
 [[elasticsearch]]
 === Section elasticsearch
 
-WARNING: The Elasticsearch support is incomplete. Online reindexing
-is still considered as beta.
+WARNING: The Elasticsearch support has only been tested with Elasticsearch
+version 2.4.x. Support for other versions is not guaranteed.
 
 Open and closed changes are indexed in a single index, separated
 into types 'open_changes' and 'closed_changes' respectively.
diff --git a/Documentation/user-search.txt b/Documentation/user-search.txt
index 69a75c9..bebe81b 100644
--- a/Documentation/user-search.txt
+++ b/Documentation/user-search.txt
@@ -31,13 +31,15 @@
 |Full or abbreviated Change-Id    | Ic0ff33
 |Full or abbreviated commit SHA-1 | d81b32ef
 |Email address                    | user@example.com
-|Approval requirement             | Code-Review>=+2, Verified=1
 |=============================================================
 
 For change searches (i.e. those using a numerical id, Change-Id, or commit
 SHA1), if the search results in a single change that change will be
 presented instead of a list.
 
+For more predictable results, use explicit search operators as described
+in the following section.
+
 [[search-operators]]
 == Search Operators
 
diff --git a/java/com/google/gerrit/httpd/init/BUILD b/java/com/google/gerrit/httpd/init/BUILD
index 9624241..f240088 100644
--- a/java/com/google/gerrit/httpd/init/BUILD
+++ b/java/com/google/gerrit/httpd/init/BUILD
@@ -19,6 +19,7 @@
         "//java/com/google/gerrit/server:module",
         "//java/com/google/gerrit/server/api",
         "//java/com/google/gerrit/server/cache/h2",
+        "//java/com/google/gerrit/server/cache/mem",
         "//java/com/google/gerrit/server/git/receive",
         "//java/com/google/gerrit/server/restapi",
         "//java/com/google/gerrit/server/schema",
diff --git a/java/com/google/gerrit/httpd/init/WebAppInitializer.java b/java/com/google/gerrit/httpd/init/WebAppInitializer.java
index 04d08e5..77677f8 100644
--- a/java/com/google/gerrit/httpd/init/WebAppInitializer.java
+++ b/java/com/google/gerrit/httpd/init/WebAppInitializer.java
@@ -45,7 +45,9 @@
 import com.google.gerrit.server.account.AccountDeactivator;
 import com.google.gerrit.server.account.InternalAccountDirectory;
 import com.google.gerrit.server.api.GerritApiModule;
-import com.google.gerrit.server.cache.h2.DefaultCacheFactory;
+import com.google.gerrit.server.cache.CacheOverrides;
+import com.google.gerrit.server.cache.h2.H2CacheModule;
+import com.google.gerrit.server.cache.mem.DefaultMemoryCacheModule;
 import com.google.gerrit.server.change.ChangeCleanupRunner;
 import com.google.gerrit.server.config.AuthConfig;
 import com.google.gerrit.server.config.AuthConfigModule;
@@ -336,7 +338,8 @@
     modules.add(new SearchingChangeCacheImpl.Module());
     modules.add(new InternalAccountDirectory.Module());
     modules.add(new DefaultPermissionBackendModule());
-    modules.add(new DefaultCacheFactory.Module());
+    modules.add(new DefaultMemoryCacheModule());
+    modules.add(new H2CacheModule());
     modules.add(cfgInjector.getInstance(MailReceiver.Module.class));
     modules.add(new SmtpEmailSender.Module());
     modules.add(new SignedTokenEmailTokenVerifier.Module());
@@ -384,9 +387,9 @@
     modules.add(new GarbageCollectionModule());
     modules.add(new ChangeCleanupRunner.Module());
     modules.add(new AccountDeactivator.Module());
-    modules.addAll(LibModuleLoader.loadModules(cfgInjector));
     modules.add(new DefaultProjectNameLockManager.Module());
-    return cfgInjector.createChildInjector(modules);
+    return cfgInjector.createChildInjector(
+        CacheOverrides.override(modules, LibModuleLoader.loadModules(cfgInjector)));
   }
 
   private Module createIndexModule() {
diff --git a/java/com/google/gerrit/pgm/BUILD b/java/com/google/gerrit/pgm/BUILD
index b5b513f..76421fc 100644
--- a/java/com/google/gerrit/pgm/BUILD
+++ b/java/com/google/gerrit/pgm/BUILD
@@ -37,6 +37,7 @@
         "//java/com/google/gerrit/server:module",
         "//java/com/google/gerrit/server/api",
         "//java/com/google/gerrit/server/cache/h2",
+        "//java/com/google/gerrit/server/cache/mem",
         "//java/com/google/gerrit/server/git/receive",
         "//java/com/google/gerrit/server/restapi",
         "//java/com/google/gerrit/server/schema",
diff --git a/java/com/google/gerrit/pgm/Daemon.java b/java/com/google/gerrit/pgm/Daemon.java
index 4cc7b52..be4e2e9 100644
--- a/java/com/google/gerrit/pgm/Daemon.java
+++ b/java/com/google/gerrit/pgm/Daemon.java
@@ -54,7 +54,9 @@
 import com.google.gerrit.server.account.InternalAccountDirectory;
 import com.google.gerrit.server.api.GerritApiModule;
 import com.google.gerrit.server.api.PluginApiModule;
-import com.google.gerrit.server.cache.h2.DefaultCacheFactory;
+import com.google.gerrit.server.cache.CacheOverrides;
+import com.google.gerrit.server.cache.h2.H2CacheModule;
+import com.google.gerrit.server.cache.mem.DefaultMemoryCacheModule;
 import com.google.gerrit.server.change.ChangeCleanupRunner;
 import com.google.gerrit.server.config.AuthConfig;
 import com.google.gerrit.server.config.AuthConfigModule;
@@ -422,7 +424,8 @@
     modules.add(new SearchingChangeCacheImpl.Module(slave));
     modules.add(new InternalAccountDirectory.Module());
     modules.add(new DefaultPermissionBackendModule());
-    modules.add(new DefaultCacheFactory.Module());
+    modules.add(new DefaultMemoryCacheModule());
+    modules.add(new H2CacheModule());
     modules.add(cfgInjector.getInstance(MailReceiver.Module.class));
     if (emailModule != null) {
       modules.add(emailModule);
@@ -478,7 +481,6 @@
       modules.add(new AccountDeactivator.Module());
       modules.add(new ChangeCleanupRunner.Module());
     }
-    modules.addAll(LibModuleLoader.loadModules(cfgInjector));
     if (migrateToNoteDb()) {
       modules.add(new OnlineNoteDbMigrator.Module(trial));
     }
@@ -487,7 +489,8 @@
     }
     modules.add(new LocalMergeSuperSetComputation.Module());
     modules.add(new DefaultProjectNameLockManager.Module());
-    return cfgInjector.createChildInjector(modules);
+    return cfgInjector.createChildInjector(
+        CacheOverrides.override(modules, LibModuleLoader.loadModules(cfgInjector)));
   }
 
   private boolean migrateToNoteDb() {
diff --git a/java/com/google/gerrit/pgm/util/BUILD b/java/com/google/gerrit/pgm/util/BUILD
index d6e44bd..91647fb 100644
--- a/java/com/google/gerrit/pgm/util/BUILD
+++ b/java/com/google/gerrit/pgm/util/BUILD
@@ -12,6 +12,7 @@
         "//java/com/google/gerrit/server",
         "//java/com/google/gerrit/server:module",
         "//java/com/google/gerrit/server/cache/h2",
+        "//java/com/google/gerrit/server/cache/mem",
         "//java/com/google/gerrit/server/git/receive",
         "//java/com/google/gerrit/server/restapi",
         "//java/com/google/gerrit/server/schema",
diff --git a/java/com/google/gerrit/pgm/util/BatchProgramModule.java b/java/com/google/gerrit/pgm/util/BatchProgramModule.java
index efd1bf4..17c7319 100644
--- a/java/com/google/gerrit/pgm/util/BatchProgramModule.java
+++ b/java/com/google/gerrit/pgm/util/BatchProgramModule.java
@@ -37,7 +37,8 @@
 import com.google.gerrit.server.account.Realm;
 import com.google.gerrit.server.account.externalids.ExternalIdModule;
 import com.google.gerrit.server.cache.CacheRemovalListener;
-import com.google.gerrit.server.cache.h2.DefaultCacheFactory;
+import com.google.gerrit.server.cache.h2.H2CacheModule;
+import com.google.gerrit.server.cache.mem.DefaultMemoryCacheModule;
 import com.google.gerrit.server.change.ChangeJson;
 import com.google.gerrit.server.change.ChangeKindCacheImpl;
 import com.google.gerrit.server.change.MergeabilityCacheImpl;
@@ -154,7 +155,8 @@
 
     install(new BatchGitModule());
     install(new DefaultPermissionBackendModule());
-    install(new DefaultCacheFactory.Module());
+    install(new DefaultMemoryCacheModule());
+    install(new H2CacheModule());
     install(new ExternalIdModule());
     install(new GroupModule());
     install(new NoteDbModule(cfg));
diff --git a/java/com/google/gerrit/server/cache/CacheImpl.java b/java/com/google/gerrit/server/cache/CacheImpl.java
new file mode 100644
index 0000000..f06f8d5
--- /dev/null
+++ b/java/com/google/gerrit/server/cache/CacheImpl.java
@@ -0,0 +1,34 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.cache;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+@Retention(RUNTIME)
+@Target(TYPE)
+@Inherited
+public @interface CacheImpl {
+  enum Type {
+    MEMORY,
+    PERSISTENT
+  }
+
+  Type type();
+}
diff --git a/java/com/google/gerrit/server/cache/CacheOverrides.java b/java/com/google/gerrit/server/cache/CacheOverrides.java
new file mode 100644
index 0000000..9008f7b
--- /dev/null
+++ b/java/com/google/gerrit/server/cache/CacheOverrides.java
@@ -0,0 +1,65 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.cache;
+
+import com.google.inject.Module;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public class CacheOverrides {
+  public static List<Module> override(List<Module> modules, List<Module> overrideCandidates) {
+    if (overrideCandidates == null || overrideCandidates.isEmpty()) {
+      return modules;
+    }
+
+    // group candidates by annotation existence
+    Map<Boolean, List<Module>> grouped =
+        overrideCandidates
+            .stream()
+            .collect(
+                Collectors.groupingBy(m -> m.getClass().getAnnotation(CacheImpl.class) != null));
+
+    // add all non annotated libs to modules list
+    List<Module> libs = grouped.get(Boolean.FALSE);
+    if (libs != null) {
+      modules.addAll(libs);
+    }
+
+    List<Module> overrides = grouped.get(Boolean.TRUE);
+    if (overrides == null) {
+      return modules;
+    }
+
+    // swipe cache implementation with alternative provided in lib
+    return modules
+        .stream()
+        .map(
+            m -> {
+              CacheImpl a = m.getClass().getAnnotation(CacheImpl.class);
+              if (a == null) {
+                return m;
+              }
+              return overrides
+                  .stream()
+                  .filter(o -> o.getClass().getAnnotation(CacheImpl.class).type() == a.type())
+                  .findFirst()
+                  .orElse(m);
+            })
+        .collect(Collectors.toList());
+  }
+
+  private CacheOverrides() {}
+}
diff --git a/java/com/google/gerrit/server/cache/h2/H2CacheBindingProxy.java b/java/com/google/gerrit/server/cache/h2/H2CacheBindingProxy.java
new file mode 100644
index 0000000..0d1cf20
--- /dev/null
+++ b/java/com/google/gerrit/server/cache/h2/H2CacheBindingProxy.java
@@ -0,0 +1,112 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.cache.h2;
+
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.Weigher;
+import com.google.gerrit.server.cache.CacheBinding;
+import com.google.gerrit.server.cache.h2.H2CacheImpl.ValueHolder;
+import com.google.inject.TypeLiteral;
+import java.util.concurrent.TimeUnit;
+
+class H2CacheBindingProxy<K, V> implements CacheBinding<K, V> {
+  private static final String MSG_NOT_SUPPORTED =
+      "This is read-only wrapper. Modifications are not supported";
+
+  private final CacheBinding<K, V> source;
+
+  H2CacheBindingProxy(CacheBinding<K, V> source) {
+    this.source = source;
+  }
+
+  @Override
+  public Long expireAfterWrite(TimeUnit unit) {
+    return source.expireAfterWrite(unit);
+  }
+
+  @SuppressWarnings("unchecked")
+  @Override
+  public Weigher<K, V> weigher() {
+    Weigher<K, V> weigher = source.weigher();
+    if (weigher == null) {
+      return null;
+    }
+
+    // introduce weigher that performs calculations
+    // on value that is being stored not on ValueHolder
+    return (Weigher<K, V>)
+        new Weigher<K, ValueHolder<V>>() {
+          @Override
+          public int weigh(K key, ValueHolder<V> value) {
+            return weigher.weigh(key, value.value);
+          }
+        };
+  }
+
+  @Override
+  public String name() {
+    return source.name();
+  }
+
+  @Override
+  public TypeLiteral<K> keyType() {
+    return source.keyType();
+  }
+
+  @Override
+  public TypeLiteral<V> valueType() {
+    return source.valueType();
+  }
+
+  @Override
+  public long maximumWeight() {
+    return source.maximumWeight();
+  }
+
+  @Override
+  public long diskLimit() {
+    return source.diskLimit();
+  }
+
+  @Override
+  public CacheLoader<K, V> loader() {
+    return source.loader();
+  }
+
+  @Override
+  public CacheBinding<K, V> maximumWeight(long weight) {
+    throw new RuntimeException(MSG_NOT_SUPPORTED);
+  }
+
+  @Override
+  public CacheBinding<K, V> diskLimit(long limit) {
+    throw new RuntimeException(MSG_NOT_SUPPORTED);
+  }
+
+  @Override
+  public CacheBinding<K, V> expireAfterWrite(long duration, TimeUnit durationUnits) {
+    throw new RuntimeException(MSG_NOT_SUPPORTED);
+  }
+
+  @Override
+  public CacheBinding<K, V> loader(Class<? extends CacheLoader<K, V>> clazz) {
+    throw new RuntimeException(MSG_NOT_SUPPORTED);
+  }
+
+  @Override
+  public CacheBinding<K, V> weigher(Class<? extends Weigher<K, V>> clazz) {
+    throw new RuntimeException(MSG_NOT_SUPPORTED);
+  }
+}
diff --git a/java/com/google/gerrit/server/cache/h2/H2CacheFactory.java b/java/com/google/gerrit/server/cache/h2/H2CacheFactory.java
index 065d3a1..2240c7d 100644
--- a/java/com/google/gerrit/server/cache/h2/H2CacheFactory.java
+++ b/java/com/google/gerrit/server/cache/h2/H2CacheFactory.java
@@ -21,6 +21,7 @@
 import com.google.gerrit.extensions.events.LifecycleListener;
 import com.google.gerrit.extensions.registration.DynamicMap;
 import com.google.gerrit.server.cache.CacheBinding;
+import com.google.gerrit.server.cache.MemoryCacheFactory;
 import com.google.gerrit.server.cache.PersistentCacheFactory;
 import com.google.gerrit.server.cache.h2.H2CacheImpl.SqlStore;
 import com.google.gerrit.server.cache.h2.H2CacheImpl.ValueHolder;
@@ -49,7 +50,7 @@
 class H2CacheFactory implements PersistentCacheFactory, LifecycleListener {
   private static final Logger log = LoggerFactory.getLogger(H2CacheFactory.class);
 
-  private final DefaultCacheFactory defaultFactory;
+  private final MemoryCacheFactory memCacheFactory;
   private final Config config;
   private final Path cacheDir;
   private final List<H2CacheImpl<?, ?>> caches;
@@ -61,11 +62,11 @@
 
   @Inject
   H2CacheFactory(
-      DefaultCacheFactory defaultCacheFactory,
+      MemoryCacheFactory memCacheFactory,
       @GerritServerConfig Config cfg,
       SitePaths site,
       DynamicMap<Cache<?, ?>> cacheMap) {
-    defaultFactory = defaultCacheFactory;
+    this.memCacheFactory = memCacheFactory;
     config = cfg;
     cacheDir = getCacheDir(site, cfg.getString("cache", null, "directory"));
     h2CacheSize = cfg.getLong("cache", null, "h2CacheSize", -1);
@@ -153,21 +154,19 @@
 
   @SuppressWarnings({"unchecked"})
   @Override
-  public <K, V> Cache<K, V> build(CacheBinding<K, V> def) {
-    long limit = config.getLong("cache", def.name(), "diskLimit", def.diskLimit());
+  public <K, V> Cache<K, V> build(CacheBinding<K, V> in) {
+    long limit = config.getLong("cache", in.name(), "diskLimit", in.diskLimit());
 
     if (cacheDir == null || limit <= 0) {
-      return defaultFactory.build(def);
+      return memCacheFactory.build(in);
     }
 
+    H2CacheBindingProxy<K, V> def = new H2CacheBindingProxy<>(in);
     SqlStore<K, V> store =
         newSqlStore(def.name(), def.keyType(), limit, def.expireAfterWrite(TimeUnit.SECONDS));
     H2CacheImpl<K, V> cache =
         new H2CacheImpl<>(
-            executor,
-            store,
-            def.keyType(),
-            (Cache<K, ValueHolder<V>>) defaultFactory.create(def, true).build());
+            executor, store, def.keyType(), (Cache<K, ValueHolder<V>>) memCacheFactory.build(def));
     synchronized (caches) {
       caches.add(cache);
     }
@@ -176,22 +175,24 @@
 
   @SuppressWarnings("unchecked")
   @Override
-  public <K, V> LoadingCache<K, V> build(CacheBinding<K, V> def, CacheLoader<K, V> loader) {
-    long limit = config.getLong("cache", def.name(), "diskLimit", def.diskLimit());
+  public <K, V> LoadingCache<K, V> build(CacheBinding<K, V> in, CacheLoader<K, V> loader) {
+    long limit = config.getLong("cache", in.name(), "diskLimit", in.diskLimit());
 
     if (cacheDir == null || limit <= 0) {
-      return defaultFactory.build(def, loader);
+      return memCacheFactory.build(in, loader);
     }
 
+    H2CacheBindingProxy<K, V> def = new H2CacheBindingProxy<>(in);
     SqlStore<K, V> store =
         newSqlStore(def.name(), def.keyType(), limit, def.expireAfterWrite(TimeUnit.SECONDS));
     Cache<K, ValueHolder<V>> mem =
         (Cache<K, ValueHolder<V>>)
-            defaultFactory
-                .create(def, true)
-                .build((CacheLoader<K, V>) new H2CacheImpl.Loader<>(executor, store, loader));
+            memCacheFactory.build(
+                def, (CacheLoader<K, V>) new H2CacheImpl.Loader<>(executor, store, loader));
     H2CacheImpl<K, V> cache = new H2CacheImpl<>(executor, store, def.keyType(), mem);
-    caches.add(cache);
+    synchronized (caches) {
+      caches.add(cache);
+    }
     return cache;
   }
 
diff --git a/java/com/google/gerrit/server/cache/h2/H2CacheModule.java b/java/com/google/gerrit/server/cache/h2/H2CacheModule.java
new file mode 100644
index 0000000..90ca7d6
--- /dev/null
+++ b/java/com/google/gerrit/server/cache/h2/H2CacheModule.java
@@ -0,0 +1,28 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.cache.h2;
+
+import com.google.gerrit.lifecycle.LifecycleModule;
+import com.google.gerrit.server.cache.CacheImpl;
+import com.google.gerrit.server.cache.PersistentCacheFactory;
+
+@CacheImpl(type = CacheImpl.Type.PERSISTENT)
+public class H2CacheModule extends LifecycleModule {
+  @Override
+  protected void configure() {
+    bind(PersistentCacheFactory.class).to(H2CacheFactory.class);
+    listener().to(H2CacheFactory.class);
+  }
+}
diff --git a/java/com/google/gerrit/server/cache/mem/BUILD b/java/com/google/gerrit/server/cache/mem/BUILD
new file mode 100644
index 0000000..ef297f1
--- /dev/null
+++ b/java/com/google/gerrit/server/cache/mem/BUILD
@@ -0,0 +1,12 @@
+java_library(
+    name = "mem",
+    srcs = glob(["*.java"]),
+    visibility = ["//visibility:public"],
+    deps = [
+        "//java/com/google/gerrit/extensions:api",
+        "//java/com/google/gerrit/server",
+        "//lib:guava",
+        "//lib/guice",
+        "//lib/jgit/org.eclipse.jgit:jgit",
+    ],
+)
diff --git a/java/com/google/gerrit/server/cache/h2/DefaultCacheFactory.java b/java/com/google/gerrit/server/cache/mem/DefaultMemoryCacheFactory.java
similarity index 71%
rename from java/com/google/gerrit/server/cache/h2/DefaultCacheFactory.java
rename to java/com/google/gerrit/server/cache/mem/DefaultMemoryCacheFactory.java
index e7eaa18..114e893 100644
--- a/java/com/google/gerrit/server/cache/h2/DefaultCacheFactory.java
+++ b/java/com/google/gerrit/server/cache/mem/DefaultMemoryCacheFactory.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.server.cache.h2;
+package com.google.gerrit.server.cache.mem;
 
 import com.google.common.base.Strings;
 import com.google.common.cache.Cache;
@@ -20,34 +20,21 @@
 import com.google.common.cache.CacheLoader;
 import com.google.common.cache.LoadingCache;
 import com.google.common.cache.Weigher;
-import com.google.gerrit.lifecycle.LifecycleModule;
 import com.google.gerrit.server.cache.CacheBinding;
 import com.google.gerrit.server.cache.ForwardingRemovalListener;
 import com.google.gerrit.server.cache.MemoryCacheFactory;
-import com.google.gerrit.server.cache.PersistentCacheFactory;
-import com.google.gerrit.server.cache.h2.H2CacheImpl.ValueHolder;
 import com.google.gerrit.server.config.ConfigUtil;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.inject.Inject;
 import java.util.concurrent.TimeUnit;
 import org.eclipse.jgit.lib.Config;
 
-public class DefaultCacheFactory implements MemoryCacheFactory {
-  public static class Module extends LifecycleModule {
-    @Override
-    protected void configure() {
-      factory(ForwardingRemovalListener.Factory.class);
-      bind(MemoryCacheFactory.class).to(DefaultCacheFactory.class);
-      bind(PersistentCacheFactory.class).to(H2CacheFactory.class);
-      listener().to(H2CacheFactory.class);
-    }
-  }
-
+class DefaultMemoryCacheFactory implements MemoryCacheFactory {
   private final Config cfg;
   private final ForwardingRemovalListener.Factory forwardingRemovalListenerFactory;
 
   @Inject
-  public DefaultCacheFactory(
+  DefaultMemoryCacheFactory(
       @GerritServerConfig Config config,
       ForwardingRemovalListener.Factory forwardingRemovalListenerFactory) {
     this.cfg = config;
@@ -56,16 +43,16 @@
 
   @Override
   public <K, V> Cache<K, V> build(CacheBinding<K, V> def) {
-    return create(def, false).build();
+    return create(def).build();
   }
 
   @Override
   public <K, V> LoadingCache<K, V> build(CacheBinding<K, V> def, CacheLoader<K, V> loader) {
-    return create(def, false).build(loader);
+    return create(def).build(loader);
   }
 
   @SuppressWarnings("unchecked")
-  <K, V> CacheBuilder<K, V> create(CacheBinding<K, V> def, boolean unwrapValueHolder) {
+  private <K, V> CacheBuilder<K, V> create(CacheBinding<K, V> def) {
     CacheBuilder<K, V> builder = newCacheBuilder();
     builder.recordStats();
     builder.maximumWeight(cfg.getLong("cache", def.name(), "memoryLimit", def.maximumWeight()));
@@ -73,17 +60,7 @@
     builder = builder.removalListener(forwardingRemovalListenerFactory.create(def.name()));
 
     Weigher<K, V> weigher = def.weigher();
-    if (weigher != null && unwrapValueHolder) {
-      final Weigher<K, V> impl = weigher;
-      weigher =
-          (Weigher<K, V>)
-              new Weigher<K, ValueHolder<V>>() {
-                @Override
-                public int weigh(K key, ValueHolder<V> value) {
-                  return impl.weigh(key, value.value);
-                }
-              };
-    } else if (weigher == null) {
+    if (weigher == null) {
       weigher = unitWeight();
     }
     builder.weigher(weigher);
diff --git a/java/com/google/gerrit/server/cache/mem/DefaultMemoryCacheModule.java b/java/com/google/gerrit/server/cache/mem/DefaultMemoryCacheModule.java
new file mode 100644
index 0000000..0e4ec3b
--- /dev/null
+++ b/java/com/google/gerrit/server/cache/mem/DefaultMemoryCacheModule.java
@@ -0,0 +1,29 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.cache.mem;
+
+import com.google.gerrit.extensions.config.FactoryModule;
+import com.google.gerrit.server.cache.CacheImpl;
+import com.google.gerrit.server.cache.ForwardingRemovalListener;
+import com.google.gerrit.server.cache.MemoryCacheFactory;
+
+@CacheImpl(type = CacheImpl.Type.MEMORY)
+public class DefaultMemoryCacheModule extends FactoryModule {
+  @Override
+  protected void configure() {
+    factory(ForwardingRemovalListener.Factory.class);
+    bind(MemoryCacheFactory.class).to(DefaultMemoryCacheFactory.class);
+  }
+}
diff --git a/java/com/google/gerrit/server/project/ProjectCache.java b/java/com/google/gerrit/server/project/ProjectCache.java
index 9ebcc99..7fa390e 100644
--- a/java/com/google/gerrit/server/project/ProjectCache.java
+++ b/java/com/google/gerrit/server/project/ProjectCache.java
@@ -15,6 +15,7 @@
 package com.google.gerrit.server.project;
 
 import com.google.common.collect.ImmutableSortedSet;
+import com.google.gerrit.common.Nullable;
 import com.google.gerrit.reviewdb.client.AccountGroup;
 import com.google.gerrit.reviewdb.client.Project;
 import java.io.IOException;
@@ -32,19 +33,20 @@
    * Get the cached data for a project by its unique name.
    *
    * @param projectName name of the project.
-   * @return the cached data; null if no such project exists or a error occurred.
+   * @return the cached data; null if no such project exists, projectName is null or an error
+   *     occurred.
    * @see #checkedGet(com.google.gerrit.reviewdb.client.Project.NameKey)
    */
-  ProjectState get(Project.NameKey projectName);
+  ProjectState get(@Nullable Project.NameKey projectName);
 
   /**
    * Get the cached data for a project by its unique name.
    *
    * @param projectName name of the project.
    * @throws IOException when there was an error.
-   * @return the cached data; null if no such project exists.
+   * @return the cached data; null if no such project exists or projectName is null.
    */
-  ProjectState checkedGet(Project.NameKey projectName) throws IOException;
+  ProjectState checkedGet(@Nullable Project.NameKey projectName) throws IOException;
 
   /**
    * Invalidate the cached information about the given project, and triggers reindexing for it
diff --git a/java/com/google/gerrit/testing/BUILD b/java/com/google/gerrit/testing/BUILD
index dd726a8..f2fe4c2 100644
--- a/java/com/google/gerrit/testing/BUILD
+++ b/java/com/google/gerrit/testing/BUILD
@@ -26,6 +26,7 @@
         "//java/com/google/gerrit/server:module",
         "//java/com/google/gerrit/server/api",
         "//java/com/google/gerrit/server/cache/h2",
+        "//java/com/google/gerrit/server/cache/mem",
         "//java/com/google/gerrit/server/restapi",
         "//java/com/google/gerrit/server/schema",
         "//lib:gwtorm",
diff --git a/java/com/google/gerrit/testing/InMemoryModule.java b/java/com/google/gerrit/testing/InMemoryModule.java
index 0a9165f1..6d90510 100644
--- a/java/com/google/gerrit/testing/InMemoryModule.java
+++ b/java/com/google/gerrit/testing/InMemoryModule.java
@@ -33,7 +33,8 @@
 import com.google.gerrit.server.GerritPersonIdentProvider;
 import com.google.gerrit.server.api.GerritApiModule;
 import com.google.gerrit.server.api.PluginApiModule;
-import com.google.gerrit.server.cache.h2.DefaultCacheFactory;
+import com.google.gerrit.server.cache.h2.H2CacheModule;
+import com.google.gerrit.server.cache.mem.DefaultMemoryCacheModule;
 import com.google.gerrit.server.config.AllProjectsName;
 import com.google.gerrit.server.config.AllProjectsNameProvider;
 import com.google.gerrit.server.config.AllUsersName;
@@ -227,7 +228,8 @@
             return MoreExecutors.newDirectExecutorService();
           }
         });
-    install(new DefaultCacheFactory.Module());
+    install(new DefaultMemoryCacheModule());
+    install(new H2CacheModule());
     install(new FakeEmailSender.Module());
     install(new SignedTokenEmailTokenVerifier.Module());
     install(new GpgModule(cfg));
diff --git a/plugins/replication b/plugins/replication
index 1b107f8..5e91925 160000
--- a/plugins/replication
+++ b/plugins/replication
@@ -1 +1 @@
-Subproject commit 1b107f8b839574c74bd173cc47ff12cddc72eee4
+Subproject commit 5e91925cfd391898e8e33fd149b9e1a115dafee4
diff --git a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.html b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.html
index e85fe38..cf39b5a 100644
--- a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.html
+++ b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.html
@@ -41,7 +41,6 @@
         display: inline-block
       }
       #textarea {
-        background-color: var(--background-color, none);
         width: 100%;
       }
       #hiddenText #emojiSuggestions {
diff --git a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.js b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.js
index c70dc8d..a3da7d8 100644
--- a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.js
+++ b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.js
@@ -70,10 +70,6 @@
         notify: true,
         observer: '_handleTextChanged',
       },
-      backgroundColor: {
-        type: String,
-        value: '#fff',
-      },
       hideBorder: {
         type: Boolean,
         value: false,
@@ -123,9 +119,6 @@
       if (this.hideBorder) {
         this.$.textarea.classList.add('noBorder');
       }
-      if (this.backgroundColor) {
-        this.updateStyles({'--background-color': this.backgroundColor});
-      }
     },
 
     closeDropdown() {
diff --git a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.html b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.html
index 97f8ca4..3a52543 100644
--- a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.html
@@ -25,7 +25,6 @@
 <link rel="import" href="gr-textarea.html">
 
 <script>void(0);</script>
-
 <test-fixture id="basic">
   <template>
     <gr-textarea></gr-textarea>
@@ -60,15 +59,6 @@
       assert.isTrue(element.$.textarea.classList.contains('noBorder'));
     });
 
-    test('background color is set properly', () => {
-      assert.equal(getComputedStyle(element.$.textarea).backgroundColor,
-          'rgb(255, 255, 255)');
-      element.backgroundColor = 'pink';
-      element.ready();
-      assert.equal(getComputedStyle(element.$.textarea).backgroundColor,
-          'rgb(255, 192, 203)');
-    });
-
     test('emoji selector is not open with the textarea lacks focus', () => {
       element.$.textarea.selectionStart = 1;
       element.$.textarea.selectionEnd = 1;
diff --git a/polygerrit-ui/app/styles/shared-styles.html b/polygerrit-ui/app/styles/shared-styles.html
index 0cb40dc..e9f7bcb 100644
--- a/polygerrit-ui/app/styles/shared-styles.html
+++ b/polygerrit-ui/app/styles/shared-styles.html
@@ -35,6 +35,7 @@
       }
       input,
       iron-autogrow-textarea {
+        background-color: inherit;
         box-sizing: border-box;
         margin: 0;
         padding: 0;