Merge "Remove SVN publish support from release notes makefile"
diff --git a/Documentation/config-project-config.txt b/Documentation/config-project-config.txt
index 474893d..43ede06 100644
--- a/Documentation/config-project-config.txt
+++ b/Documentation/config-project-config.txt
@@ -198,6 +198,41 @@
 documentation for a full list of available capabilities.
 
 
+[[branchOrder-section]]
+=== branchOrder section
+
+Defines a branch ordering which is used for backporting of changes.
+Backporting will be offered for a change (in the Gerrit UI) for all
+more stable branches where the change can merge cleanly.
+
+[[branchOrder.branch]]branchOrder.branch::
++
+A branch name, typically multiple values will be defined. The order of branch
+names in this section defines the branch order. The topmost is considered to be
+the least stable branch (typically the master branch) and the last one the
+most stable (typically the last maintained release branch).
+
+Example:
+
+----
+[branchOrder]
+  branch = master
+  branch = stable-2.9
+  branch = stable-2.8
+  branch = stable-2.7
+----
+
+The `branchOrder` section is inheritable. This is useful when multiple or all
+projects follow the same branch rules. A `branchOrder` section in a child
+project completely overrides any `branchOrder` section from a parent i.e. there
+is no merging of `branchOrder` sections. A present but empty `branchOrder`
+section removes all inherited branch order.
+
+Branches not listed in this section will not be included in the mergeability
+check. If the `branchOrder` section is not defined then the mergeability of a
+change into other branches will not be done.
+
+
 [[file-groups]]
 == The file +groups+
 
diff --git a/Documentation/json.txt b/Documentation/json.txt
index 6ab35f9..3624b3f 100644
--- a/Documentation/json.txt
+++ b/Documentation/json.txt
@@ -115,7 +115,7 @@
 
 isDraft:: Whether or not the patch set is a draft patch set.
 
-changeKind:: Kind of change uploaded.
+kind:: Kind of change uploaded.
 
   REWORK;; Nontrivial content changes.
 
diff --git a/Documentation/rest-api-config.txt b/Documentation/rest-api-config.txt
index 6a3b34e..9ea4f13 100644
--- a/Documentation/rest-api-config.txt
+++ b/Documentation/rest-api-config.txt
@@ -30,6 +30,261 @@
   "2.7"
 ----
 
+[[list-caches]]
+=== List Caches
+--
+'GET /config/server/caches/'
+--
+
+Lists the caches of the server. Caches defined by plugins are included.
+
+The caller must be a member of a group that is granted the
+link:access-control.html#capability_viewCaches[View Caches] capability
+or the link:access-control.html#capability_administrateServer[
+Administrate Server] capability.
+
+As result a map of link:#cache-info[CacheInfo] entities is returned.
+
+The entries in the map are sorted by cache name.
+
+.Request
+----
+  GET /config/server/caches/ HTTP/1.0
+----
+
+.Response
+----
+  HTTP/1.1 200 OK
+  Content-Type: application/json;charset=UTF-8
+
+  )]}'
+  {
+    "accounts": {
+      "entries": {
+        "mem": 4
+      },
+      "average_get": "2.5ms",
+      "hit_ratio": {
+        "mem": 94
+      }
+    },
+    "accounts_byemail": {
+      "entries": {
+        "mem": 4
+      },
+      "average_get": "771.8us",
+      "hit_ratio": {
+        "mem": 95
+      }
+    },
+    "accounts_byname": {
+      "entries": {
+        "mem": 4
+      },
+      "hit_ratio": {
+        "mem": 100
+      }
+    },
+    "adv_bases": {
+      "entries": {},
+      "hit_ratio": {}
+    },
+    "change_kind": {
+      "type": "DISK",
+      "entries": {
+        "space": "0.00k"
+      },
+      "hit_ratio": {}
+    },
+    "changes": {
+      "entries": {},
+      "hit_ratio": {}
+    },
+    "conflicts": {
+      "type": "DISK",
+      "entries": {
+        "mem": 2,
+        "disk": 3,
+        "space": "2.75k"
+      },
+      "hit_ratio": {
+        "mem": 0,
+        "disk": 100
+      }
+    },
+    "diff": {
+      "type": "DISK",
+      "entries": {
+        "mem": 177,
+        "disk": 253,
+        "space": "170.97k"
+      },
+      "average_get": "1.1ms",
+      "hit_ratio": {
+        "mem": 67,
+        "disk": 100
+      }
+    },
+    "diff_intraline": {
+      "type": "DISK",
+      "entries": {
+        "mem": 1,
+        "disk": 1,
+        "space": "0.37k"
+      },
+      "average_get": "6.8ms",
+      "hit_ratio": {
+        "mem": 0
+      }
+    },
+    "git_tags": {
+      "type": "DISK",
+      "entries": {
+        "space": "0.00k"
+      },
+      "hit_ratio": {}
+    },
+    groups": {
+      "entries": {
+        "mem": 27
+      },
+      "average_get": "183.2us",
+      "hit_ratio": {
+        "mem": 12
+      }
+    },
+    "groups_byinclude": {
+      "entries": {},
+      "hit_ratio": {}
+    },
+    "groups_byname": {
+      "entries": {},
+      "hit_ratio": {}
+    },
+    "groups_byuuid": {
+      "entries": {
+        "mem": 25
+      },
+      "average_get": "173.4us",
+      "hit_ratio": {
+        "mem": 13
+      }
+    },
+    "groups_external": {
+      "entries": {},
+      "hit_ratio": {}
+    },
+    groups_members": {
+      "entries": {
+        "mem": 4
+      },
+      "average_get": "697.8us",
+      "hit_ratio": {
+        "mem": 82
+      }
+    },
+    "permission_sort": {
+      "entries": {
+        "mem": 16
+      },
+      "hit_ratio": {
+        "mem": 96
+      }
+    },
+    "plugin_resources": {
+      "entries": {
+        "mem": 2
+      },
+      "hit_ratio": {
+        "mem": 83
+      }
+    },
+    "project_list": {
+      "entries": {
+        "mem": 1
+      },
+      "average_get": "18.6ms",
+      "hit_ratio": {
+        "mem": 0
+      }
+    },
+    "projects": {
+      "entries": {
+        "mem": 35
+      },
+      "average_get": "8.6ms",
+      "hit_ratio": {
+        "mem": 99
+      }
+    },
+    "quota-repo_size": {
+      "type": "DISK",
+      "entries": {
+        "space": "0.00k"
+      },
+      "hit_ratio": {}
+    },
+    "sshkeys": {
+      "entries": {
+        "mem": 1
+      },
+      "average_get": "3.2ms",
+      "hit_ratio": {
+        "mem": 50
+      }
+    },
+    "web_sessions": {
+      "type": "DISK",
+      "entries": {
+        "mem": 1,
+        "disk": 2,
+        "space": "0.78k"
+      },
+      "hit_ratio": {
+        "mem": 82
+      }
+    }
+  }
+----
+
+[[get-cache]]
+=== Get Cache
+--
+'GET /config/server/caches/link:#cache-name[\{cache-name\}]'
+--
+
+Retrieves information about a cache.
+
+The caller must be a member of a group that is granted the
+link:access-control.html#capability_viewCaches[View Caches] capability
+or the link:access-control.html#capability_administrateServer[
+Administrate Server] capability.
+
+As result a link:#cache-info[CacheInfo] entity is returned.
+
+.Request
+----
+  GET /config/server/caches/projects HTTP/1.0
+----
+
+.Response
+----
+  HTTP/1.1 200 OK
+  Content-Type: application/json;charset=UTF-8
+
+  )]}'
+  {
+    "name": "projects",
+    "entries": {
+      "mem": 35
+    },
+    "average_get": " 8.6ms",
+    "hit_ratio": {
+      "mem": 99
+    }
+  }
+----
+
 [[list-capabilities]]
 === List Capabilities
 --
@@ -176,9 +431,48 @@
 ----
 
 
+[[ids]]
+== IDs
+
+[[cache-name]]
+=== \{cache-name\}
+The name of the cache.
+
+If the cache is defined by a plugin the cache name must include the
+plugin name: "<plugin-name>-<cache-name>".
+
+Gerrit core caches can optionally be prefixed with "gerrit":
+"gerrit-<cache-name>".
+
+
 [[json-entities]]
 == JSON Entities
 
+[[cache-info]]
+=== CacheInfo
+The `CacheInfo` entity contains information about a cache.
+
+[options="header",width="50%",cols="1,^1,5"]
+|==================================
+|Field Name           ||Description
+|`name`               |
+not set if returned in a map where the cache name is used as map key|
+The cache name. If the cache is defined by a plugin the cache name
+includes the plugin name: "<plugin-name>-<cache-name>".
+|`type`               |not set for in memory caches|
+The type of the cache (`MEM`: in memory cache, `DISK`: disk cache).
+|`entries`            ||
+Information about the entries in the cache as a
+link:#entries-info[EntriesInfo] entity.
+|`average_get`        |optional|
+The average duration of getting one entry from the cache. The value is
+returned with a standard time unit abbreviation (`ns`: nanoseconds,
+`us`: microseconds, `ms`: milliseconds, `s`: seconds).
+|`hit_ratio`          ||
+Information about the hit ratio as a link:#hit-ration-info[
+HitRatioInfo] entity.
+|==================================
+
 [[capability-info]]
 === CapabilityInfo
 The `CapabilityInfo` entity contains information about a capability.
@@ -191,6 +485,39 @@
 |`name`               |capability name
 |=================================
 
+[[entries-info]]
+=== EntriesInfo
+The `EntriesInfo` entity contains information about the entries in a
+cache.
+
+[options="header",width="50%",cols="1,^1,5"]
+|==================================
+|Field Name ||Description
+|`mem`      |optional|Number of cache entries that are held in memory.
+|`disk`     |optional|Number of cache entries on the disk. For non-disk
+caches this value is not set; for disk caches it is only set if there
+are entries in the cache.
+|`space`    |optional|
+The space that is consumed by the cache on disk. The value is returned
+with a unit abbreviation (`k`: kilobytes, `m`: megabytes,
+`g`: gigabytes). Only set for disk caches.
+|==================================
+
+[[hit-ration-info]]
+=== HitRatioInfo
+The `HitRatioInfo` entity contains information about the hit ratio of a
+cache.
+
+[options="header",width="50%",cols="1,^1,5"]
+|==================================
+|Field Name ||Description
+|`mem`      ||
+Hit ratio for cache entries that are held in memory (0 \<= value \<= 100).
+|`disk`     |optional|
+Hit ratio for cache entries that are held on disk (0 \<= value \<= 100).
+Only set for disk caches.
+|==================================
+
 [[top-menu-entry-info]]
 === TopMenuEntryInfo
 The `TopMenuEntryInfo` entity contains information about a top menu
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/BUCK b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/BUCK
new file mode 100644
index 0000000..c89da30
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/BUCK
@@ -0,0 +1,6 @@
+include_defs('//gerrit-acceptance-tests/tests.defs')
+
+acceptance_tests(
+  srcs = glob(['*IT.java']),
+  labels = ['rest']
+)
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/GetCacheIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/GetCacheIT.java
new file mode 100644
index 0000000..5a22b19
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/GetCacheIT.java
@@ -0,0 +1,74 @@
+// Copyright (C) 2014 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.acceptance.rest.config;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.server.config.ListCaches.CacheInfo;
+
+import org.apache.http.HttpStatus;
+import org.junit.Test;
+
+import java.io.IOException;
+
+public class GetCacheIT extends AbstractDaemonTest {
+
+  @Test
+  public void getCache() throws IOException {
+    RestResponse r = adminSession.get("/config/server/caches/accounts");
+    assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+    CacheInfo result = newGson().fromJson(r.getReader(), CacheInfo.class);
+
+    assertEquals("accounts", result.name);
+    assertNull(result.type);
+    assertEquals(1, result.entries.mem.longValue());
+    assertNotNull(result.averageGet);
+    assertTrue(result.averageGet.endsWith("s"));
+    assertNull(result.entries.disk);
+    assertNull(result.entries.space);
+    assertTrue(result.hitRatio.mem >= 0);
+    assertTrue(result.hitRatio.mem <= 100);
+    assertNull(result.hitRatio.disk);
+
+    userSession.get("/config/server/version").consume();
+    r = adminSession.get("/config/server/caches/accounts");
+    assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+    result = newGson().fromJson(r.getReader(), CacheInfo.class);
+    assertEquals(2, result.entries.mem.longValue());
+  }
+
+  @Test
+  public void getCache_Forbidden() throws IOException {
+    RestResponse r = userSession.get("/config/server/caches/accounts");
+    assertEquals(HttpStatus.SC_FORBIDDEN, r.getStatusCode());
+  }
+
+  @Test
+  public void getCache_NotFound() throws IOException {
+    RestResponse r = adminSession.get("/config/server/caches/nonExisting");
+    assertEquals(HttpStatus.SC_NOT_FOUND, r.getStatusCode());
+  }
+
+  @Test
+  public void getCacheWithGerritPrefix() throws IOException {
+    RestResponse r = adminSession.get("/config/server/caches/gerrit-accounts");
+    assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+  }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/ListCachesIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/ListCachesIT.java
new file mode 100644
index 0000000..950b076
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/ListCachesIT.java
@@ -0,0 +1,68 @@
+// Copyright (C) 2014 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.acceptance.rest.config;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.server.config.ListCaches.CacheInfo;
+import com.google.gson.reflect.TypeToken;
+
+import org.apache.http.HttpStatus;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.Map;
+
+public class ListCachesIT extends AbstractDaemonTest {
+
+  @Test
+  public void listCaches() throws IOException {
+    RestResponse r = adminSession.get("/config/server/caches/");
+    assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+    Map<String, CacheInfo> result =
+        newGson().fromJson(r.getReader(),
+            new TypeToken<Map<String, CacheInfo>>() {}.getType());
+
+    assertTrue(result.containsKey("accounts"));
+    CacheInfo accountsCacheInfo = result.get("accounts");
+    assertNull(accountsCacheInfo.type);
+    assertEquals(1, accountsCacheInfo.entries.mem.longValue());
+    assertNotNull(accountsCacheInfo.averageGet);
+    assertTrue(accountsCacheInfo.averageGet.endsWith("s"));
+    assertNull(accountsCacheInfo.entries.disk);
+    assertNull(accountsCacheInfo.entries.space);
+    assertTrue(accountsCacheInfo.hitRatio.mem >= 0);
+    assertTrue(accountsCacheInfo.hitRatio.mem <= 100);
+    assertNull(accountsCacheInfo.hitRatio.disk);
+
+    userSession.get("/config/server/version").consume();
+    r = adminSession.get("/config/server/caches/");
+    assertEquals(HttpStatus.SC_OK, r.getStatusCode());
+    result = newGson().fromJson(r.getReader(),
+        new TypeToken<Map<String, CacheInfo>>() {}.getType());
+    assertEquals(2, result.get("accounts").entries.mem.longValue());
+  }
+
+  @Test
+  public void listCaches_Forbidden() throws IOException {
+    RestResponse r = userSession.get("/config/server/caches/");
+    assertEquals(HttpStatus.SC_FORBIDDEN, r.getStatusCode());
+  }
+}
diff --git a/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/H2CacheImpl.java b/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/H2CacheImpl.java
index de7613d..652ed30 100644
--- a/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/H2CacheImpl.java
+++ b/gerrit-cache-h2/src/main/java/com/google/gerrit/server/cache/h2/H2CacheImpl.java
@@ -11,6 +11,7 @@
 import com.google.common.hash.Funnel;
 import com.google.common.hash.Funnels;
 import com.google.common.hash.PrimitiveSink;
+import com.google.gerrit.server.cache.PersistentCache;
 import com.google.gerrit.server.util.TimeUtil;
 import com.google.inject.TypeLiteral;
 
@@ -63,7 +64,8 @@
  *
  * @see H2CacheFactory
  */
-public class H2CacheImpl<K, V> extends AbstractLoadingCache<K, V> {
+public class H2CacheImpl<K, V> extends AbstractLoadingCache<K, V> implements
+    PersistentCache {
   private static final Logger log = LoggerFactory.getLogger(H2CacheImpl.class);
 
   private final Executor executor;
@@ -156,6 +158,7 @@
     return mem.stats();
   }
 
+  @Override
   public DiskStats diskStats() {
     return store.diskStats();
   }
@@ -193,29 +196,6 @@
     }, delay, TimeUnit.MILLISECONDS);
   }
 
-  public static class DiskStats {
-    long size;
-    long space;
-    long hitCount;
-    long missCount;
-
-    public long size() {
-      return size;
-    }
-
-    public long space() {
-      return space;
-    }
-
-    public long hitCount() {
-      return hitCount;
-    }
-
-    public long requestCount() {
-      return hitCount + missCount;
-    }
-  }
-
   static class ValueHolder<V> {
     final V value;
     long created;
@@ -599,9 +579,8 @@
     }
 
     DiskStats diskStats() {
-      DiskStats d = new DiskStats();
-      d.hitCount = hitCount.get();
-      d.missCount = missCount.get();
+      long size = 0;
+      long space = 0;
       SqlHandle c = null;
       try {
         c = acquire();
@@ -613,8 +592,8 @@
               + " FROM data");
           try {
             if (r.next()) {
-              d.size = r.getLong(1);
-              d.space = r.getLong(2);
+              size = r.getLong(1);
+              space = r.getLong(2);
             }
           } finally {
             r.close();
@@ -628,7 +607,7 @@
       } finally {
         release(c);
       }
-      return d;
+      return new DiskStats(size, space, hitCount.get(), missCount.get());
     }
 
     private SqlHandle acquire() throws SQLException {
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/annotations/RootRelative.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/annotations/RootRelative.java
index 3875b77..a812b53 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/annotations/RootRelative.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/annotations/RootRelative.java
@@ -26,7 +26,7 @@
  * Annotation applied to HttpServletRequest and HttpServletResponse
  * when they are inherited from Gerrit instead of being injected by
  * a plugin's ServletModule.  This means that the path returned by
- * {@link javax.servlet.http.HttpServletRequest#getPathInfo} is
+ * 'javax.servlet.http.HttpServletRequest#getPathInfo()' is
  * relative to the Gerrit root instead of a path within the plugin's
  * URL space.
  */
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/ApprovalCopier.java b/gerrit-server/src/main/java/com/google/gerrit/server/ApprovalCopier.java
index e68b29c..b74eb77 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/ApprovalCopier.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/ApprovalCopier.java
@@ -38,6 +38,7 @@
 import com.google.gerrit.server.query.change.ChangeData;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.Repository;
@@ -56,6 +57,7 @@
  * database at submit time, or refreshed on demand, as when reading approvals
  * from the notedb.
  */
+@Singleton
 public class ApprovalCopier {
   private final GitRepositoryManager repoManager;
   private final ProjectCache projectCache;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/ApprovalsUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/ApprovalsUtil.java
index f98393b..900bbdd 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/ApprovalsUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/ApprovalsUtil.java
@@ -49,6 +49,7 @@
 import com.google.gerrit.server.util.TimeUtil;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
 import java.sql.Timestamp;
 import java.util.ArrayList;
@@ -70,6 +71,7 @@
  * <p>
  * The methods in this class only modify the gwtorm database.
  */
+@Singleton
 public class ApprovalsUtil {
   private static Ordering<PatchSetApproval> SORT_APPROVALS = Ordering.natural()
       .onResultOf(new Function<PatchSetApproval, Timestamp>() {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/access/AccessCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/access/AccessCollection.java
index 58f93d8..aa04b33 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/access/AccessCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/access/AccessCollection.java
@@ -22,7 +22,9 @@
 import com.google.gerrit.extensions.restapi.TopLevelResource;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
+@Singleton
 public class AccessCollection implements
     RestCollection<TopLevelResource, AccessResource> {
   private final Provider<ListAccess> list;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountsCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountsCollection.java
index 213ecd1..5ef745b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountsCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountsCollection.java
@@ -30,7 +30,9 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
+@Singleton
 public class AccountsCollection implements
     RestCollection<TopLevelResource, AccountResource>,
     AcceptsCreate<TopLevelResource>{
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AddSshKey.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AddSshKey.java
index 6fd035f..3c21d17 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AddSshKey.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AddSshKey.java
@@ -35,11 +35,13 @@
 import com.google.gwtorm.server.ResultSet;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.Collections;
 
+@Singleton
 public class AddSshKey implements RestModifyView<AccountResource, Input> {
   public static class Input {
     public RawInput raw;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/Capabilities.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/Capabilities.java
index 38e5013..95338fe 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/Capabilities.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/Capabilities.java
@@ -25,7 +25,9 @@
 import com.google.gerrit.server.account.AccountResource.Capability;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
+@Singleton
 class Capabilities implements
     ChildCollection<AccountResource, AccountResource.Capability> {
   private final Provider<CurrentUser> self;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/DeleteActive.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/DeleteActive.java
index 4382655..52ab651 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/DeleteActive.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/DeleteActive.java
@@ -25,10 +25,12 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import java.util.Collections;
 
 @RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
+@Singleton
 public class DeleteActive implements RestModifyView<AccountResource, Input> {
   public static class Input {
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/DeleteEmail.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/DeleteEmail.java
index 5e0597b..6048586 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/DeleteEmail.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/DeleteEmail.java
@@ -29,7 +29,9 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
+@Singleton
 public class DeleteEmail implements RestModifyView<AccountResource.Email, Input> {
   public static class Input {
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/DeleteSshKey.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/DeleteSshKey.java
index bbba48a..7df1848 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/DeleteSshKey.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/DeleteSshKey.java
@@ -22,9 +22,11 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import java.util.Collections;
 
+@Singleton
 public class DeleteSshKey implements
     RestModifyView<AccountResource.SshKey, Input> {
   public static class Input {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/Emails.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/Emails.java
index f523e15..2dc9620 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/Emails.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/Emails.java
@@ -25,7 +25,9 @@
 import com.google.gerrit.server.account.AccountResource.Email;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
+@Singleton
 public class Emails implements
     ChildCollection<AccountResource, AccountResource.Email>,
     AcceptsCreate<AccountResource> {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetAccount.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetAccount.java
index f990b5b..200595f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetAccount.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetAccount.java
@@ -17,7 +17,9 @@
 import com.google.gerrit.extensions.restapi.RestReadView;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
+@Singleton
 public class GetAccount implements RestReadView<AccountResource> {
   private final AccountInfo.Loader.Factory infoFactory;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetActive.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetActive.java
index c042e18..10b6df9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetActive.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetActive.java
@@ -17,7 +17,9 @@
 import com.google.gerrit.extensions.restapi.BinaryResult;
 import com.google.gerrit.extensions.restapi.Response;
 import com.google.gerrit.extensions.restapi.RestReadView;
+import com.google.inject.Singleton;
 
+@Singleton
 public class GetActive implements RestReadView<AccountResource> {
   @Override
   public Object apply(AccountResource rsrc) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetAvatarChangeUrl.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetAvatarChangeUrl.java
index ec538bc..ccff183 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetAvatarChangeUrl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetAvatarChangeUrl.java
@@ -20,7 +20,9 @@
 import com.google.gerrit.extensions.restapi.RestReadView;
 import com.google.gerrit.server.avatar.AvatarProvider;
 import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
+@Singleton
 public class GetAvatarChangeUrl implements RestReadView<AccountResource> {
   private final DynamicItem<AvatarProvider> avatarProvider;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetCapabilities.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetCapabilities.java
index 465ddab..47047ed 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetCapabilities.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetCapabilities.java
@@ -48,6 +48,7 @@
 import com.google.gson.reflect.TypeToken;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import org.kohsuke.args4j.Option;
 
@@ -178,6 +179,7 @@
     }
   }
 
+  @Singleton
   static class CheckOne implements RestReadView<AccountResource.Capability> {
     @Override
     public BinaryResult apply(Capability resource) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetDiffPreferences.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetDiffPreferences.java
index 031788a..5959fac 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetDiffPreferences.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetDiffPreferences.java
@@ -25,7 +25,9 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
+@Singleton
 public class GetDiffPreferences implements RestReadView<AccountResource> {
   private final Provider<CurrentUser> self;
   private final Provider<ReviewDb> db;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetEmail.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetEmail.java
index c56a0a0..a4a6bd0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetEmail.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetEmail.java
@@ -16,7 +16,9 @@
 
 import com.google.gerrit.extensions.restapi.RestReadView;
 import com.google.gerrit.server.account.GetEmails.EmailInfo;
+import com.google.inject.Singleton;
 
+@Singleton
 public class GetEmail implements RestReadView<AccountResource.Email> {
   @Override
   public EmailInfo apply(AccountResource.Email rsrc) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetGroups.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetGroups.java
index 97e4e70..d335add 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetGroups.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetGroups.java
@@ -24,9 +24,11 @@
 import com.google.gerrit.server.group.GroupJson.GroupInfo;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
 import java.util.List;
 
+@Singleton
 public class GetGroups implements RestReadView<AccountResource> {
   private final GroupControl.Factory groupControlFactory;
   private final GroupJson json;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetHttpPassword.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetHttpPassword.java
index 7fc82f9..c49ab98 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetHttpPassword.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetHttpPassword.java
@@ -20,7 +20,9 @@
 import com.google.gerrit.server.CurrentUser;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
+@Singleton
 public class GetHttpPassword implements RestReadView<AccountResource> {
 
   private final Provider<CurrentUser> self;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetName.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetName.java
index 646a3b2..7add77a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetName.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetName.java
@@ -16,7 +16,9 @@
 
 import com.google.common.base.Strings;
 import com.google.gerrit.extensions.restapi.RestReadView;
+import com.google.inject.Singleton;
 
+@Singleton
 public class GetName implements RestReadView<AccountResource> {
   @Override
   public String apply(AccountResource rsrc) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetPreferences.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetPreferences.java
index 5cd912d..17661b2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetPreferences.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetPreferences.java
@@ -35,6 +35,7 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.lib.Config;
@@ -46,6 +47,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
+@Singleton
 public class GetPreferences implements RestReadView<AccountResource> {
   private static final Logger log = LoggerFactory.getLogger(GetPreferences.class);
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetSshKey.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetSshKey.java
index 37445e9..a7700cf 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetSshKey.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetSshKey.java
@@ -17,7 +17,9 @@
 import com.google.gerrit.extensions.restapi.RestReadView;
 import com.google.gerrit.server.account.AccountResource.SshKey;
 import com.google.gerrit.server.account.GetSshKeys.SshKeyInfo;
+import com.google.inject.Singleton;
 
+@Singleton
 public class GetSshKey implements RestReadView<AccountResource.SshKey> {
 
   @Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetUsername.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetUsername.java
index 8dcb236..41622cf 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetUsername.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetUsername.java
@@ -20,7 +20,9 @@
 import com.google.gerrit.server.CurrentUser;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
+@Singleton
 public class GetUsername implements RestReadView<AccountResource> {
 
   private final Provider<CurrentUser> self;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/PutAccount.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/PutAccount.java
index f7584ed..17e177f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/PutAccount.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/PutAccount.java
@@ -17,7 +17,9 @@
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
 import com.google.gerrit.extensions.restapi.RestModifyView;
 import com.google.gerrit.server.account.CreateAccount.Input;
+import com.google.inject.Singleton;
 
+@Singleton
 public class PutAccount implements RestModifyView<AccountResource, Input> {
   @Override
   public Object apply(AccountResource resource, Input input)
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/PutActive.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/PutActive.java
index f1b5151..69d16d8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/PutActive.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/PutActive.java
@@ -25,10 +25,12 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import java.util.Collections;
 
 @RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
+@Singleton
 public class PutActive implements RestModifyView<AccountResource, Input> {
   public static class Input {
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/PutEmail.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/PutEmail.java
index ba12bbf..3831cbf 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/PutEmail.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/PutEmail.java
@@ -18,7 +18,9 @@
 import com.google.gerrit.extensions.restapi.Response;
 import com.google.gerrit.extensions.restapi.RestModifyView;
 import com.google.gerrit.server.account.CreateEmail.Input;
+import com.google.inject.Singleton;
 
+@Singleton
 public class PutEmail implements RestModifyView<AccountResource.Email, Input> {
   @Override
   public Response<?> apply(AccountResource.Email rsrc, Input input)
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/PutHttpPassword.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/PutHttpPassword.java
index f7061e3..3903050 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/PutHttpPassword.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/PutHttpPassword.java
@@ -30,6 +30,7 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import org.apache.commons.codec.binary.Base64;
 
@@ -37,6 +38,7 @@
 import java.security.SecureRandom;
 import java.util.Collections;
 
+@Singleton
 public class PutHttpPassword implements RestModifyView<AccountResource, Input> {
   public static class Input {
     public String httpPassword;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/PutName.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/PutName.java
index 87629d8..554bae7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/PutName.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/PutName.java
@@ -34,9 +34,11 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import java.util.Collections;
 
+@Singleton
 public class PutName implements RestModifyView<AccountResource, Input> {
   public static class Input {
     @DefaultInput
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/PutPreferred.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/PutPreferred.java
index 8fc2e6c..7ac987d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/PutPreferred.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/PutPreferred.java
@@ -26,9 +26,11 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import java.util.Collections;
 
+@Singleton
 public class PutPreferred implements
     RestModifyView<AccountResource.Email, Input> {
   static class Input {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/SetDiffPreferences.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/SetDiffPreferences.java
index c056f63..9b971e4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/SetDiffPreferences.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/SetDiffPreferences.java
@@ -27,9 +27,11 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import java.util.Collections;
 
+@Singleton
 public class SetDiffPreferences implements RestModifyView<AccountResource, Input> {
   static class Input {
     Short context;
@@ -54,10 +56,10 @@
   }
 
   private final Provider<CurrentUser> self;
-  private final ReviewDb db;
+  private final Provider<ReviewDb> db;
 
   @Inject
-  SetDiffPreferences(Provider<CurrentUser> self, ReviewDb db) {
+  SetDiffPreferences(Provider<CurrentUser> self, Provider<ReviewDb> db) {
     this.self = self;
     this.db = db;
   }
@@ -76,9 +78,9 @@
     Account.Id accountId = rsrc.getUser().getAccountId();
     AccountDiffPreference p;
 
-    db.accounts().beginTransaction(accountId);
+    db.get().accounts().beginTransaction(accountId);
     try {
-      p = db.accountDiffPreferences().get(accountId);
+      p = db.get().accountDiffPreferences().get(accountId);
       if (p == null) {
         p = new AccountDiffPreference(accountId);
       }
@@ -141,10 +143,10 @@
         p.setHideEmptyPane(input.hideEmptyPane);
       }
 
-      db.accountDiffPreferences().upsert(Collections.singleton(p));
-      db.commit();
+      db.get().accountDiffPreferences().upsert(Collections.singleton(p));
+      db.get().commit();
     } finally {
-      db.rollback();
+      db.get().rollback();
     }
     return DiffPreferencesInfo.parse(p);
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/SetPreferences.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/SetPreferences.java
index fcbf46b..fbf9a37 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/SetPreferences.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/SetPreferences.java
@@ -41,6 +41,7 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.lib.Config;
@@ -49,6 +50,7 @@
 import java.util.Collections;
 import java.util.List;
 
+@Singleton
 public class SetPreferences implements RestModifyView<AccountResource, Input> {
   public static class Input {
     public Short changesPerPage;
@@ -72,13 +74,14 @@
 
   private final Provider<CurrentUser> self;
   private final AccountCache cache;
-  private final ReviewDb db;
+  private final Provider<ReviewDb> db;
   private final MetaDataUpdate.User metaDataUpdateFactory;
   private final AllUsersName allUsersName;
 
   @Inject
-  SetPreferences(Provider<CurrentUser> self, AccountCache cache, ReviewDb db,
-      MetaDataUpdate.User metaDataUpdateFactory, AllUsersName allUsersName) {
+  SetPreferences(Provider<CurrentUser> self, AccountCache cache,
+      Provider<ReviewDb> db, MetaDataUpdate.User metaDataUpdateFactory,
+      AllUsersName allUsersName) {
     this.self = self;
     this.cache = cache;
     this.db = db;
@@ -102,9 +105,9 @@
     AccountGeneralPreferences p;
     VersionedAccountPreferences versionedPrefs;
     MetaDataUpdate md = metaDataUpdateFactory.create(allUsersName);
-    db.accounts().beginTransaction(accountId);
+    db.get().accounts().beginTransaction(accountId);
     try {
-      Account a = db.accounts().get(accountId);
+      Account a = db.get().accounts().get(accountId);
       if (a == null) {
         throw new ResourceNotFoundException();
       }
@@ -167,8 +170,8 @@
         p.setChangeScreen(i.changeScreen);
       }
 
-      db.accounts().update(Collections.singleton(a));
-      db.commit();
+      db.get().accounts().update(Collections.singleton(a));
+      db.get().commit();
       storeMyMenus(versionedPrefs, i.my);
       versionedPrefs.commit(md);
       cache.evict(accountId);
@@ -177,7 +180,7 @@
           md.getRepository());
     } finally {
       md.close();
-      db.rollback();
+      db.get().rollback();
     }
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/SshKeys.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/SshKeys.java
index 69acd1e..46539c5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/SshKeys.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/SshKeys.java
@@ -26,7 +26,9 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
+@Singleton
 public class SshKeys implements
     ChildCollection<AccountResource, AccountResource.SshKey> {
   private final DynamicMap<RestView<AccountResource.SshKey>> views;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/StarredChanges.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/StarredChanges.java
index 43f7211..a3c0d37 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/StarredChanges.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/StarredChanges.java
@@ -38,12 +38,14 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.util.Collections;
 
+@Singleton
 public class StarredChanges implements
     ChildCollection<AccountResource, AccountResource.StarredChange>,
     AcceptsCreate<AccountResource> {
@@ -112,6 +114,7 @@
     }
   }
 
+  @Singleton
   public static class Create implements RestModifyView<AccountResource, EmptyInput> {
     private final Provider<CurrentUser> self;
     private final Provider<ReviewDb> dbProvider;
@@ -146,6 +149,7 @@
     }
   }
 
+  @Singleton
   static class Put implements
       RestModifyView<AccountResource.StarredChange, EmptyInput> {
     private final Provider<CurrentUser> self;
@@ -165,6 +169,7 @@
     }
   }
 
+  @Singleton
   public static class Delete implements
       RestModifyView<AccountResource.StarredChange, EmptyInput> {
     private final Provider<CurrentUser> self;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/GerritApiImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/GerritApiImpl.java
index 6815bb1..cc09b77 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/GerritApiImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/GerritApiImpl.java
@@ -20,7 +20,9 @@
 import com.google.gerrit.extensions.api.projects.Projects;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
+@Singleton
 class GerritApiImpl extends GerritApi.NotImplemented implements GerritApi {
   private final Provider<Accounts> accounts;
   private final Provider<Changes> changes;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/accounts/AccountsImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/accounts/AccountsImpl.java
index 3f0ecfb..0c02c99 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/accounts/AccountsImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/accounts/AccountsImpl.java
@@ -27,7 +27,9 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
+@Singleton
 public class AccountsImpl extends Accounts.NotImplemented implements Accounts {
   private final AccountsCollection accounts;
   private final AccountApiImpl.Factory api;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangesImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangesImpl.java
index 0718810..db72c9c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangesImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangesImpl.java
@@ -38,24 +38,26 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import java.io.IOException;
 import java.util.List;
 
+@Singleton
 class ChangesImpl implements Changes {
   private final ChangesCollection changes;
   private final ChangeApiImpl.Factory api;
-  private final CreateChange.Factory createChangeFactory;
+  private final CreateChange createChange;
   private final Provider<QueryChanges> queryProvider;
 
   @Inject
   ChangesImpl(ChangesCollection changes,
       ChangeApiImpl.Factory api,
-      CreateChange.Factory createChangeFactory,
+      CreateChange createChange,
       Provider<QueryChanges> queryProvider) {
     this.changes = changes;
     this.api = api;
-    this.createChangeFactory = createChangeFactory;
+    this.createChange = createChange;
     this.queryProvider = queryProvider;
   }
 
@@ -87,7 +89,7 @@
   @Override
   public ChangeApi create(ChangeInfo in) throws RestApiException {
     try {
-      ChangeJson.ChangeInfo out = createChangeFactory.create().apply(
+      ChangeJson.ChangeInfo out = createChange.apply(
           TopLevelResource.INSTANCE, in).value();
       return api.create(changes.parse(TopLevelResource.INSTANCE,
           IdString.fromUrl(out.changeId)));
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/ProjectsImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/ProjectsImpl.java
index edb49fcc..86baa1e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/ProjectsImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/projects/ProjectsImpl.java
@@ -24,10 +24,12 @@
 import com.google.gerrit.server.project.ProjectsCollection;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import java.io.IOException;
 import java.util.List;
 
+@Singleton
 class ProjectsImpl extends Projects.NotImplemented implements Projects {
   private final ProjectsCollection projects;
   private final ProjectApiImpl.Factory api;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/cache/PersistentCache.java b/gerrit-server/src/main/java/com/google/gerrit/server/cache/PersistentCache.java
new file mode 100644
index 0000000..62623ea
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/cache/PersistentCache.java
@@ -0,0 +1,50 @@
+// Copyright (C) 2014 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;
+
+public interface PersistentCache {
+
+  DiskStats diskStats();
+
+  public static class DiskStats {
+    private final long size;
+    private final long space;
+    private final long hitCount;
+    private final long missCount;
+
+    public DiskStats(long size, long space, long hitCount, long missCount) {
+      this.size = size;
+      this.space = space;
+      this.hitCount = hitCount;
+      this.missCount = missCount;
+    }
+
+    public long size() {
+      return size;
+    }
+
+    public long space() {
+      return space;
+    }
+
+    public long hitCount() {
+      return hitCount;
+    }
+
+    public long requestCount() {
+      return hitCount + missCount;
+    }
+  }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
index 4f4f1d9..2e60300 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
@@ -33,9 +33,6 @@
 import com.google.common.base.Joiner;
 import com.google.common.base.Objects;
 import com.google.common.base.Optional;
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.CacheLoader;
-import com.google.common.cache.LoadingCache;
 import com.google.common.collect.HashBasedTable;
 import com.google.common.collect.HashMultimap;
 import com.google.common.collect.ImmutableList;
@@ -74,7 +71,6 @@
 import com.google.gerrit.reviewdb.client.PatchSetApproval;
 import com.google.gerrit.reviewdb.client.PatchSetInfo;
 import com.google.gerrit.reviewdb.client.PatchSetInfo.ParentInfo;
-import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.reviewdb.client.UserIdentity;
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.AnonymousUser;
@@ -88,7 +84,6 @@
 import com.google.gerrit.server.patch.PatchSetInfoFactory;
 import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
 import com.google.gerrit.server.project.ChangeControl;
-import com.google.gerrit.server.project.NoSuchProjectException;
 import com.google.gerrit.server.project.ProjectControl;
 import com.google.gerrit.server.query.change.ChangeData;
 import com.google.gerrit.server.query.change.ChangeData.ChangedLines;
@@ -100,7 +95,6 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.IOException;
 import java.sql.Timestamp;
 import java.util.Collection;
 import java.util.Collections;
@@ -111,7 +105,6 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
-import java.util.concurrent.ExecutionException;
 
 public class ChangeJson {
   private static final Logger log = LoggerFactory.getLogger(ChangeJson.class);
@@ -137,23 +130,18 @@
   private final Provider<CurrentUser> userProvider;
   private final AnonymousUser anonymous;
   private final IdentifiedUser.GenericFactory userFactory;
-  private final ProjectControl.GenericFactory projectControlFactory;
   private final ChangeData.Factory changeDataFactory;
   private final PatchSetInfoFactory patchSetInfoFactory;
-  private final ChangesCollection changes;
   private final FileInfoJson fileInfoJson;
   private final AccountInfo.Loader.Factory accountLoaderFactory;
   private final DynamicMap<DownloadScheme> downloadSchemes;
   private final DynamicMap<DownloadCommand> downloadCommands;
   private final DynamicMap<RestView<ChangeResource>> changeViews;
   private final Revisions revisions;
+  private final Provider<WebLinks> webLinks;
+  private final EnumSet<ListChangesOption> options;
 
-  private EnumSet<ListChangesOption> options;
   private AccountInfo.Loader accountLoader;
-  private ChangeControl lastControl;
-  private Set<Change.Id> reviewed;
-  private LoadingCache<Project.NameKey, ProjectControl> projectControls;
-  private Provider<WebLinks> webLinks;
 
   @Inject
   ChangeJson(
@@ -165,7 +153,6 @@
       ProjectControl.GenericFactory pcf,
       ChangeData.Factory cdf,
       PatchSetInfoFactory psi,
-      ChangesCollection changes,
       FileInfoJson fileInfoJson,
       AccountInfo.Loader.Factory ailf,
       DynamicMap<DownloadScheme> downloadSchemes,
@@ -178,10 +165,8 @@
     this.userProvider = user;
     this.anonymous = au;
     this.userFactory = uf;
-    this.projectControlFactory = pcf;
     this.changeDataFactory = cdf;
     this.patchSetInfoFactory = psi;
-    this.changes = changes;
     this.fileInfoJson = fileInfoJson;
     this.accountLoaderFactory = ailf;
     this.downloadSchemes = downloadSchemes;
@@ -189,17 +174,7 @@
     this.changeViews = changeViews;
     this.revisions = revisions;
     this.webLinks = webLinks;
-
     options = EnumSet.noneOf(ListChangesOption.class);
-    projectControls = CacheBuilder.newBuilder()
-      .concurrencyLevel(1)
-      .build(new CacheLoader<Project.NameKey, ProjectControl>() {
-        @Override
-        public ProjectControl load(Project.NameKey key)
-            throws NoSuchProjectException, IOException {
-          return projectControlFactory.controlFor(key, userProvider.get());
-        }
-      });
   }
 
   public ChangeJson addOption(ListChangesOption o) {
@@ -231,10 +206,11 @@
   private ChangeInfo format(ChangeData cd, Optional<PatchSet.Id> limitToPsId)
       throws OrmException {
     accountLoader = accountLoaderFactory.create(has(DETAILED_ACCOUNTS));
+    Set<Change.Id> reviewed = Sets.newHashSet();
     if (has(REVIEWED)) {
-      ensureReviewedLoaded(Collections.singleton(cd));
+      reviewed = loadReviewed(Collections.singleton(cd));
     }
-    ChangeInfo res = toChangeInfo(cd, limitToPsId);
+    ChangeInfo res = toChangeInfo(cd, reviewed, limitToPsId);
     accountLoader.fill();
     return res;
   }
@@ -254,15 +230,16 @@
     } else {
       ChangeData.ensureCurrentPatchSetLoaded(all);
     }
+    Set<Change.Id> reviewed = Sets.newHashSet();
     if (has(REVIEWED)) {
-      ensureReviewedLoaded(all);
+      reviewed = loadReviewed(all);
     }
     ChangeData.ensureCurrentApprovalsLoaded(all);
 
     List<List<ChangeInfo>> res = Lists.newArrayListWithCapacity(in.size());
     Map<Change.Id, ChangeInfo> out = Maps.newHashMap();
     for (List<ChangeData> changes : in) {
-      res.add(toChangeInfo(out, changes));
+      res.add(toChangeInfo(out, changes, reviewed));
     }
     accountLoader.fill();
     return res;
@@ -273,13 +250,13 @@
   }
 
   private List<ChangeInfo> toChangeInfo(Map<Change.Id, ChangeInfo> out,
-      List<ChangeData> changes) throws OrmException {
+      List<ChangeData> changes, Set<Change.Id> reviewed) throws OrmException {
     List<ChangeInfo> info = Lists.newArrayListWithCapacity(changes.size());
     for (ChangeData cd : changes) {
       ChangeInfo i = out.get(cd.getId());
       if (i == null) {
         try {
-          i = toChangeInfo(cd, Optional.<PatchSet.Id> absent());
+          i = toChangeInfo(cd, reviewed, Optional.<PatchSet.Id> absent());
         } catch (OrmException e) {
           log.warn(
               "Omitting corrupt change " + cd.getId() + " from results", e);
@@ -292,8 +269,9 @@
     return info;
   }
 
-  private ChangeInfo toChangeInfo(ChangeData cd,
+  private ChangeInfo toChangeInfo(ChangeData cd, Set<Change.Id> reviewed,
       Optional<PatchSet.Id> limitToPsId) throws OrmException {
+    ChangeControl ctl = cd.changeControl().forUser(userProvider.get());
     ChangeInfo out = new ChangeInfo();
     Change in = cd.change();
     out.project = in.getProject().get();
@@ -319,28 +297,28 @@
     out.reviewed = in.getStatus().isOpen()
         && has(REVIEWED)
         && reviewed.contains(cd.getId()) ? true : null;
-    out.labels = labelsFor(cd, has(LABELS), has(DETAILED_LABELS));
+    out.labels = labelsFor(ctl, cd, has(LABELS), has(DETAILED_LABELS));
 
     if (out.labels != null && has(DETAILED_LABELS)) {
       // If limited to specific patch sets but not the current patch set, don't
       // list permitted labels, since users can't vote on those patch sets.
       if (!limitToPsId.isPresent()
           || limitToPsId.get().equals(in.currentPatchSetId())) {
-        out.permittedLabels = permittedLabels(cd);
+        out.permittedLabels = permittedLabels(ctl, cd);
       }
-      out.removableReviewers = removableReviewers(cd, out.labels.values());
+      out.removableReviewers = removableReviewers(ctl, cd, out.labels.values());
     }
 
     Map<PatchSet.Id, PatchSet> src = loadPatchSets(cd, limitToPsId);
     if (has(MESSAGES)) {
-      out.messages = messages(cd, src);
+      out.messages = messages(ctl, cd, src);
     }
     out.finish();
 
     if (has(ALL_REVISIONS)
         || has(CURRENT_REVISION)
         || limitToPsId.isPresent()) {
-      out.revisions = revisions(cd, limitToPsId, out.project, src);
+      out.revisions = revisions(ctl, cd, limitToPsId, out.project, src);
       if (out.revisions != null) {
         for (Map.Entry<String, RevisionInfo> entry : out.revisions.entrySet()) {
           if (entry.getValue().isCurrent) {
@@ -355,40 +333,19 @@
       out.actions = Maps.newTreeMap();
       for (UiAction.Description d : UiActions.from(
           changeViews,
-          changes.parse(control(cd)),
+          new ChangeResource(ctl),
           userProvider)) {
         out.actions.put(d.getId(), new ActionInfo(d));
       }
     }
-    lastControl = null;
     return out;
   }
 
-  private ChangeControl control(ChangeData cd) throws OrmException {
-    if (lastControl != null
-        && cd.getId().equals(lastControl.getChange().getId())) {
-      return lastControl;
-    }
-    ChangeControl ctrl;
-    try {
-      if (cd.hasChangeControl()) {
-        ctrl = cd.changeControl().forUser(userProvider.get());
-      } else {
-        ctrl = projectControls.get(cd.change().getProject())
-            .controlFor(cd.change());
-      }
-    } catch (ExecutionException e) {
-      throw new OrmException(e);
-    }
-    lastControl = ctrl;
-    return ctrl;
-  }
-
-  private List<SubmitRecord> submitRecords(ChangeData cd) throws OrmException {
+  private List<SubmitRecord> submitRecords(ChangeControl ctl, ChangeData cd)
+      throws OrmException {
     if (cd.getSubmitRecords() != null) {
       return cd.getSubmitRecords();
     }
-    ChangeControl ctl = control(cd);
     if (ctl == null) {
       return ImmutableList.of();
     }
@@ -400,31 +357,30 @@
     return cd.getSubmitRecords();
   }
 
-  private Map<String, LabelInfo> labelsFor(ChangeData cd, boolean standard,
+  private Map<String, LabelInfo> labelsFor(ChangeControl ctl, ChangeData cd, boolean standard,
       boolean detailed) throws OrmException {
     if (!standard && !detailed) {
       return null;
     }
 
-    ChangeControl ctl = control(cd);
     if (ctl == null) {
       return null;
     }
 
     LabelTypes labelTypes = ctl.getLabelTypes();
     if (cd.change().getStatus().isOpen()) {
-      return labelsForOpenChange(cd, labelTypes, standard, detailed);
+      return labelsForOpenChange(ctl, cd, labelTypes, standard, detailed);
     } else {
       return labelsForClosedChange(cd, labelTypes, standard, detailed);
     }
   }
 
-  private Map<String, LabelInfo> labelsForOpenChange(ChangeData cd,
-      LabelTypes labelTypes, boolean standard, boolean detailed)
+  private Map<String, LabelInfo> labelsForOpenChange(ChangeControl ctl,
+      ChangeData cd, LabelTypes labelTypes, boolean standard, boolean detailed)
       throws OrmException {
-    Map<String, LabelInfo> labels = initLabels(cd, labelTypes, standard);
+    Map<String, LabelInfo> labels = initLabels(ctl, cd, labelTypes, standard);
     if (detailed) {
-      setAllApprovals(cd, labels);
+      setAllApprovals(ctl, cd, labels);
     }
     for (Map.Entry<String, LabelInfo> e : labels.entrySet()) {
       LabelType type = labelTypes.byLabel(e.getKey());
@@ -447,11 +403,11 @@
     return labels;
   }
 
-  private Map<String, LabelInfo> initLabels(ChangeData cd,
+  private Map<String, LabelInfo> initLabels(ChangeControl ctl, ChangeData cd,
       LabelTypes labelTypes, boolean standard) throws OrmException {
     // Don't use Maps.newTreeMap(Comparator) due to OpenJDK bug 100167.
     Map<String, LabelInfo> labels = new TreeMap<>(labelTypes.nameComparator());
-    for (SubmitRecord rec : submitRecords(cd)) {
+    for (SubmitRecord rec : submitRecords(ctl, cd)) {
       if (rec.labels == null) {
         continue;
       }
@@ -509,13 +465,8 @@
     }
   }
 
-  private void setAllApprovals(ChangeData cd,
+  private void setAllApprovals(ChangeControl baseCtrl, ChangeData cd,
       Map<String, LabelInfo> labels) throws OrmException {
-    ChangeControl baseCtrl = control(cd);
-    if (baseCtrl == null) {
-      return;
-    }
-
     // Include a user in the output for this label if either:
     //  - They are an explicit reviewer.
     //  - They ever voted on this change.
@@ -649,16 +600,15 @@
     }
   }
 
-  private Map<String, Collection<String>> permittedLabels(ChangeData cd)
+  private Map<String, Collection<String>> permittedLabels(ChangeControl ctl, ChangeData cd)
       throws OrmException {
-    ChangeControl ctl = control(cd);
     if (ctl == null) {
       return null;
     }
 
     LabelTypes labelTypes = ctl.getLabelTypes();
     SetMultimap<String, String> permitted = LinkedHashMultimap.create();
-    for (SubmitRecord rec : submitRecords(cd)) {
+    for (SubmitRecord rec : submitRecords(ctl, cd)) {
       if (rec.labels == null) {
         continue;
       }
@@ -689,14 +639,9 @@
     return permitted.asMap();
   }
 
-  private Collection<ChangeMessageInfo> messages(ChangeData cd,
+  private Collection<ChangeMessageInfo> messages(ChangeControl ctl, ChangeData cd,
       Map<PatchSet.Id, PatchSet> map)
       throws OrmException {
-    ChangeControl ctl = control(cd);
-    if (ctl == null) {
-      return null;
-    }
-
     List<ChangeMessage> messages =
         db.get().changeMessages().byChange(cd.getId()).toList();
     if (messages.isEmpty()) {
@@ -729,13 +674,8 @@
     return result;
   }
 
-  private Collection<AccountInfo> removableReviewers(ChangeData cd,
+  private Collection<AccountInfo> removableReviewers(ChangeControl ctl, ChangeData cd,
       Collection<LabelInfo> labels) throws OrmException {
-    ChangeControl ctl = control(cd);
-    if (ctl == null) {
-      return null;
-    }
-
     Set<Account.Id> fixed = Sets.newHashSetWithExpectedSize(labels.size());
     Set<Account.Id> removable = Sets.newHashSetWithExpectedSize(labels.size());
     for (LabelInfo label : labels) {
@@ -759,9 +699,9 @@
     return result;
   }
 
-  private void ensureReviewedLoaded(Iterable<ChangeData> all)
+  private Set<Change.Id> loadReviewed(Iterable<ChangeData> all)
       throws OrmException {
-    reviewed = Sets.newHashSet();
+    Set<Change.Id> reviewed = Sets.newHashSet();
     if (userProvider.get().isIdentifiedUser()) {
       Account.Id self = ((IdentifiedUser) userProvider.get()).getAccountId();
       for (List<ChangeData> batch : Iterables.partition(all, 50)) {
@@ -782,6 +722,7 @@
         }
       }
     }
+    return reviewed;
   }
 
   private boolean isChangeReviewed(Account.Id self, ChangeData cd,
@@ -805,20 +746,15 @@
     return false;
   }
 
-  private Map<String, RevisionInfo> revisions(ChangeData cd,
+  private Map<String, RevisionInfo> revisions(ChangeControl ctl, ChangeData cd,
       Optional<PatchSet.Id> limitToPsId, String project,
       Map<PatchSet.Id, PatchSet> map) throws OrmException {
-    ChangeControl ctl = control(cd);
-    if (ctl == null) {
-      return null;
-    }
-
     Map<String, RevisionInfo> res = Maps.newLinkedHashMap();
     for (PatchSet in : map.values()) {
       if ((has(ALL_REVISIONS)
           || in.getId().equals(cd.change().currentPatchSetId()))
           && ctl.isPatchVisible(in, db.get())) {
-        res.put(in.getRevision().get(), toRevisionInfo(cd, in, project));
+        res.put(in.getRevision().get(), toRevisionInfo(ctl, cd, in, project));
       }
     }
     return res;
@@ -852,13 +788,13 @@
     return map;
   }
 
-  private RevisionInfo toRevisionInfo(ChangeData cd, PatchSet in, String project)
-      throws OrmException {
+  private RevisionInfo toRevisionInfo(ChangeControl ctl, ChangeData cd,
+      PatchSet in, String project) throws OrmException {
     RevisionInfo out = new RevisionInfo();
     out.isCurrent = in.getId().equals(cd.change().currentPatchSetId());
     out._number = in.getId().get();
     out.draft = in.isDraft() ? true : null;
-    out.fetch = makeFetchMap(cd, in);
+    out.fetch = makeFetchMap(ctl, cd, in);
 
     if (has(ALL_COMMITS) || (out.isCurrent && has(CURRENT_COMMIT))) {
       try {
@@ -883,7 +819,7 @@
       out.actions = Maps.newTreeMap();
       for (UiAction.Description d : UiActions.from(
           revisions,
-          new RevisionResource(changes.parse(control(cd)), in),
+          new RevisionResource(new ChangeResource(ctl), in),
           userProvider)) {
         out.actions.put(d.getId(), new ActionInfo(d));
       }
@@ -928,7 +864,7 @@
     return commit;
   }
 
-  private Map<String, FetchInfo> makeFetchMap(ChangeData cd, PatchSet in)
+  private Map<String, FetchInfo> makeFetchMap(ChangeControl ctl, ChangeData cd, PatchSet in)
       throws OrmException {
     Map<String, FetchInfo> r = Maps.newLinkedHashMap();
 
@@ -940,7 +876,6 @@
         continue;
       }
 
-      ChangeControl ctl = control(cd);
       if (!scheme.isAuthSupported()
           && !ctl.forUser(anonymous).isPatchVisible(in, db.get())) {
         continue;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangesCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangesCollection.java
index 73f9b2e..b9b92cb 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangesCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangesCollection.java
@@ -32,10 +32,12 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import java.util.Collections;
 import java.util.List;
 
+@Singleton
 public class ChangesCollection implements
     RestCollection<TopLevelResource, ChangeResource>,
     AcceptsPost<TopLevelResource> {
@@ -44,7 +46,7 @@
   private final ChangeControl.GenericFactory changeControlFactory;
   private final Provider<QueryChanges> queryFactory;
   private final DynamicMap<RestView<ChangeResource>> views;
-  private final CreateChange.Factory createChangeFactory;
+  private final CreateChange createChange;
 
   @Inject
   ChangesCollection(
@@ -53,13 +55,13 @@
       ChangeControl.GenericFactory changeControlFactory,
       Provider<QueryChanges> queryFactory,
       DynamicMap<RestView<ChangeResource>> views,
-      CreateChange.Factory createChangeFactory) {
+      CreateChange createChange) {
     this.db = dbProvider;
     this.user = user;
     this.changeControlFactory = changeControlFactory;
     this.queryFactory = queryFactory;
     this.views = views;
-    this.createChangeFactory = createChangeFactory;
+    this.createChange = createChange;
   }
 
   @Override
@@ -135,6 +137,6 @@
   @SuppressWarnings("unchecked")
   @Override
   public CreateChange post(TopLevelResource parent) throws RestApiException {
-    return createChangeFactory.create();
+    return createChange;
   }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/CherryPickChange.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/CherryPickChange.java
index 3ae4602..b1f6d8c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/CherryPickChange.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/CherryPickChange.java
@@ -22,6 +22,7 @@
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.ChangeUtil;
+import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.GerritPersonIdent;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.events.CommitReceivedEvent;
@@ -39,6 +40,8 @@
 import com.google.gerrit.server.util.TimeUtil;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.MissingObjectException;
@@ -57,30 +60,34 @@
 
 import java.io.IOException;
 import java.util.List;
+import java.util.TimeZone;
 
+@Singleton
 public class CherryPickChange {
 
   private static final FooterKey CHANGE_ID = new FooterKey("Change-Id");
 
-  private final ReviewDb db;
+  private final Provider<ReviewDb> db;
   private final GitRepositoryManager gitManager;
-  private final PersonIdent myIdent;
-  private final IdentifiedUser currentUser;
+  private final TimeZone serverTimeZone;
+  private final Provider<CurrentUser> currentUser;
   private final CommitValidators.Factory commitValidatorsFactory;
   private final ChangeInserter.Factory changeInserterFactory;
   private final PatchSetInserter.Factory patchSetInserterFactory;
   final MergeUtil.Factory mergeUtilFactory;
 
   @Inject
-  CherryPickChange(final ReviewDb db, @GerritPersonIdent final PersonIdent myIdent,
-      final GitRepositoryManager gitManager, final IdentifiedUser currentUser,
+  CherryPickChange(final Provider<ReviewDb> db,
+      @GerritPersonIdent final PersonIdent myIdent,
+      final GitRepositoryManager gitManager,
+      final Provider<CurrentUser> currentUser,
       final CommitValidators.Factory commitValidatorsFactory,
       final ChangeInserter.Factory changeInserterFactory,
       final PatchSetInserter.Factory patchSetInserterFactory,
       final MergeUtil.Factory mergeUtilFactory) {
     this.db = db;
     this.gitManager = gitManager;
-    this.myIdent = myIdent;
+    this.serverTimeZone = myIdent.getTimeZone();
     this.currentUser = currentUser;
     this.commitValidatorsFactory = commitValidatorsFactory;
     this.changeInserterFactory = changeInserterFactory;
@@ -96,7 +103,7 @@
       InvalidChangeOperationException, MergeException {
 
     final Change.Id changeId = patchSetId.getParentKey();
-    final PatchSet patch = db.patchSets().get(patchSetId);
+    final PatchSet patch = db.get().patchSets().get(patchSetId);
     if (patch == null) {
       throw new NoSuchChangeException(changeId);
     }
@@ -105,7 +112,8 @@
           "Cherry Pick: Destination branch cannot be null or empty");
     }
 
-    Project.NameKey project = db.changes().get(changeId).getProject();
+    Project.NameKey project = db.get().changes().get(changeId).getProject();
+    IdentifiedUser identifiedUser = (IdentifiedUser) currentUser.get();
     final Repository git;
     try {
       git = gitManager.openRepository(project);
@@ -128,13 +136,13 @@
             revWalk.parseCommit(ObjectId.fromString(patch.getRevision().get()));
 
         PersonIdent committerIdent =
-            currentUser.newCommitterIdent(myIdent.getWhen(),
-                myIdent.getTimeZone());
+            identifiedUser.newCommitterIdent(TimeUtil.nowTs(),
+                serverTimeZone);
 
         final ObjectId computedChangeId =
             ChangeIdUtil
                 .computeChangeId(commitToCherryPick.getTree(), mergeTip,
-                    commitToCherryPick.getAuthorIdent(), myIdent, message);
+                    commitToCherryPick.getAuthorIdent(), committerIdent, message);
         String commitMessage =
             ChangeIdUtil.insertId(message, computedChangeId).trim() + '\n';
 
@@ -163,9 +171,9 @@
         }
 
         List<Change> destChanges =
-            db.changes()
+            db.get().changes()
                 .byBranchKey(
-                    new Branch.NameKey(db.changes().get(changeId).getProject(),
+                    new Branch.NameKey(db.get().changes().get(changeId).getProject(),
                         destRef.getName()), changeKey).toList();
 
         if (destChanges.size() > 1) {
@@ -176,12 +184,12 @@
           // The change key exists on the destination branch. The cherry pick
           // will be added as a new patch set.
           return insertPatchSet(git, revWalk, destChanges.get(0), patchSetId,
-              cherryPickCommit, refControl, currentUser);
+              cherryPickCommit, refControl, identifiedUser);
         } else {
           // Change key not found on destination branch. We can create a new
           // change.
           return createNewChange(git, revWalk, changeKey, project, patchSetId, destRef,
-              cherryPickCommit, refControl);
+              cherryPickCommit, refControl, identifiedUser);
         }
       } finally {
         revWalk.release();
@@ -193,7 +201,7 @@
 
   private Change.Id insertPatchSet(Repository git, RevWalk revWalk, Change change,
       PatchSet.Id patchSetId, RevCommit cherryPickCommit,
-      RefControl refControl, IdentifiedUser uploader)
+      RefControl refControl, IdentifiedUser identifiedUser)
       throws InvalidChangeOperationException, IOException, OrmException,
       NoSuchChangeException {
     final ChangeControl changeControl =
@@ -201,11 +209,11 @@
     final PatchSetInserter inserter = patchSetInserterFactory
         .create(git, revWalk, changeControl, cherryPickCommit);
     final PatchSet.Id newPatchSetId = inserter.getPatchSetId();
-    final PatchSet current = db.patchSets().get(change.currentPatchSetId());
+    PatchSet current = db.get().patchSets().get(change.currentPatchSetId());
     inserter
       .setMessage("Uploaded patch set " + newPatchSetId.get() + ".")
       .setDraft(current.isDraft())
-      .setUploader(uploader.getAccountId())
+      .setUploader(identifiedUser.getAccountId())
       .setCopyLabels(true)
       .insert();
     return change.getId();
@@ -213,11 +221,12 @@
 
   private Change.Id createNewChange(Repository git, RevWalk revWalk,
       Change.Key changeKey, Project.NameKey project, PatchSet.Id patchSetId,
-      Ref destRef, RevCommit cherryPickCommit, RefControl refControl)
+      Ref destRef, RevCommit cherryPickCommit, RefControl refControl,
+      IdentifiedUser identifiedUser)
       throws OrmException, InvalidChangeOperationException, IOException {
     Change change =
-        new Change(changeKey, new Change.Id(db.nextChangeId()),
-            currentUser.getAccountId(), new Branch.NameKey(project,
+        new Change(changeKey, new Change.Id(db.get().nextChangeId()),
+            identifiedUser.getAccountId(), new Branch.NameKey(project,
                 destRef.getName()), TimeUtil.nowTs());
     ChangeInserter ins =
         changeInserterFactory.create(refControl, change, cherryPickCommit);
@@ -229,7 +238,7 @@
         new CommitReceivedEvent(new ReceiveCommand(ObjectId.zeroId(),
             cherryPickCommit.getId(), newPatchSet.getRefName()), refControl
             .getProjectControl().getProject(), refControl.getRefName(),
-            cherryPickCommit, currentUser);
+            cherryPickCommit, identifiedUser);
 
     try {
       commitValidators.validateForGerritCommits(commitReceivedEvent);
@@ -247,18 +256,20 @@
           change.getDest().getParentKey().get(), ru.getResult()));
     }
 
-    ins.setMessage(buildChangeMessage(patchSetId, change, cherryPickCommit))
+    ins.setMessage(buildChangeMessage(patchSetId, change, cherryPickCommit,
+        identifiedUser))
         .insert();
 
     return change.getId();
   }
 
   private ChangeMessage buildChangeMessage(PatchSet.Id patchSetId, Change dest,
-      RevCommit cherryPickCommit) throws OrmException {
+      RevCommit cherryPickCommit, IdentifiedUser identifiedUser)
+      throws OrmException {
     ChangeMessage cmsg = new ChangeMessage(
         new ChangeMessage.Key(
-            patchSetId.getParentKey(), ChangeUtil.messageUUID(db)),
-        currentUser.getAccountId(), TimeUtil.nowTs(), patchSetId);
+            patchSetId.getParentKey(), ChangeUtil.messageUUID(db.get())),
+            identifiedUser.getAccountId(), TimeUtil.nowTs(), patchSetId);
     String destBranchName = dest.getDest().get();
     StringBuilder msgBuf = new StringBuilder("Patch Set ")
         .append(patchSetId.get())
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Comments.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Comments.java
index 91cfbf8..bc67d4a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Comments.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Comments.java
@@ -24,7 +24,9 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
+@Singleton
 class Comments implements ChildCollection<RevisionResource, CommentResource> {
   private final DynamicMap<RestView<CommentResource>> views;
   private final Provider<ListComments> list;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/CreateChange.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/CreateChange.java
index f1e4309..8f96c60 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/CreateChange.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/CreateChange.java
@@ -47,6 +47,7 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import org.eclipse.jgit.lib.CommitBuilder;
 import org.eclipse.jgit.lib.Constants;
@@ -63,18 +64,17 @@
 
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
+import java.sql.Timestamp;
 import java.util.List;
+import java.util.TimeZone;
 
+@Singleton
 public class CreateChange implements
     RestModifyView<TopLevelResource, ChangeInfo> {
 
-  public static interface Factory {
-    CreateChange create();
-  }
-
-  private final ReviewDb db;
+  private final Provider<ReviewDb> db;
   private final GitRepositoryManager gitManager;
-  private final PersonIdent myIdent;
+  private final TimeZone serverTimeZone;
   private final Provider<CurrentUser> userProvider;
   private final Provider<ProjectsCollection> projectsCollection;
   private final CommitValidators.Factory commitValidatorsFactory;
@@ -82,7 +82,7 @@
   private final ChangeJson json;
 
   @Inject
-  CreateChange(ReviewDb db,
+  CreateChange(Provider<ReviewDb> db,
       GitRepositoryManager gitManager,
       @GerritPersonIdent PersonIdent myIdent,
       Provider<CurrentUser> userProvider,
@@ -92,7 +92,7 @@
       ChangeJson json) {
     this.db = db;
     this.gitManager = gitManager;
-    this.myIdent = myIdent;
+    this.serverTimeZone = myIdent.getTimeZone();
     this.userProvider = userProvider;
     this.projectsCollection = projectsCollection;
     this.commitValidatorsFactory = commitValidatorsFactory;
@@ -154,9 +154,9 @@
               "Branch %s does not exist.", refName));
         }
 
-        IdentifiedUser me = (IdentifiedUser)userProvider.get();
-        PersonIdent author =
-            me.newCommitterIdent(myIdent.getWhen(), myIdent.getTimeZone());
+        Timestamp now = TimeUtil.nowTs();
+        IdentifiedUser me = (IdentifiedUser) userProvider.get();
+        PersonIdent author = me.newCommitterIdent(now, serverTimeZone);
 
         RevCommit mergeTip = rw.parseCommit(destRef.getObjectId());
         ObjectId id = ChangeIdUtil.computeChangeId(mergeTip.getTree(),
@@ -167,10 +167,10 @@
 
         Change change = new Change(
             getChangeId(id, c),
-            new Change.Id(db.nextChangeId()),
+            new Change.Id(db.get().nextChangeId()),
             me.getAccountId(),
             new Branch.NameKey(project, destRef.getName()),
-            TimeUtil.nowTs());
+            now);
 
         ChangeInserter ins =
             changeInserterFactory.create(refControl, change, c);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/CreateDraft.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/CreateDraft.java
index afd0b85..1d2fa406 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/CreateDraft.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/CreateDraft.java
@@ -29,9 +29,11 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import java.util.Collections;
 
+@Singleton
 class CreateDraft implements RestModifyView<RevisionResource, Input> {
   private final Provider<ReviewDb> db;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraft.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraft.java
index 588c372..46ae834 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraft.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraft.java
@@ -21,9 +21,11 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import java.util.Collections;
 
+@Singleton
 class DeleteDraft implements RestModifyView<DraftResource, Input> {
   static class Input {
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteReviewer.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteReviewer.java
index b4dcdd7..a1245fb 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteReviewer.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteReviewer.java
@@ -37,11 +37,13 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import java.io.IOException;
 import java.util.Collections;
 import java.util.List;
 
+@Singleton
 public class DeleteReviewer implements RestModifyView<ReviewerResource, Input> {
   public static class Input {
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Drafts.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Drafts.java
index 8fc05be..0b0bb53 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Drafts.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Drafts.java
@@ -26,7 +26,9 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
+@Singleton
 class Drafts implements ChildCollection<RevisionResource, DraftResource> {
   private final DynamicMap<RestView<DraftResource>> views;
   private final Provider<CurrentUser> user;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetComment.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetComment.java
index 3606eed..27de91c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetComment.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetComment.java
@@ -18,7 +18,9 @@
 import com.google.gerrit.server.account.AccountInfo;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
+@Singleton
 class GetComment implements RestReadView<CommentResource> {
 
   private final AccountInfo.Loader.Factory accountLoaderFactory;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetCommit.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetCommit.java
index 679466a..2cd948e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetCommit.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetCommit.java
@@ -22,9 +22,11 @@
 import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
 import java.util.concurrent.TimeUnit;
 
+@Singleton
 public class GetCommit implements RestReadView<RevisionResource> {
   private final ChangeJson json;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetContent.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetContent.java
index 86a3da6..bfc1df9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetContent.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetContent.java
@@ -20,6 +20,7 @@
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
 import org.eclipse.jgit.lib.ObjectLoader;
 import org.eclipse.jgit.lib.Repository;
@@ -30,6 +31,7 @@
 import java.io.IOException;
 import java.io.OutputStream;
 
+@Singleton
 public class GetContent implements RestReadView<FileResource> {
   private final GitRepositoryManager repoManager;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDraft.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDraft.java
index c8a2d43..275b418 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDraft.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDraft.java
@@ -15,7 +15,9 @@
 package com.google.gerrit.server.change;
 
 import com.google.gerrit.extensions.restapi.RestReadView;
+import com.google.inject.Singleton;
 
+@Singleton
 class GetDraft implements RestReadView<DraftResource> {
   @Override
   public CommentInfo apply(DraftResource rsrc) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetRelated.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetRelated.java
index 81debde..0ccb15c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetRelated.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetRelated.java
@@ -34,6 +34,7 @@
 import com.google.gwtorm.server.ResultSet;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.RepositoryNotFoundException;
@@ -57,6 +58,7 @@
 import java.util.Map;
 import java.util.Set;
 
+@Singleton
 public class GetRelated implements RestReadView<RevisionResource> {
   private static final Logger log = LoggerFactory.getLogger(GetRelated.class);
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetReview.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetReview.java
index b646dd6..9f98590 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetReview.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetReview.java
@@ -20,7 +20,9 @@
 import com.google.gerrit.server.change.ChangeJson.ChangeInfo;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
+@Singleton
 public class GetReview implements RestReadView<RevisionResource> {
   private final GetChange delegate;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetReviewer.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetReviewer.java
index fac4618..c90b3bc 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetReviewer.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetReviewer.java
@@ -18,9 +18,11 @@
 import com.google.gerrit.server.change.ReviewerJson.ReviewerInfo;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
 import java.util.List;
 
+@Singleton
 public class GetReviewer implements RestReadView<ReviewerResource> {
   private final ReviewerJson json;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetTopic.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetTopic.java
index 53f71fd..3a2f7e7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetTopic.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetTopic.java
@@ -16,7 +16,9 @@
 
 import com.google.common.base.Strings;
 import com.google.gerrit.extensions.restapi.RestReadView;
+import com.google.inject.Singleton;
 
+@Singleton
 class GetTopic implements RestReadView<ChangeResource> {
   @Override
   public String apply(ChangeResource rsrc) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/IncludedIn.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/IncludedIn.java
index 8df6957..ceaeff7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/IncludedIn.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/IncludedIn.java
@@ -24,6 +24,7 @@
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
+import com.google.inject.Provider;
 
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.MissingObjectException;
@@ -37,11 +38,11 @@
 
 class IncludedIn implements RestReadView<ChangeResource> {
 
-  private final ReviewDb db;
+  private final Provider<ReviewDb> db;
   private final GitRepositoryManager repoManager;
 
   @Inject
-  IncludedIn(ReviewDb db, GitRepositoryManager repoManager) {
+  IncludedIn(Provider<ReviewDb> db, GitRepositoryManager repoManager) {
     this.db = db;
     this.repoManager = repoManager;
   }
@@ -51,7 +52,7 @@
       ResourceConflictException, OrmException, IOException {
     ChangeControl ctl = rsrc.getControl();
     PatchSet ps =
-        db.patchSets().get(ctl.getChange().currentPatchSetId());
+        db.get().patchSets().get(ctl.getChange().currentPatchSetId());
     Repository r =
         repoManager.openRepository(ctl.getProject().getNameKey());
     try {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Index.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Index.java
index f773f2f..6cf3e00 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Index.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Index.java
@@ -23,10 +23,12 @@
 import com.google.gerrit.server.index.ChangeIndexer;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import java.io.IOException;
 
 @RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
+@Singleton
 public class Index implements RestModifyView<ChangeResource, Input> {
   public static class Input {
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Mergeable.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Mergeable.java
index e785736..f2c4adc 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Mergeable.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Mergeable.java
@@ -24,12 +24,14 @@
 import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gerrit.reviewdb.client.RevId;
 import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.git.BranchOrderSection;
 import com.google.gerrit.server.git.CodeReviewCommit;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.MergeException;
 import com.google.gerrit.server.git.strategy.SubmitStrategyFactory;
 import com.google.gerrit.server.index.ChangeIndexer;
 import com.google.gerrit.server.project.NoSuchProjectException;
+import com.google.gerrit.server.project.ProjectCache;
 import com.google.gwtorm.server.AtomicUpdate;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
@@ -73,6 +75,7 @@
 
   private final TestSubmitType.Get submitType;
   private final GitRepositoryManager gitManager;
+  private final ProjectCache projectCache;
   private final SubmitStrategyFactory submitStrategyFactory;
   private final Provider<ReviewDb> db;
   private final ChangeIndexer indexer;
@@ -82,11 +85,13 @@
   @Inject
   Mergeable(TestSubmitType.Get submitType,
       GitRepositoryManager gitManager,
+      ProjectCache projectCache,
       SubmitStrategyFactory submitStrategyFactory,
       Provider<ReviewDb> db,
       ChangeIndexer indexer) {
     this.submitType = submitType;
     this.gitManager = gitManager;
+    this.projectCache = projectCache;
     this.submitStrategyFactory = submitStrategyFactory;
     this.db = db;
     this.indexer = indexer;
@@ -124,11 +129,17 @@
 
       if (otherBranches) {
         result.mergeableInto = new ArrayList<>();
-        for (Ref r : refs.values()) {
-          if (r.getName().startsWith(Constants.R_HEADS)
-              && !r.getName().equals(ref.getName())) {
-            if (isMergeable(change, ps, SubmitType.CHERRY_PICK, git, refs, r)) {
-              result.mergeableInto.add(r.getName());
+        BranchOrderSection branchOrder =
+            projectCache.get(change.getProject()).getBranchOrderSection();
+        if (branchOrder != null) {
+          int prefixLen = Constants.R_HEADS.length();
+          for (String n : branchOrder.getMoreStable(ref.getName())) {
+            Ref other = refs.get(n);
+            if (other == null) {
+              continue;
+            }
+            if (isMergeable(change, ps, SubmitType.CHERRY_PICK, git, refs, other)) {
+              result.mergeableInto.add(other.getName().substring(prefixLen));
             }
           }
         }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Module.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Module.java
index acb6eef..6880ca2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Module.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Module.java
@@ -107,7 +107,6 @@
         factory(EmailReviewComments.Factory.class);
         factory(ChangeInserter.Factory.class);
         factory(PatchSetInserter.Factory.class);
-        factory(CreateChange.Factory.class);
       }
     });
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReviewers.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReviewers.java
index 7f6fc97..d7a6747 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReviewers.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReviewers.java
@@ -36,6 +36,7 @@
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.ApprovalsUtil;
 import com.google.gerrit.server.ChangeUtil;
+import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.account.AccountCache;
 import com.google.gerrit.server.account.AccountInfo;
@@ -54,6 +55,7 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import org.eclipse.jgit.lib.Config;
 import org.slf4j.Logger;
@@ -65,6 +67,7 @@
 import java.util.Map;
 import java.util.Set;
 
+@Singleton
 public class PostReviewers implements RestModifyView<ChangeResource, AddReviewerInput> {
   private static final Logger log = LoggerFactory
       .getLogger(PostReviewers.class);
@@ -81,7 +84,7 @@
   private final AccountInfo.Loader.Factory accountLoaderFactory;
   private final Provider<ReviewDb> dbProvider;
   private final ChangeUpdate.Factory updateFactory;
-  private final IdentifiedUser currentUser;
+  private final Provider<CurrentUser> currentUser;
   private final IdentifiedUser.GenericFactory identifiedUserFactory;
   private final Config cfg;
   private final ChangeHooks hooks;
@@ -99,7 +102,7 @@
       AccountInfo.Loader.Factory accountLoaderFactory,
       Provider<ReviewDb> db,
       ChangeUpdate.Factory updateFactory,
-      IdentifiedUser currentUser,
+      Provider<CurrentUser> currentUser,
       IdentifiedUser.GenericFactory identifiedUserFactory,
       @GerritServerConfig Config cfg,
       ChangeHooks hooks,
@@ -268,15 +271,16 @@
     //
     // The user knows they added themselves, don't bother emailing them.
     List<Account.Id> toMail = Lists.newArrayListWithCapacity(added.size());
+    IdentifiedUser identifiedUser = (IdentifiedUser) currentUser.get();
     for (PatchSetApproval psa : added) {
-      if (!psa.getAccountId().equals(currentUser.getAccountId())) {
+      if (!psa.getAccountId().equals(identifiedUser.getAccountId())) {
         toMail.add(psa.getAccountId());
       }
     }
     if (!toMail.isEmpty()) {
       try {
         AddReviewerSender cm = addReviewerSenderFactory.create(change);
-        cm.setFrom(currentUser.getAccountId());
+        cm.setFrom(identifiedUser.getAccountId());
         cm.addReviewers(toMail);
         cm.send();
       } catch (Exception err) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/PutDraft.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/PutDraft.java
index 881b876..d010b2a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/PutDraft.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/PutDraft.java
@@ -29,10 +29,12 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import java.sql.Timestamp;
 import java.util.Collections;
 
+@Singleton
 class PutDraft implements RestModifyView<DraftResource, Input> {
   static class Input {
     String kind;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Rebase.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Rebase.java
index bbd501c..6322668 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Rebase.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Rebase.java
@@ -49,7 +49,9 @@
   @Inject
   public Rebase(Provider<RebaseChange> rebaseChange, ChangeJson json) {
     this.rebaseChange = rebaseChange;
-    this.json = json;
+    this.json = json
+        .addOption(ListChangesOption.CURRENT_REVISION)
+        .addOption(ListChangesOption.CURRENT_COMMIT);
   }
 
   @Override
@@ -75,8 +77,6 @@
       throw new ResourceNotFoundException(change.getId().toString());
     }
 
-    json.addOption(ListChangesOption.CURRENT_REVISION)
-        .addOption(ListChangesOption.CURRENT_COMMIT);
     return json.format(change.getId());
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Reviewed.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Reviewed.java
index dd27139..c138a60 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Reviewed.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Reviewed.java
@@ -22,6 +22,7 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import java.util.Collections;
 
@@ -29,6 +30,7 @@
   static class Input {
   }
 
+  @Singleton
   static class PutReviewed implements RestModifyView<FileResource, Input> {
     private final Provider<ReviewDb> dbProvider;
 
@@ -57,6 +59,7 @@
     }
   }
 
+  @Singleton
   static class DeleteReviewed implements RestModifyView<FileResource, Input> {
     private final Provider<ReviewDb> dbProvider;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ReviewerJson.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ReviewerJson.java
index 2b9ca6a..d8c3cef 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ReviewerJson.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ReviewerJson.java
@@ -35,12 +35,14 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.TreeMap;
 
+@Singleton
 public class ReviewerJson {
   private final Provider<ReviewDb> db;
   private final ChangeData.Factory changeDataFactory;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Reviewers.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Reviewers.java
index e7c913a..ba4504d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Reviewers.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Reviewers.java
@@ -28,9 +28,11 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import java.util.Collection;
 
+@Singleton
 public class Reviewers implements
     ChildCollection<ChangeResource, ReviewerResource> {
   private final DynamicMap<RestView<ReviewerResource>> views;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Revisions.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Revisions.java
index 19c6d3a..239aae2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Revisions.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Revisions.java
@@ -27,10 +27,12 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import java.util.Collections;
 import java.util.List;
 
+@Singleton
 public class Revisions implements ChildCollection<ChangeResource, RevisionResource> {
   private final DynamicMap<RestView<RevisionResource>> views;
   private final Provider<ReviewDb> dbProvider;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/TestSubmitRule.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/TestSubmitRule.java
index 4f739e6..25070ab 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/TestSubmitRule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/TestSubmitRule.java
@@ -37,6 +37,7 @@
 import com.google.gerrit.server.query.change.ChangeData;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
+import com.google.inject.Provider;
 
 import com.googlecode.prolog_cafe.lang.Term;
 
@@ -57,7 +58,7 @@
     public Filters filters;
   }
 
-  private final ReviewDb db;
+  private final Provider<ReviewDb> db;
   private final ChangeData.Factory changeDataFactory;
   private final RulesCache rules;
   private final AccountInfo.Loader.Factory accountInfoFactory;
@@ -66,7 +67,7 @@
   private Filters filters = Filters.RUN;
 
   @Inject
-  TestSubmitRule(ReviewDb db,
+  TestSubmitRule(Provider<ReviewDb> db,
       ChangeData.Factory changeDataFactory,
       RulesCache rules,
       AccountInfo.Loader.Factory infoFactory) {
@@ -88,12 +89,12 @@
     input.filters = Objects.firstNonNull(input.filters, filters);
 
     SubmitRuleEvaluator evaluator = new SubmitRuleEvaluator(
-        db,
+        db.get(),
         rsrc.getPatchSet(),
         rsrc.getControl().getProjectControl(),
         rsrc.getControl(),
         rsrc.getChange(),
-        changeDataFactory.create(db, rsrc.getChange()),
+        changeDataFactory.create(db.get(), rsrc.getChange()),
         false,
         "locate_submit_rule", "can_submit",
         "locate_submit_filter", "filter_submit_results",
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/TestSubmitType.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/TestSubmitType.java
index 92ff87b..3b7f419 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/TestSubmitType.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/TestSubmitType.java
@@ -30,6 +30,7 @@
 import com.google.gerrit.server.project.SubmitRuleEvaluator;
 import com.google.gerrit.server.query.change.ChangeData;
 import com.google.inject.Inject;
+import com.google.inject.Provider;
 
 import com.googlecode.prolog_cafe.lang.SymbolTerm;
 import com.googlecode.prolog_cafe.lang.Term;
@@ -40,7 +41,7 @@
 import java.util.List;
 
 public class TestSubmitType implements RestModifyView<RevisionResource, Input> {
-  private final ReviewDb db;
+  private final Provider<ReviewDb> db;
   private final ChangeData.Factory changeDataFactory;
   private final RulesCache rules;
 
@@ -48,7 +49,7 @@
   private Filters filters = Filters.RUN;
 
   @Inject
-  TestSubmitType(ReviewDb db,
+  TestSubmitType(Provider<ReviewDb> db,
       ChangeData.Factory changeDataFactory,
       RulesCache rules) {
     this.db = db;
@@ -68,12 +69,12 @@
     input.filters = Objects.firstNonNull(input.filters, filters);
 
     SubmitRuleEvaluator evaluator = new SubmitRuleEvaluator(
-        db,
+        db.get(),
         rsrc.getPatchSet(),
         rsrc.getControl().getProjectControl(),
         rsrc.getControl(),
         rsrc.getChange(),
-        changeDataFactory.create(db, rsrc.getChange()),
+        changeDataFactory.create(db.get(), rsrc.getChange()),
         false,
         "locate_submit_type", "get_submit_type",
         "locate_submit_type_filter", "filter_submit_type_results",
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/RebaseChange.java b/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/RebaseChange.java
index 8de6904..f0b027a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/RebaseChange.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/RebaseChange.java
@@ -14,8 +14,6 @@
 
 package com.google.gerrit.server.changedetail;
 
-import static com.google.gerrit.server.change.PatchSetInserter.ValidatePolicy;
-
 import com.google.gerrit.common.errors.EmailException;
 import com.google.gerrit.reviewdb.client.Branch;
 import com.google.gerrit.reviewdb.client.Change;
@@ -29,6 +27,7 @@
 import com.google.gerrit.server.GerritPersonIdent;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.change.PatchSetInserter;
+import com.google.gerrit.server.change.PatchSetInserter.ValidatePolicy;
 import com.google.gerrit.server.change.RevisionResource;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.MergeUtil;
@@ -38,6 +37,8 @@
 import com.google.gerrit.server.util.TimeUtil;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import org.eclipse.jgit.errors.RepositoryNotFoundException;
 import org.eclipse.jgit.lib.CommitBuilder;
@@ -52,18 +53,20 @@
 
 import java.io.IOException;
 import java.util.List;
+import java.util.TimeZone;
 
+@Singleton
 public class RebaseChange {
   private final ChangeControl.GenericFactory changeControlFactory;
-  private final ReviewDb db;
+  private final Provider<ReviewDb> db;
   private final GitRepositoryManager gitManager;
-  private final PersonIdent myIdent;
+  private final TimeZone serverTimeZone;
   private final MergeUtil.Factory mergeUtilFactory;
   private final PatchSetInserter.Factory patchSetInserterFactory;
 
   @Inject
   RebaseChange(final ChangeControl.GenericFactory changeControlFactory,
-      final ReviewDb db,
+      final Provider<ReviewDb> db,
       @GerritPersonIdent final PersonIdent myIdent,
       final GitRepositoryManager gitManager,
       final MergeUtil.Factory mergeUtilFactory,
@@ -71,7 +74,7 @@
     this.changeControlFactory = changeControlFactory;
     this.db = db;
     this.gitManager = gitManager;
-    this.myIdent = myIdent;
+    this.serverTimeZone = myIdent.getTimeZone();
     this.mergeUtilFactory = mergeUtilFactory;
     this.patchSetInserterFactory = patchSetInserterFactory;
   }
@@ -122,14 +125,14 @@
       rw = new RevWalk(git);
       inserter = git.newObjectInserter();
 
-      final String baseRev = findBaseRevision(patchSetId, db,
+      final String baseRev = findBaseRevision(patchSetId, db.get(),
           change.getDest(), git, null, null, null);
       final RevCommit baseCommit =
           rw.parseCommit(ObjectId.fromString(baseRev));
 
       PersonIdent committerIdent =
-          uploader.newCommitterIdent(myIdent.getWhen(),
-              myIdent.getTimeZone());
+          uploader.newCommitterIdent(TimeUtil.nowTs(),
+              serverTimeZone);
 
       rebase(git, rw, inserter, patchSetId, change,
           uploader, baseCommit, mergeUtilFactory.create(
@@ -282,7 +285,7 @@
     if (!change.currentPatchSetId().equals(patchSetId)) {
       throw new InvalidChangeOperationException("patch set is not current");
     }
-    final PatchSet originalPatchSet = db.patchSets().get(patchSetId);
+    final PatchSet originalPatchSet = db.get().patchSets().get(patchSetId);
 
     final RevCommit rebasedCommit;
     ObjectId oldId = ObjectId.fromString(originalPatchSet.getRevision().get());
@@ -305,8 +308,9 @@
 
     final PatchSet.Id newPatchSetId = patchSetInserter.getPatchSetId();
     final ChangeMessage cmsg = new ChangeMessage(
-        new ChangeMessage.Key(change.getId(), ChangeUtil.messageUUID(db)),
-        uploader.getAccountId(), TimeUtil.nowTs(), patchSetId);
+        new ChangeMessage.Key(change.getId(),
+            ChangeUtil.messageUUID(db.get())), uploader.getAccountId(),
+            TimeUtil.nowTs(), patchSetId);
 
     cmsg.setMessage("Patch Set " + newPatchSetId.get()
         + ": Patch Set " + patchSetId.get() + " was rebased");
@@ -315,7 +319,7 @@
         .setMessage(cmsg)
         .insert();
 
-    return db.patchSets().get(newChange.currentPatchSetId());
+    return db.get().patchSets().get(newChange.currentPatchSetId());
   }
 
   /**
@@ -375,7 +379,7 @@
     try {
       findBaseRevision(
           r.getPatchSet().getId(),
-          db,
+          db.get(),
           r.getChange().getDest(),
           git,
           null,
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/CacheResource.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/CacheResource.java
new file mode 100644
index 0000000..9019f4d
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/CacheResource.java
@@ -0,0 +1,49 @@
+// Copyright (C) 2014 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.config;
+
+import com.google.common.cache.Cache;
+import com.google.gerrit.extensions.restapi.RestView;
+import com.google.inject.Provider;
+import com.google.inject.TypeLiteral;
+
+public class CacheResource extends ConfigResource {
+  public static final TypeLiteral<RestView<CacheResource>> CACHE_KIND =
+      new TypeLiteral<RestView<CacheResource>>() {};
+
+  private final String name;
+  private final Provider<Cache<?, ?>> cacheProvider;
+
+  public CacheResource(String pluginName, String cacheName, Provider<Cache<?, ?>> cacheProvider) {
+    this.name = cacheNameOf(pluginName, cacheName);
+    this.cacheProvider = cacheProvider;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public Cache<?, ?> getCache() {
+    return cacheProvider.get();
+  }
+
+  public static String cacheNameOf(String plugin, String name) {
+    if ("gerrit".equals(plugin)) {
+      return name;
+    } else {
+      return plugin + "-" + name;
+    }
+  }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/CachesCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/CachesCollection.java
new file mode 100644
index 0000000..e288456
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/CachesCollection.java
@@ -0,0 +1,88 @@
+// Copyright (C) 2014 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.config;
+
+import com.google.common.cache.Cache;
+import com.google.gerrit.common.data.GlobalCapability;
+import com.google.gerrit.extensions.annotations.RequiresCapability;
+import com.google.gerrit.extensions.registration.DynamicMap;
+import com.google.gerrit.extensions.restapi.AuthException;
+import com.google.gerrit.extensions.restapi.ChildCollection;
+import com.google.gerrit.extensions.restapi.IdString;
+import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
+import com.google.gerrit.extensions.restapi.RestView;
+import com.google.gerrit.server.AnonymousUser;
+import com.google.gerrit.server.CurrentUser;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+
+@RequiresCapability(GlobalCapability.VIEW_CACHES)
+@Singleton
+public class CachesCollection implements
+    ChildCollection<ConfigResource, CacheResource> {
+
+  private final DynamicMap<RestView<CacheResource>> views;
+  private final Provider<ListCaches> list;
+  private final Provider<CurrentUser> self;
+  private final DynamicMap<Cache<?, ?>> cacheMap;
+
+  @Inject
+  CachesCollection(DynamicMap<RestView<CacheResource>> views,
+      Provider<ListCaches> list, Provider<CurrentUser> self,
+      DynamicMap<Cache<?, ?>> cacheMap) {
+    this.views = views;
+    this.list = list;
+    this.self = self;
+    this.cacheMap = cacheMap;
+  }
+
+  @Override
+  public RestView<ConfigResource> list() {
+    return list.get();
+  }
+
+  @Override
+  public CacheResource parse(ConfigResource parent, IdString id)
+      throws AuthException, ResourceNotFoundException {
+    CurrentUser user = self.get();
+    if (user instanceof AnonymousUser) {
+      throw new AuthException("Authentication required");
+    } else if (!user.isIdentifiedUser()) {
+      throw new ResourceNotFoundException();
+    } else if (!user.getCapabilities().canViewCaches()) {
+      throw new AuthException("not allowed to view caches");
+    }
+
+    String cacheName = id.get();
+    String pluginName = "gerrit";
+    int i = cacheName.lastIndexOf('-');
+    if (i != -1) {
+      pluginName = cacheName.substring(0, i);
+      cacheName = cacheName.length() > i + 1 ? cacheName.substring(i + 1) : "";
+    }
+
+    Provider<Cache<?, ?>> cacheProvider = cacheMap.byPlugin(pluginName).get(cacheName);
+    if (cacheProvider == null) {
+      throw new ResourceNotFoundException(id);
+    }
+    return new CacheResource(pluginName, cacheName, cacheProvider);
+  }
+
+  @Override
+  public DynamicMap<RestView<CacheResource>> views() {
+    return views;
+  }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/CapabilitiesCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/CapabilitiesCollection.java
index 3a8bcc5..a9f22a2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/CapabilitiesCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/CapabilitiesCollection.java
@@ -21,7 +21,9 @@
 import com.google.gerrit.extensions.restapi.RestView;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
+@Singleton
 public class CapabilitiesCollection implements
     ChildCollection<ConfigResource, CapabilityResource> {
   private final DynamicMap<RestView<CapabilityResource>> views;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GetCache.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GetCache.java
new file mode 100644
index 0000000..53628cc
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GetCache.java
@@ -0,0 +1,28 @@
+// Copyright (C) 2014 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.config;
+
+import com.google.gerrit.extensions.restapi.RestReadView;
+import com.google.gerrit.server.config.ListCaches.CacheInfo;
+import com.google.inject.Singleton;
+
+@Singleton
+public class GetCache implements RestReadView<CacheResource> {
+
+  @Override
+  public CacheInfo apply(CacheResource rsrc) {
+    return new CacheInfo(rsrc.getName(), rsrc.getCache());
+  }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GetPreferences.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GetPreferences.java
index f6c1d1d..e915427 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GetPreferences.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GetPreferences.java
@@ -19,12 +19,14 @@
 import com.google.gerrit.server.account.VersionedAccountPreferences;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.lib.Repository;
 
 import java.io.IOException;
 
+@Singleton
 public class GetPreferences implements RestReadView<ConfigResource> {
   private final AllUsersName allUsersName;
   private final GitRepositoryManager gitMgr;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GetVersion.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GetVersion.java
index f618959c..c71cb69 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GetVersion.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GetVersion.java
@@ -17,7 +17,9 @@
 import com.google.gerrit.common.Version;
 import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
 import com.google.gerrit.extensions.restapi.RestReadView;
+import com.google.inject.Singleton;
 
+@Singleton
 public class GetVersion implements RestReadView<ConfigResource> {
   @Override
   public String apply(ConfigResource resource) throws ResourceNotFoundException {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/ListCaches.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/ListCaches.java
new file mode 100644
index 0000000..6c5e9f1
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/ListCaches.java
@@ -0,0 +1,163 @@
+// Copyright (C) 2014 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.config;
+
+import static com.google.gerrit.server.config.CacheResource.cacheNameOf;
+
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheStats;
+import com.google.gerrit.common.data.GlobalCapability;
+import com.google.gerrit.extensions.annotations.RequiresCapability;
+import com.google.gerrit.extensions.registration.DynamicMap;
+import com.google.gerrit.extensions.restapi.RestReadView;
+import com.google.gerrit.server.cache.PersistentCache;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+import java.util.Map;
+import java.util.TreeMap;
+
+@RequiresCapability(GlobalCapability.VIEW_CACHES)
+@Singleton
+public class ListCaches implements RestReadView<ConfigResource> {
+  private final DynamicMap<Cache<?, ?>> cacheMap;
+
+  @Inject
+  public ListCaches(DynamicMap<Cache<?, ?>> cacheMap) {
+    this.cacheMap = cacheMap;
+  }
+
+  @Override
+  public Map<String, CacheInfo> apply(ConfigResource rsrc) {
+    Map<String, CacheInfo> cacheInfos = new TreeMap<>();
+    for (DynamicMap.Entry<Cache<?, ?>> e : cacheMap) {
+      cacheInfos.put(cacheNameOf(e.getPluginName(), e.getExportName()),
+          new CacheInfo(e.getProvider().get()));
+    }
+    return cacheInfos;
+  }
+
+  public enum CacheType {
+    MEM, DISK;
+  }
+
+  public static class CacheInfo {
+    public String name;
+    public CacheType type;
+    public EntriesInfo entries;
+    public String averageGet;
+    public HitRatioInfo hitRatio;
+
+    public CacheInfo(Cache<?,?> cache) {
+      this(null, cache);
+    }
+
+    public CacheInfo(String name, Cache<?,?> cache) {
+      this.name = name;
+
+      CacheStats stat = cache.stats();
+
+      entries = new EntriesInfo();
+      entries.setMem(cache.size());
+
+      averageGet = duration(stat.averageLoadPenalty());
+
+      hitRatio = new HitRatioInfo();
+      hitRatio.setMem(stat.hitCount(), stat.requestCount());
+
+      if (cache instanceof PersistentCache) {
+        type = CacheType.DISK;
+        PersistentCache.DiskStats diskStats =
+            ((PersistentCache) cache).diskStats();
+        entries.setDisk(diskStats.size());
+        entries.setSpace(diskStats.space());
+        hitRatio.setDisk(diskStats.hitCount(), diskStats.requestCount());
+      }
+    }
+
+    private static String duration(double ns) {
+      if (ns < 0.5) {
+        return null;
+      }
+      String suffix = "ns";
+      if (ns >= 1000.0) {
+        ns /= 1000.0;
+        suffix = "us";
+      }
+      if (ns >= 1000.0) {
+        ns /= 1000.0;
+        suffix = "ms";
+      }
+      if (ns >= 1000.0) {
+        ns /= 1000.0;
+        suffix = "s";
+      }
+      return String.format("%4.1f%s", ns, suffix).trim();
+    }
+  }
+
+  public static class EntriesInfo {
+    public Long mem;
+    public Long disk;
+    public String space;
+
+    public void setMem(long mem) {
+      this.mem = mem != 0 ? mem : null;
+    }
+
+    public void setDisk(long disk) {
+      this.disk = disk != 0 ? disk : null;
+    }
+
+    public void setSpace(double value) {
+      space = bytes(value);
+    }
+
+    private static String bytes(double value) {
+      value /= 1024;
+      String suffix = "k";
+
+      if (value > 1024) {
+        value /= 1024;
+        suffix = "m";
+      }
+      if (value > 1024) {
+        value /= 1024;
+        suffix = "g";
+      }
+      return String.format("%1$6.2f%2$s", value, suffix).trim();
+    }
+  }
+
+  public static class HitRatioInfo {
+    public Integer mem;
+    public Integer disk;
+
+    public void setMem(long value, long total) {
+      mem = percent(value, total);
+    }
+
+    public void setDisk(long value, long total) {
+      disk = percent(value, total);
+    }
+
+    private static Integer percent(long value, long total) {
+      if (total <= 0) {
+        return null;
+      }
+      return (int) ((100 * value) / total);
+    }
+  }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/Module.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/Module.java
index 761b265..9d82640 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/Module.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/Module.java
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.server.config;
 
+import static com.google.gerrit.server.config.CacheResource.CACHE_KIND;
 import static com.google.gerrit.server.config.CapabilityResource.CAPABILITY_KIND;
 import static com.google.gerrit.server.config.ConfigResource.CONFIG_KIND;
 import static com.google.gerrit.server.config.TopMenuResource.TOP_MENU_KIND;
@@ -24,9 +25,12 @@
 public class Module extends RestApiModule {
   @Override
   protected void configure() {
+    DynamicMap.mapOf(binder(), CACHE_KIND);
+    DynamicMap.mapOf(binder(), CAPABILITY_KIND);
     DynamicMap.mapOf(binder(), CONFIG_KIND);
     DynamicMap.mapOf(binder(), TOP_MENU_KIND);
-    DynamicMap.mapOf(binder(), CAPABILITY_KIND);
+    child(CONFIG_KIND, "caches").to(CachesCollection.class);
+    get(CACHE_KIND).to(GetCache.class);
     child(CONFIG_KIND, "capabilities").to(CapabilitiesCollection.class);
     child(CONFIG_KIND, "top-menus").to(TopMenuCollection.class);
     get(CONFIG_KIND, "version").to(GetVersion.class);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/SetPreferences.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/SetPreferences.java
index 7fe9f42..5260b98 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/SetPreferences.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/SetPreferences.java
@@ -23,12 +23,14 @@
 import com.google.gerrit.server.account.VersionedAccountPreferences;
 import com.google.gerrit.server.git.MetaDataUpdate;
 import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
 import org.eclipse.jgit.errors.ConfigInvalidException;
 
 import java.io.IOException;
 
 @RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
+@Singleton
 public class SetPreferences implements RestModifyView<ConfigResource, Input> {
   private final MetaDataUpdate.User metaDataUpdateFactory;
   private final AllUsersName allUsersName;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/TopMenuCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/TopMenuCollection.java
index 55fd2df..8e5d4ef 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/TopMenuCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/TopMenuCollection.java
@@ -21,7 +21,9 @@
 import com.google.gerrit.extensions.restapi.RestView;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
+@Singleton
 class TopMenuCollection implements
     ChildCollection<ConfigResource, TopMenuResource> {
   private final DynamicMap<RestView<TopMenuResource>> views;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/BranchOrderSection.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/BranchOrderSection.java
new file mode 100644
index 0000000..c447d31
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/BranchOrderSection.java
@@ -0,0 +1,60 @@
+// Copyright (C) 2014 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.git;
+
+import com.google.common.collect.ImmutableList;
+
+import org.eclipse.jgit.lib.Constants;
+
+import java.util.List;
+
+public class BranchOrderSection {
+
+  /**
+   * Branch names ordered from least to the most stable.
+   *
+   * Typically the order will be like: master, stable-M.N, stable-M.N-1, ...
+   */
+  private final ImmutableList<String> order;
+
+  public BranchOrderSection(String[] order) {
+    if (order.length == 0) {
+      this.order = ImmutableList.of();
+    } else {
+      ImmutableList.Builder<String> builder = ImmutableList.builder();
+      for (String b : order) {
+        builder.add(fullName(b));
+      }
+      this.order = builder.build();
+    }
+  }
+
+  private static String fullName(String branch) {
+    if (branch.startsWith(Constants.R_HEADS)) {
+      return branch;
+    } else {
+      return Constants.R_HEADS + branch;
+    }
+  }
+
+  public List<String> getMoreStable(String branch) {
+    int i = order.indexOf(fullName(branch));
+    if (0 <= i) {
+      return order.subList(i + 1, order.size());
+    } else {
+      return ImmutableList.of();
+    }
+  }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/LabelNormalizer.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/LabelNormalizer.java
index 19b5ec9..12efd56 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/LabelNormalizer.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/LabelNormalizer.java
@@ -33,6 +33,7 @@
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.NoSuchChangeException;
 import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
 import java.util.Collection;
 import java.util.List;
@@ -46,6 +47,7 @@
  * is originally made and a later point, for example when a change is submitted.
  * This class normalizes old votes against current project configuration.
  */
+@Singleton
 public class LabelNormalizer {
   public static class Result {
     private final ImmutableList<PatchSetApproval> unchanged;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java
index d5dae8e..c4c1b7f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java
@@ -95,6 +95,9 @@
   private static final String ACCOUNTS = "accounts";
   private static final String KEY_SAME_GROUP_VISIBILITY = "sameGroupVisibility";
 
+  private static final String BRANCH_ORDER = "branchOrder";
+  private static final String BRANCH = "branch";
+
   private static final String CONTRIBUTOR_AGREEMENT = "contributor-agreement";
   private static final String KEY_ACCEPTED = "accepted";
   private static final String KEY_REQUIRE_CONTACT_INFORMATION = "requireContactInformation";
@@ -152,6 +155,7 @@
   private AccountsSection accountsSection;
   private Map<AccountGroup.UUID, GroupReference> groupsByUUID;
   private Map<String, AccessSection> accessSections;
+  private BranchOrderSection branchOrderSection;
   private Map<String, ContributorAgreement> contributorAgreements;
   private Map<String, NotifyConfig> notifySections;
   private Map<String, LabelType> labelSections;
@@ -242,6 +246,10 @@
     return sort(accessSections.values());
   }
 
+  public BranchOrderSection getBranchOrderSection() {
+    return branchOrderSection;
+  }
+
   public void remove(AccessSection section) {
     if (section != null) {
       accessSections.remove(section.getName());
@@ -420,6 +428,7 @@
     loadAccountsSection(rc, groupsByName);
     loadContributorAgreements(rc, groupsByName);
     loadAccessSections(rc, groupsByName);
+    loadBranchOrderSection(rc);
     loadNotifySections(rc, groupsByName);
     loadLabelSections(rc);
     loadCommentLinkSections(rc);
@@ -570,6 +579,13 @@
     }
   }
 
+  private void loadBranchOrderSection(Config rc) {
+    if (rc.getSections().contains(BRANCH_ORDER)) {
+      branchOrderSection = new BranchOrderSection(
+          rc.getStringList(BRANCH_ORDER, null, BRANCH));
+    }
+  }
+
   private List<PermissionRule> loadPermissionRules(Config rc, String section,
       String subsection, String varName,
       Map<String, GroupReference> groupsByName,
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/AddIncludedGroups.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/AddIncludedGroups.java
index c5273ba..aa9b85c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/AddIncludedGroups.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/AddIncludedGroups.java
@@ -38,10 +38,12 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import java.util.List;
 import java.util.Map;
 
+@Singleton
 public class AddIncludedGroups implements RestModifyView<GroupResource, Input> {
   public static class Input {
     @DefaultInput
@@ -71,13 +73,13 @@
 
   private final Provider<GroupsCollection> groupsCollection;
   private final GroupIncludeCache groupIncludeCache;
-  private final ReviewDb db;
+  private final Provider<ReviewDb> db;
   private final GroupJson json;
 
   @Inject
   public AddIncludedGroups(Provider<GroupsCollection> groupsCollection,
       GroupIncludeCache groupIncludeCache,
-      ReviewDb db, GroupJson json) {
+      Provider<ReviewDb> db, GroupJson json) {
     this.groupsCollection = groupsCollection;
     this.groupIncludeCache = groupIncludeCache;
     this.db = db;
@@ -111,7 +113,7 @@
         AccountGroupById.Key agiKey =
             new AccountGroupById.Key(group.getId(),
                 d.getGroupUUID());
-        AccountGroupById agi = db.accountGroupById().get(agiKey);
+        AccountGroupById agi = db.get().accountGroupById().get(agiKey);
         if (agi == null) {
           agi = new AccountGroupById(agiKey);
           newIncludedGroups.put(d.getGroupUUID(), agi);
@@ -123,8 +125,8 @@
     }
 
     if (!newIncludedGroups.isEmpty()) {
-      db.accountGroupByIdAud().insert(newIncludedGroupsAudits);
-      db.accountGroupById().insert(newIncludedGroups.values());
+      db.get().accountGroupByIdAud().insert(newIncludedGroupsAudits);
+      db.get().accountGroupById().insert(newIncludedGroups.values());
       for (AccountGroupById agi : newIncludedGroups.values()) {
         groupIncludeCache.evictMemberIn(agi.getIncludeUUID());
       }
@@ -160,6 +162,7 @@
     }
   }
 
+  @Singleton
   static class UpdateIncludedGroup implements RestModifyView<IncludedGroupResource, PutIncludedGroup.Input> {
     static class Input {
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/AddMembers.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/AddMembers.java
index 8ec6a3f..83c6521 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/AddMembers.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/AddMembers.java
@@ -43,10 +43,12 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import java.util.List;
 import java.util.Map;
 
+@Singleton
 public class AddMembers implements RestModifyView<GroupResource, Input> {
   public static class Input {
     @DefaultInput
@@ -79,7 +81,7 @@
   private final AccountResolver accountResolver;
   private final AccountCache accountCache;
   private final AccountInfo.Loader.Factory infoFactory;
-  private final ReviewDb db;
+  private final Provider<ReviewDb> db;
 
   @Inject
   AddMembers(AccountManager accountManager,
@@ -88,7 +90,7 @@
       AccountResolver accountResolver,
       AccountCache accountCache,
       AccountInfo.Loader.Factory infoFactory,
-      ReviewDb db) {
+      Provider<ReviewDb> db) {
     this.accountManager = accountManager;
     this.authType = authConfig.getAuthType();
     this.accounts = accounts;
@@ -129,7 +131,7 @@
       if (!newAccountGroupMembers.containsKey(a.getId())) {
         AccountGroupMember.Key key =
             new AccountGroupMember.Key(a.getId(), internalGroup.getId());
-        AccountGroupMember m = db.accountGroupMembers().get(key);
+        AccountGroupMember m = db.get().accountGroupMembers().get(key);
         if (m == null) {
           m = new AccountGroupMember(key);
           newAccountGroupMembers.put(m.getAccountId(), m);
@@ -140,8 +142,8 @@
       result.add(loader.get(a.getId()));
     }
 
-    db.accountGroupMembersAudit().insert(newAccountGroupMemberAudits);
-    db.accountGroupMembers().insert(newAccountGroupMembers.values());
+    db.get().accountGroupMembersAudit().insert(newAccountGroupMemberAudits);
+    db.get().accountGroupMembers().insert(newAccountGroupMembers.values());
     for (AccountGroupMember m : newAccountGroupMembers.values()) {
       accountCache.evict(m.getAccountId());
     }
@@ -213,6 +215,7 @@
     }
   }
 
+  @Singleton
   static class UpdateMember implements RestModifyView<MemberResource, PutMember.Input> {
     static class Input {
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/DeleteIncludedGroups.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/DeleteIncludedGroups.java
index 04dcda3..c8646da 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/DeleteIncludedGroups.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/DeleteIncludedGroups.java
@@ -37,19 +37,22 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import java.util.List;
 import java.util.Map;
 
+@Singleton
 public class DeleteIncludedGroups implements RestModifyView<GroupResource, Input> {
   private final Provider<GroupsCollection> groupsCollection;
   private final GroupIncludeCache groupIncludeCache;
-  private final ReviewDb db;
+  private final Provider<ReviewDb> db;
   private final Provider<CurrentUser> self;
 
   @Inject
   DeleteIncludedGroups(Provider<GroupsCollection> groupsCollection,
-      GroupIncludeCache groupIncludeCache, ReviewDb db,
+      GroupIncludeCache groupIncludeCache,
+      Provider<ReviewDb> db,
       Provider<CurrentUser> self) {
     this.groupsCollection = groupsCollection;
     this.groupIncludeCache = groupIncludeCache;
@@ -86,7 +89,7 @@
 
     if (!toRemove.isEmpty()) {
       writeAudits(toRemove);
-      db.accountGroupById().delete(toRemove);
+      db.get().accountGroupById().delete(toRemove);
       for (final AccountGroupById g : toRemove) {
         groupIncludeCache.evictMemberIn(g.getIncludeUUID());
       }
@@ -100,7 +103,7 @@
       final AccountGroup.Id groupId) throws OrmException {
     final Map<AccountGroup.UUID, AccountGroupById> groups =
         Maps.newHashMap();
-    for (final AccountGroupById g : db.accountGroupById().byGroup(groupId)) {
+    for (AccountGroupById g : db.get().accountGroupById().byGroup(groupId)) {
       groups.put(g.getIncludeUUID(), g);
     }
     return groups;
@@ -112,7 +115,7 @@
     final List<AccountGroupByIdAud> auditUpdates = Lists.newLinkedList();
     for (final AccountGroupById g : toBeRemoved) {
       AccountGroupByIdAud audit = null;
-      for (AccountGroupByIdAud a : db
+      for (AccountGroupByIdAud a : db.get()
           .accountGroupByIdAud().byGroupInclude(g.getGroupId(),
               g.getIncludeUUID())) {
         if (a.isActive()) {
@@ -126,9 +129,10 @@
         auditUpdates.add(audit);
       }
     }
-    db.accountGroupByIdAud().update(auditUpdates);
+    db.get().accountGroupByIdAud().update(auditUpdates);
   }
 
+  @Singleton
   static class DeleteIncludedGroup implements
       RestModifyView<IncludedGroupResource, DeleteIncludedGroup.Input> {
     static class Input {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/DeleteMembers.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/DeleteMembers.java
index fd1b8f4..73cc352 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/DeleteMembers.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/DeleteMembers.java
@@ -36,19 +36,22 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import java.util.List;
 import java.util.Map;
 
+@Singleton
 public class DeleteMembers implements RestModifyView<GroupResource, Input> {
   private final Provider<AccountsCollection> accounts;
   private final AccountCache accountCache;
-  private final ReviewDb db;
+  private final Provider<ReviewDb> db;
   private final Provider<CurrentUser> self;
 
   @Inject
   DeleteMembers(Provider<AccountsCollection> accounts,
-      AccountCache accountCache, ReviewDb db, Provider<CurrentUser> self) {
+      AccountCache accountCache, Provider<ReviewDb> db,
+      Provider<CurrentUser> self) {
     this.accounts = accounts;
     this.accountCache = accountCache;
     this.db = db;
@@ -83,7 +86,7 @@
     }
 
     writeAudits(toRemove);
-    db.accountGroupMembers().delete(toRemove);
+    db.get().accountGroupMembers().delete(toRemove);
     for (final AccountGroupMember m : toRemove) {
       accountCache.evict(m.getAccountId());
     }
@@ -98,7 +101,7 @@
     final List<AccountGroupMemberAudit> auditInserts = Lists.newLinkedList();
     for (final AccountGroupMember m : toBeRemoved) {
       AccountGroupMemberAudit audit = null;
-      for (AccountGroupMemberAudit a : db.accountGroupMembersAudit()
+      for (AccountGroupMemberAudit a : db.get().accountGroupMembersAudit()
           .byGroupAccount(m.getAccountGroupId(), m.getAccountId())) {
         if (a.isActive()) {
           audit = a;
@@ -115,19 +118,21 @@
         auditInserts.add(audit);
       }
     }
-    db.accountGroupMembersAudit().update(auditUpdates);
-    db.accountGroupMembersAudit().insert(auditInserts);
+    db.get().accountGroupMembersAudit().update(auditUpdates);
+    db.get().accountGroupMembersAudit().insert(auditInserts);
   }
 
   private Map<Account.Id, AccountGroupMember> getMembers(
       final AccountGroup.Id groupId) throws OrmException {
     final Map<Account.Id, AccountGroupMember> members = Maps.newHashMap();
-    for (final AccountGroupMember m : db.accountGroupMembers().byGroup(groupId)) {
+    for (final AccountGroupMember m : db.get().accountGroupMembers()
+        .byGroup(groupId)) {
       members.put(m.getAccountId(), m);
     }
     return members;
   }
 
+  @Singleton
   static class DeleteMember implements RestModifyView<MemberResource, DeleteMember.Input> {
     static class Input {
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/GetDescription.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/GetDescription.java
index 4674a21..8c804dd 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/GetDescription.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/GetDescription.java
@@ -18,7 +18,9 @@
 import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
 import com.google.gerrit.extensions.restapi.RestReadView;
 import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.inject.Singleton;
 
+@Singleton
 class GetDescription implements RestReadView<GroupResource> {
   @Override
   public String apply(GroupResource resource) throws MethodNotAllowedException {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/GetDetail.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/GetDetail.java
index f1d2e15..936798d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/GetDetail.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/GetDetail.java
@@ -19,7 +19,9 @@
 import com.google.gerrit.server.group.GroupJson.GroupInfo;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
+@Singleton
 public class GetDetail implements RestReadView<GroupResource> {
   private final GroupJson json;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/GetGroup.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/GetGroup.java
index 09180dd..95042a2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/GetGroup.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/GetGroup.java
@@ -18,7 +18,9 @@
 import com.google.gerrit.server.group.GroupJson.GroupInfo;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
+@Singleton
 class GetGroup implements RestReadView<GroupResource> {
   private final GroupJson json;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/GetIncludedGroup.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/GetIncludedGroup.java
index 32f20c0..5d3853e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/GetIncludedGroup.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/GetIncludedGroup.java
@@ -18,7 +18,9 @@
 import com.google.gerrit.server.group.GroupJson.GroupInfo;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
+@Singleton
 public class GetIncludedGroup implements RestReadView<IncludedGroupResource>  {
   private final GroupJson json;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/GetMember.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/GetMember.java
index d98dd24..2782932e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/GetMember.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/GetMember.java
@@ -18,7 +18,9 @@
 import com.google.gerrit.server.account.AccountInfo;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
+@Singleton
 public class GetMember implements RestReadView<MemberResource> {
   private final AccountInfo.Loader.Factory infoFactory;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/GetName.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/GetName.java
index c6da7c4..ce4df2a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/GetName.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/GetName.java
@@ -15,7 +15,9 @@
 package com.google.gerrit.server.group;
 
 import com.google.gerrit.extensions.restapi.RestReadView;
+import com.google.inject.Singleton;
 
+@Singleton
 public class GetName implements RestReadView<GroupResource> {
 
   @Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/GetOptions.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/GetOptions.java
index 3fbfc70..5d1ede0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/GetOptions.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/GetOptions.java
@@ -15,7 +15,9 @@
 package com.google.gerrit.server.group;
 
 import com.google.gerrit.extensions.restapi.RestReadView;
+import com.google.inject.Singleton;
 
+@Singleton
 public class GetOptions implements RestReadView<GroupResource> {
 
   @Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/GetOwner.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/GetOwner.java
index 0113a164..5fc62c6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/GetOwner.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/GetOwner.java
@@ -23,7 +23,9 @@
 import com.google.gerrit.server.group.GroupJson.GroupInfo;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
+@Singleton
 public class GetOwner implements RestReadView<GroupResource> {
 
   private final GroupControl.Factory controlFactory;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/GroupsCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/GroupsCollection.java
index 7f9fe77..76cd137 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/GroupsCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/GroupsCollection.java
@@ -35,7 +35,9 @@
 import com.google.gerrit.server.account.GroupControl;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
+@Singleton
 public class GroupsCollection implements
     RestCollection<TopLevelResource, GroupResource>,
     AcceptsCreate<TopLevelResource> {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/IncludedGroupsCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/IncludedGroupsCollection.java
index 2ffff20..ba0930e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/IncludedGroupsCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/IncludedGroupsCollection.java
@@ -31,7 +31,9 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
+@Singleton
 public class IncludedGroupsCollection implements
     ChildCollection<GroupResource, IncludedGroupResource>,
     AcceptsCreate<GroupResource> {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/ListIncludedGroups.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/ListIncludedGroups.java
index f112e34..671486c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/ListIncludedGroups.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/ListIncludedGroups.java
@@ -27,6 +27,7 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import org.slf4j.Logger;
 
@@ -34,6 +35,7 @@
 import java.util.Comparator;
 import java.util.List;
 
+@Singleton
 public class ListIncludedGroups implements RestReadView<GroupResource> {
   private static final Logger log = org.slf4j.LoggerFactory.getLogger(ListIncludedGroups.class);
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/MembersCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/MembersCollection.java
index efed115..d69046d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/MembersCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/MembersCollection.java
@@ -31,7 +31,9 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
+@Singleton
 public class MembersCollection implements
     ChildCollection<GroupResource, MemberResource>,
     AcceptsCreate<GroupResource> {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/PutDescription.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/PutDescription.java
index 663eb9d..c2dc23a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/PutDescription.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/PutDescription.java
@@ -27,9 +27,12 @@
 import com.google.gerrit.server.group.PutDescription.Input;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import java.util.Collections;
 
+@Singleton
 public class PutDescription implements RestModifyView<GroupResource, Input> {
   public static class Input {
     @DefaultInput
@@ -37,10 +40,10 @@
   }
 
   private final GroupCache groupCache;
-  private final ReviewDb db;
+  private final Provider<ReviewDb> db;
 
   @Inject
-  PutDescription(GroupCache groupCache, ReviewDb db) {
+  PutDescription(GroupCache groupCache, Provider<ReviewDb> db) {
     this.groupCache = groupCache;
     this.db = db;
   }
@@ -59,14 +62,14 @@
       throw new AuthException("Not group owner");
     }
 
-    AccountGroup group = db.accountGroups().get(
+    AccountGroup group = db.get().accountGroups().get(
         resource.toAccountGroup().getId());
     if (group == null) {
       throw new ResourceNotFoundException();
     }
 
     group.setDescription(Strings.emptyToNull(input.description));
-    db.accountGroups().update(Collections.singleton(group));
+    db.get().accountGroups().update(Collections.singleton(group));
     groupCache.evict(group);
 
     return Strings.isNullOrEmpty(input.description)
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/PutGroup.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/PutGroup.java
index 4d3d6be..9768270 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/PutGroup.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/PutGroup.java
@@ -18,7 +18,9 @@
 import com.google.gerrit.extensions.restapi.Response;
 import com.google.gerrit.extensions.restapi.RestModifyView;
 import com.google.gerrit.server.group.CreateGroup.Input;
+import com.google.inject.Singleton;
 
+@Singleton
 public class PutGroup implements RestModifyView<GroupResource, Input> {
   @Override
   public Response<?> apply(GroupResource resource, Input input)
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/PutName.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/PutName.java
index 447b666..6d980ae 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/PutName.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/PutName.java
@@ -29,7 +29,9 @@
 import com.google.gerrit.server.group.PutName.Input;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
+@Singleton
 public class PutName implements RestModifyView<GroupResource, Input> {
   public static class Input {
     @DefaultInput
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/PutOptions.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/PutOptions.java
index 5139c34..6ed6703 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/PutOptions.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/PutOptions.java
@@ -25,19 +25,22 @@
 import com.google.gerrit.server.group.PutOptions.Input;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import java.util.Collections;
 
+@Singleton
 public class PutOptions implements RestModifyView<GroupResource, Input> {
   public static class Input {
     public Boolean visibleToAll;
   }
 
   private final GroupCache groupCache;
-  private final ReviewDb db;
+  private final Provider<ReviewDb> db;
 
   @Inject
-  PutOptions(GroupCache groupCache, ReviewDb db) {
+  PutOptions(GroupCache groupCache, Provider<ReviewDb> db) {
     this.groupCache = groupCache;
     this.db = db;
   }
@@ -59,14 +62,14 @@
       input.visibleToAll = false;
     }
 
-    AccountGroup group = db.accountGroups().get(
+    AccountGroup group = db.get().accountGroups().get(
         resource.toAccountGroup().getId());
     if (group == null) {
       throw new ResourceNotFoundException();
     }
 
     group.setVisibleToAll(input.visibleToAll);
-    db.accountGroups().update(Collections.singleton(group));
+    db.get().accountGroups().update(Collections.singleton(group));
     groupCache.evict(group);
 
     return new GroupOptionsInfo(group);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/PutOwner.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/PutOwner.java
index 737a74a..7aa1560 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/PutOwner.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/PutOwner.java
@@ -31,9 +31,11 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import java.util.Collections;
 
+@Singleton
 public class PutOwner implements RestModifyView<GroupResource, Input> {
   public static class Input {
     @DefaultInput
@@ -42,12 +44,12 @@
 
   private final Provider<GroupsCollection> groupsCollection;
   private final GroupCache groupCache;
-  private final ReviewDb db;
+  private final Provider<ReviewDb> db;
   private final GroupJson json;
 
   @Inject
   PutOwner(Provider<GroupsCollection> groupsCollection, GroupCache groupCache,
-      ReviewDb db, GroupJson json) {
+      Provider<ReviewDb> db, GroupJson json) {
     this.groupsCollection = groupsCollection;
     this.groupCache = groupCache;
     this.db = db;
@@ -70,7 +72,7 @@
       throw new BadRequestException("owner is required");
     }
 
-    group = db.accountGroups().get(group.getId());
+    group = db.get().accountGroups().get(group.getId());
     if (group == null) {
       throw new ResourceNotFoundException();
     }
@@ -78,7 +80,7 @@
     GroupDescription.Basic owner = groupsCollection.get().parse(input.owner);
     if (!group.getOwnerGroupUUID().equals(owner.getGroupUUID())) {
       group.setOwnerGroupUUID(owner.getGroupUUID());
-      db.accountGroups().update(Collections.singleton(group));
+      db.get().accountGroups().update(Collections.singleton(group));
       groupCache.evict(group);
     }
     return json.format(owner);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/DisablePlugin.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/DisablePlugin.java
index 3a1915a..d92dce0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/DisablePlugin.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/DisablePlugin.java
@@ -22,8 +22,10 @@
 import com.google.gerrit.server.plugins.DisablePlugin.Input;
 import com.google.gerrit.server.plugins.ListPlugins.PluginInfo;
 import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
 @RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
+@Singleton
 class DisablePlugin implements RestModifyView<PluginResource, Input> {
   static class Input {
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/EnablePlugin.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/EnablePlugin.java
index f7745cc..b6f8260 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/EnablePlugin.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/EnablePlugin.java
@@ -23,11 +23,13 @@
 import com.google.gerrit.server.plugins.EnablePlugin.Input;
 import com.google.gerrit.server.plugins.ListPlugins.PluginInfo;
 import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
 
 @RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
+@Singleton
 class EnablePlugin implements RestModifyView<PluginResource, Input> {
   static class Input {
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/GetStatus.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/GetStatus.java
index 7651506..47f7985 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/GetStatus.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/GetStatus.java
@@ -16,7 +16,9 @@
 
 import com.google.gerrit.extensions.restapi.RestReadView;
 import com.google.gerrit.server.plugins.ListPlugins.PluginInfo;
+import com.google.inject.Singleton;
 
+@Singleton
 class GetStatus implements RestReadView<PluginResource> {
   @Override
   public PluginInfo apply(PluginResource resource) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginsCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginsCollection.java
index 076bfdd..a4834ba 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginsCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginsCollection.java
@@ -24,7 +24,9 @@
 import com.google.gerrit.extensions.restapi.TopLevelResource;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
+@Singleton
 public class PluginsCollection implements
     RestCollection<TopLevelResource, PluginResource>,
     AcceptsCreate<TopLevelResource> {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ReloadPlugin.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ReloadPlugin.java
index 32e8b24..e9c5aa2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ReloadPlugin.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ReloadPlugin.java
@@ -22,11 +22,13 @@
 import com.google.gerrit.server.plugins.ListPlugins.PluginInfo;
 import com.google.gerrit.server.plugins.ReloadPlugin.Input;
 import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
 
 @RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
+@Singleton
 class ReloadPlugin implements RestModifyView<PluginResource, Input> {
   static class Input {
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/BranchesCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/BranchesCollection.java
index 8ae07de..efcad64 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/BranchesCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/BranchesCollection.java
@@ -23,12 +23,14 @@
 import com.google.gerrit.server.project.ListBranches.BranchInfo;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import org.eclipse.jgit.lib.Constants;
 
 import java.io.IOException;
 import java.util.List;
 
+@Singleton
 public class BranchesCollection implements
     ChildCollection<ProjectResource, BranchResource>,
     AcceptsCreate<ProjectResource> {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ChildProjectsCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ChildProjectsCollection.java
index 27f1648..06325d6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ChildProjectsCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ChildProjectsCollection.java
@@ -23,9 +23,11 @@
 import com.google.gerrit.extensions.restapi.TopLevelResource;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import java.io.IOException;
 
+@Singleton
 public class ChildProjectsCollection implements
     ChildCollection<ProjectResource, ChildProjectResource> {
   private final Provider<ListChildProjects> list;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/DashboardsCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/DashboardsCollection.java
index 3df8e2f..c3fc1fe 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/DashboardsCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/DashboardsCollection.java
@@ -37,6 +37,7 @@
 import com.google.gson.annotations.SerializedName;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import org.eclipse.jgit.errors.AmbiguousObjectException;
 import org.eclipse.jgit.errors.ConfigInvalidException;
@@ -51,9 +52,10 @@
 import java.io.UnsupportedEncodingException;
 import java.util.List;
 
+@Singleton
 class DashboardsCollection implements
     ChildCollection<ProjectResource, DashboardResource>,
-    AcceptsCreate<ProjectResource>{
+    AcceptsCreate<ProjectResource> {
   private final GitRepositoryManager gitManager;
   private final DynamicMap<RestView<DashboardResource>> views;
   private final Provider<ListDashboards> list;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteBranch.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteBranch.java
index 87e233f..14069bd 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteBranch.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteBranch.java
@@ -27,6 +27,7 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import org.eclipse.jgit.lib.RefUpdate;
 import org.eclipse.jgit.lib.Repository;
@@ -35,6 +36,7 @@
 
 import java.io.IOException;
 
+@Singleton
 public class DeleteBranch implements RestModifyView<BranchResource, Input>{
   private static final Logger log = LoggerFactory.getLogger(DeleteBranch.class);
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteDashboard.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteDashboard.java
index 669f024..b525399 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteDashboard.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/DeleteDashboard.java
@@ -25,9 +25,11 @@
 import com.google.gerrit.server.project.DeleteDashboard.Input;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import java.io.IOException;
 
+@Singleton
 class DeleteDashboard implements RestModifyView<DashboardResource, Input> {
   static class Input {
     String commitMessage;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/FilesCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/FilesCollection.java
index 389189e..176ab51 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/FilesCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/FilesCollection.java
@@ -21,7 +21,9 @@
 import com.google.gerrit.extensions.restapi.RestView;
 import com.google.gerrit.server.project.BranchResource;
 import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
+@Singleton
 public class FilesCollection implements
     ChildCollection<BranchResource, FileResource> {
   private final DynamicMap<RestView<FileResource>> views;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/GetBranch.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/GetBranch.java
index 781cf01..59b15d8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/GetBranch.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/GetBranch.java
@@ -16,7 +16,9 @@
 
 import com.google.gerrit.extensions.restapi.RestReadView;
 import com.google.gerrit.server.project.ListBranches.BranchInfo;
+import com.google.inject.Singleton;
 
+@Singleton
 public class GetBranch implements RestReadView<BranchResource> {
 
   @Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/GetConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/GetConfig.java
index 88ac83f..e0bc7e6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/GetConfig.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/GetConfig.java
@@ -24,7 +24,9 @@
 import com.google.gerrit.server.git.TransferConfig;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
+@Singleton
 public class GetConfig implements RestReadView<ProjectResource> {
 
   private final TransferConfig config;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/GetContent.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/GetContent.java
index 48a3ced..ea295a0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/GetContent.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/GetContent.java
@@ -19,9 +19,11 @@
 import com.google.gerrit.extensions.restapi.RestReadView;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import java.io.IOException;
 
+@Singleton
 public class GetContent implements RestReadView<FileResource> {
   private final Provider<com.google.gerrit.server.change.GetContent> getContent;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/GetDescription.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/GetDescription.java
index aeff72f..5241c69 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/GetDescription.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/GetDescription.java
@@ -17,7 +17,9 @@
 import com.google.common.base.Strings;
 import com.google.gerrit.extensions.restapi.RestReadView;
 import com.google.gerrit.reviewdb.client.Project;
+import com.google.inject.Singleton;
 
+@Singleton
 class GetDescription implements RestReadView<ProjectResource> {
   @Override
   public String apply(ProjectResource resource) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/GetHead.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/GetHead.java
index af7559a..f05ece4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/GetHead.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/GetHead.java
@@ -19,6 +19,7 @@
 import com.google.gerrit.extensions.restapi.RestReadView;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.MissingObjectException;
@@ -31,6 +32,7 @@
 
 import java.io.IOException;
 
+@Singleton
 public class GetHead implements RestReadView<ProjectResource> {
 
   private GitRepositoryManager repoManager;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/GetParent.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/GetParent.java
index f790b7e..8161cfd 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/GetParent.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/GetParent.java
@@ -18,7 +18,9 @@
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.config.AllProjectsName;
 import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
+@Singleton
 class GetParent implements RestReadView<ProjectResource> {
   private final AllProjectsName allProjectsName;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/GetProject.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/GetProject.java
index af55c15..e782cb1 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/GetProject.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/GetProject.java
@@ -17,7 +17,9 @@
 import com.google.gerrit.extensions.common.ProjectInfo;
 import com.google.gerrit.extensions.restapi.RestReadView;
 import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
+@Singleton
 class GetProject implements RestReadView<ProjectResource> {
 
   private final ProjectJson json;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/GetStatistics.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/GetStatistics.java
index 548b85a..2b9d11f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/GetStatistics.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/GetStatistics.java
@@ -21,6 +21,7 @@
 import com.google.gerrit.extensions.restapi.RestReadView;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
 import org.eclipse.jgit.api.GarbageCollectCommand;
 import org.eclipse.jgit.api.Git;
@@ -31,6 +32,7 @@
 import java.io.IOException;
 
 @RequiresCapability(GlobalCapability.RUN_GC)
+@Singleton
 public class GetStatistics implements RestReadView<ProjectResource> {
 
   private final GitRepositoryManager repoManager;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectJson.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectJson.java
index 590d69b..8934474 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectJson.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectJson.java
@@ -24,7 +24,9 @@
 import com.google.gerrit.server.config.AllProjectsName;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
+@Singleton
 public class ProjectJson {
 
   private final AllProjectsName allProjects;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java
index f6b96d7..715419d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java
@@ -40,6 +40,7 @@
 import com.google.gerrit.server.account.GroupMembership;
 import com.google.gerrit.server.config.AllProjectsName;
 import com.google.gerrit.server.config.SitePaths;
+import com.google.gerrit.server.git.BranchOrderSection;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.ProjectConfig;
 import com.google.gerrit.server.git.ProjectLevelConfig;
@@ -445,6 +446,16 @@
     return ImmutableList.copyOf(cls.values());
   }
 
+  public BranchOrderSection getBranchOrderSection() {
+    for (ProjectState s : tree()) {
+      BranchOrderSection section = s.getConfig().getBranchOrderSection();
+      if (section != null) {
+        return section;
+      }
+    }
+    return null;
+  }
+
   public ThemeInfo getTheme() {
     ThemeInfo theme = this.theme;
     if (theme == null) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectsCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectsCollection.java
index 6e9c5d9..519f4f2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectsCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectsCollection.java
@@ -27,9 +27,11 @@
 import com.google.gerrit.server.OutputFormat;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import java.io.IOException;
 
+@Singleton
 public class ProjectsCollection implements
     RestCollection<TopLevelResource, ProjectResource>,
     AcceptsCreate<TopLevelResource> {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/PutBranch.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/PutBranch.java
index 2cd5659..f8b201b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/PutBranch.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/PutBranch.java
@@ -17,7 +17,9 @@
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
 import com.google.gerrit.extensions.restapi.RestModifyView;
 import com.google.gerrit.server.project.CreateBranch.Input;
+import com.google.inject.Singleton;
 
+@Singleton
 public class PutBranch implements RestModifyView<BranchResource, Input> {
 
   @Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/PutConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/PutConfig.java
index 39d2367..9fa9b52 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/PutConfig.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/PutConfig.java
@@ -44,6 +44,7 @@
 import com.google.gerrit.server.project.PutConfig.Input;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.errors.RepositoryNotFoundException;
@@ -57,6 +58,7 @@
 import java.util.Map;
 import java.util.Map.Entry;
 
+@Singleton
 public class PutConfig implements RestModifyView<ProjectResource, Input> {
   private static final Logger log = LoggerFactory.getLogger(PutConfig.class);
   public static class Input {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/PutDescription.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/PutDescription.java
index 17ab7b3..b8a4c7c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/PutDescription.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/PutDescription.java
@@ -32,6 +32,7 @@
 import com.google.gerrit.server.git.ProjectConfig;
 import com.google.gerrit.server.project.PutDescription.Input;
 import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.errors.RepositoryNotFoundException;
@@ -39,6 +40,7 @@
 
 import java.io.IOException;
 
+@Singleton
 class PutDescription implements RestModifyView<ProjectResource, Input> {
   static class Input {
     @DefaultInput
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/PutProject.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/PutProject.java
index 19ba794..fc397e1 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/PutProject.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/PutProject.java
@@ -18,7 +18,9 @@
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
 import com.google.gerrit.extensions.restapi.Response;
 import com.google.gerrit.extensions.restapi.RestModifyView;
+import com.google.inject.Singleton;
 
+@Singleton
 public class PutProject implements RestModifyView<ProjectResource, ProjectInput> {
   @Override
   public Response<?> apply(ProjectResource resource, ProjectInput input)
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/SetDashboard.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/SetDashboard.java
index 8319bbd..cda548a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/SetDashboard.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/SetDashboard.java
@@ -24,9 +24,11 @@
 import com.google.gerrit.server.project.SetDashboard.Input;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import java.io.IOException;
 
+@Singleton
 class SetDashboard implements RestModifyView<DashboardResource, Input> {
   static class Input {
     @DefaultInput
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/SetHead.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/SetHead.java
index 05b392b..7efc1b7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/SetHead.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/SetHead.java
@@ -28,6 +28,7 @@
 import com.google.gerrit.server.project.SetHead.Input;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import com.google.inject.Singleton;
 
 import org.eclipse.jgit.errors.RepositoryNotFoundException;
 import org.eclipse.jgit.lib.Constants;
@@ -38,6 +39,7 @@
 
 import java.io.IOException;
 
+@Singleton
 public class SetHead implements RestModifyView<ProjectResource, Input> {
   private static final Logger log = LoggerFactory.getLogger(SetHead.class);
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/SetParent.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/SetParent.java
index 4f0941d..81ce582 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/SetParent.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/SetParent.java
@@ -31,12 +31,14 @@
 import com.google.gerrit.server.git.ProjectConfig;
 import com.google.gerrit.server.project.SetParent.Input;
 import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.errors.RepositoryNotFoundException;
 
 import java.io.IOException;
 
+@Singleton
 public class SetParent implements RestModifyView<ProjectResource, Input> {
   public static class Input {
     @DefaultInput
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CacheCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CacheCommand.java
index 7f9e5db..3d568e1 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CacheCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CacheCommand.java
@@ -38,7 +38,7 @@
     if ("gerrit".equals(plugin)) {
       return name;
     } else {
-      return plugin + "." + name;
+      return plugin + "-" + name;
     }
   }
 }
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowCaches.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowCaches.java
index 397120f..00ccae2 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowCaches.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowCaches.java
@@ -16,20 +16,21 @@
 
 import static com.google.gerrit.sshd.CommandMetaData.Mode.MASTER_OR_SLAVE;
 
-import com.google.common.cache.Cache;
-import com.google.common.cache.CacheStats;
-import com.google.common.collect.Maps;
+import com.google.common.base.Strings;
 import com.google.gerrit.common.Version;
 import com.google.gerrit.common.data.GlobalCapability;
 import com.google.gerrit.extensions.annotations.RequiresCapability;
 import com.google.gerrit.extensions.events.LifecycleListener;
-import com.google.gerrit.extensions.registration.DynamicMap;
-import com.google.gerrit.server.cache.h2.H2CacheImpl;
+import com.google.gerrit.server.config.ConfigResource;
+import com.google.gerrit.server.config.ListCaches;
+import com.google.gerrit.server.config.ListCaches.CacheInfo;
+import com.google.gerrit.server.config.ListCaches.CacheType;
 import com.google.gerrit.server.config.SitePath;
 import com.google.gerrit.server.git.WorkQueue;
 import com.google.gerrit.server.git.WorkQueue.Task;
 import com.google.gerrit.server.util.TimeUtil;
 import com.google.gerrit.sshd.CommandMetaData;
+import com.google.gerrit.sshd.SshCommand;
 import com.google.gerrit.sshd.SshDaemon;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
@@ -52,13 +53,12 @@
 import java.util.Collection;
 import java.util.Date;
 import java.util.Map;
-import java.util.SortedMap;
 
 /** Show the current cache states. */
 @RequiresCapability(GlobalCapability.VIEW_CACHES)
 @CommandMetaData(name = "show-caches", description = "Display current cache statistics",
   runsAt = MASTER_OR_SLAVE)
-final class ShowCaches extends CacheCommand {
+final class ShowCaches extends SshCommand {
   private static volatile long serverStarted;
 
   static class StartupListener implements LifecycleListener {
@@ -88,6 +88,9 @@
   @SitePath
   private File sitePath;
 
+  @Inject
+  private Provider<ListCaches> listCaches;
+
   @Option(name = "--width", aliases = {"-w"}, metaVar = "COLS", usage = "width of output table")
   private int columns = 80;
   private int nw;
@@ -145,23 +148,10 @@
     }
     stdout.print("+---------------------+---------+---------+\n");
 
-    Map<String, H2CacheImpl<?, ?>> disks = Maps.newTreeMap();
-    printMemoryCaches(disks, sortedCoreCaches());
-    printMemoryCaches(disks, sortedPluginCaches());
-    for (Map.Entry<String, H2CacheImpl<?, ?>> entry : disks.entrySet()) {
-      H2CacheImpl<?, ?> cache = entry.getValue();
-      CacheStats stat = cache.stats();
-      H2CacheImpl.DiskStats disk = cache.diskStats();
-      stdout.print(String.format(
-          "D %-"+nw+"s|%6s %6s %7s| %7s |%4s %4s|\n",
-          entry.getKey(),
-          count(cache.size()),
-          count(disk.size()),
-          bytes(disk.space()),
-          duration(stat.averageLoadPenalty()),
-          percent(stat.hitCount(), stat.requestCount()),
-          percent(disk.hitCount(), disk.requestCount())));
-    }
+    Collection<CacheInfo> caches = getCaches();
+    printMemoryCoreCaches(caches);
+    printMemoryPluginCaches(caches);
+    printDiskCaches(caches);
     stdout.print('\n');
 
     if (gc) {
@@ -181,46 +171,62 @@
     stdout.flush();
   }
 
-  private void printMemoryCaches(
-      Map<String, H2CacheImpl<?, ?>> disks,
-      Map<String, Cache<?,?>> caches) {
-    for (Map.Entry<String, Cache<?,?>> entry : caches.entrySet()) {
-      Cache<?,?> cache = entry.getValue();
-      if (cache instanceof H2CacheImpl) {
-        disks.put(entry.getKey(), (H2CacheImpl<?,?>)cache);
-        continue;
+  private Collection<CacheInfo> getCaches() {
+    Map<String, CacheInfo> caches = listCaches.get().apply(new ConfigResource());
+    for (Map.Entry<String, CacheInfo> entry : caches.entrySet()) {
+      CacheInfo cache = entry.getValue();
+      if (cache.type == null) {
+        cache.type = CacheType.MEM;
       }
-      CacheStats stat = cache.stats();
-      stdout.print(String.format(
-          "  %-"+nw+"s|%6s %6s %7s| %7s |%4s %4s|\n",
-          entry.getKey(),
-          count(cache.size()),
-          "",
-          "",
-          duration(stat.averageLoadPenalty()),
-          percent(stat.hitCount(), stat.requestCount()),
-          ""));
+      cache.name = entry.getKey();
+    }
+    return caches.values();
+  }
+
+  private void printMemoryCoreCaches(Collection<CacheInfo> caches) {
+    for (CacheInfo cache : caches) {
+      if (!cache.name.contains("-") && CacheType.MEM.equals(cache.type)) {
+        printCache(cache);
+      }
     }
   }
 
-  private Map<String, Cache<?, ?>> sortedCoreCaches() {
-    SortedMap<String, Cache<?, ?>> m = Maps.newTreeMap();
-    for (Map.Entry<String, Provider<Cache<?, ?>>> entry :
-        cacheMap.byPlugin("gerrit").entrySet()) {
-      m.put(cacheNameOf("gerrit", entry.getKey()), entry.getValue().get());
-    }
-    return m;
-  }
-
-  private Map<String, Cache<?, ?>> sortedPluginCaches() {
-    SortedMap<String, Cache<?, ?>> m = Maps.newTreeMap();
-    for (DynamicMap.Entry<Cache<?, ?>> e : cacheMap) {
-      if (!"gerrit".equals(e.getPluginName())) {
-        m.put(cacheNameOf(e.getPluginName(), e.getExportName()),
-            e.getProvider().get());
+  private void printMemoryPluginCaches(Collection<CacheInfo> caches) {
+    for (CacheInfo cache : caches) {
+      if (cache.name.contains("-") && CacheType.MEM.equals(cache.type)) {
+        printCache(cache);
       }
     }
-    return m;
+  }
+
+  private void printDiskCaches(Collection<CacheInfo> caches) {
+    for (CacheInfo cache : caches) {
+      if (CacheType.DISK.equals(cache.type)) {
+        printCache(cache);
+      }
+    }
+  }
+
+  private void printCache(CacheInfo cache) {
+    stdout.print(String.format(
+        "%1s %-"+nw+"s|%6s %6s %7s| %7s |%4s %4s|\n",
+        CacheType.DISK.equals(cache.type) ? "D" : "",
+        cache.name,
+        nullToEmpty(cache.entries.mem),
+        nullToEmpty(cache.entries.disk),
+        Strings.nullToEmpty(cache.entries.space),
+        Strings.nullToEmpty(cache.averageGet),
+        formatAsPercent(cache.hitRatio.mem),
+        formatAsPercent(cache.hitRatio.disk)
+      ));
+  }
+
+  private static String nullToEmpty(Long l) {
+    return l != null ? String.valueOf(l) : "";
+  }
+
+  private static String formatAsPercent(Integer i) {
+    return i != null ? String.valueOf(i) + "%" : "";
   }
 
   private void memSummary() {
@@ -358,39 +364,4 @@
     }
     return String.format("%1$6.2f%2$s", value, suffix);
   }
-
-  private String count(long cnt) {
-    if (cnt == 0) {
-      return "";
-    }
-    return String.format("%6d", cnt);
-  }
-
-  private String duration(double ns) {
-    if (ns < 0.5) {
-      return "";
-    }
-    String suffix = "ns";
-    if (ns >= 1000.0) {
-      ns /= 1000.0;
-      suffix = "us";
-    }
-    if (ns >= 1000.0) {
-      ns /= 1000.0;
-      suffix = "ms";
-    }
-    if (ns >= 1000.0) {
-      ns /= 1000.0;
-      suffix = "s ";
-    }
-    return String.format("%4.1f%s", ns, suffix);
-  }
-
-  private String percent(final long value, final long total) {
-    if (total <= 0) {
-      return "";
-    }
-    final long pcent = (100 * value) / total;
-    return String.format("%3d%%", (int) pcent);
-  }
 }
diff --git a/plugins/cookbook-plugin b/plugins/cookbook-plugin
index f95eb05..679a135 160000
--- a/plugins/cookbook-plugin
+++ b/plugins/cookbook-plugin
@@ -1 +1 @@
-Subproject commit f95eb05f758fc62726b2938b26f0e6b3f023d02b
+Subproject commit 679a1356ec20f7570246af77fa4e4c6f10ed3a42