Lazily open database connections in ChangeIndexer tasks

These connections are only needed in the request scope environment
when continuing work in a different thread. Most indexing operations
(e.g. from new-style REST APIs) don't happen in a request scope, so
don't need to tie up a database connection on the off chance that
RequestContext.getReviewDbProvider() is called.

Change-Id: Ide04ffc61dc73b2c816ed29ee018c83e948f6f1d
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeIndexerImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeIndexerImpl.java
index ef89a54..e79622c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeIndexerImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeIndexerImpl.java
@@ -14,15 +14,18 @@
 
 package com.google.gerrit.server.index;
 
+import com.google.common.util.concurrent.Atomics;
 import com.google.common.util.concurrent.ListeningScheduledExecutorService;
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.query.change.ChangeData;
 import com.google.gerrit.server.util.RequestContext;
 import com.google.gerrit.server.util.ThreadLocalRequestContext;
+import com.google.gwtorm.server.OrmException;
 import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.OutOfScopeException;
 import com.google.inject.Provider;
+import com.google.inject.ProvisionException;
 import com.google.inject.assistedinject.Assisted;
 import com.google.inject.assistedinject.AssistedInject;
 import com.google.inject.util.Providers;
@@ -32,6 +35,7 @@
 
 import java.io.IOException;
 import java.util.concurrent.Callable;
+import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * Helper for (re)indexing a change document.
@@ -94,12 +98,25 @@
     @Override
     public Void call() throws Exception {
       try {
-        final ReviewDb db = schemaFactory.open();
+        final AtomicReference<Provider<ReviewDb>> dbRef =
+            Atomics.newReference();
         try {
           context.setContext(new RequestContext() {
             @Override
             public Provider<ReviewDb> getReviewDbProvider() {
-              return Providers.of(db);
+              Provider<ReviewDb> db = dbRef.get();
+              if (db == null) {
+                try {
+                  db = Providers.of(schemaFactory.open());
+                } catch (OrmException e) {
+                  ProvisionException pe =
+                      new ProvisionException("error opening ReviewDb");
+                  pe.initCause(e);
+                  throw pe;
+                }
+                dbRef.set(db);
+              }
+              return db;
             }
 
             @Override
@@ -117,7 +134,10 @@
           return null;
         } finally  {
           context.setContext(null);
-          db.close();
+          Provider<ReviewDb> db = dbRef.get();
+          if (db != null) {
+            db.get().close();
+          }
         }
       } catch (Exception e) {
         log.error(String.format(