Repository: accumulo
Updated Branches:
  refs/heads/1.7 4136bfafc -> 48733ce8c


ACCUMULO-4458 reduce contention on config retrievals.

We retrieve configuration values in a few hot code paths, so contention
on getting the site configuration and values that are only read from the 
filesystem
once causes a perf impact. We try to reduce that here in a few ways:

* Since SiteConfiguration is a singleton, we only retrieve it once when 
HdfsZooInstance is made instead of on each lookup.
* Since HdfsZooInstance is a singleton, we create it once on initialization and 
avoid synchronizing on retrieval
* Since the Hadoop Configuration object uses a single lock for all gets against 
the shared instance, we copy out the values
  it reads when the SiteConfiguration singleton is created. This has the 
side-effect of causing our for-test-only set method
  to only work on values not set in the Configuration (essentially we treat all 
configs as final).
* Additionally, for those configurations that are read within any of the 
processing loops of the TabletServer, we have the
  SiteConfiguration singleton cache the fact that they weren't in the Hadoop 
Configuration object so that we will default to
  the parent AccumuloConfiguration without contending for the Hadoop 
Configuration object lock.


Project: http://git-wip-us.apache.org/repos/asf/accumulo/repo
Commit: http://git-wip-us.apache.org/repos/asf/accumulo/commit/48733ce8
Tree: http://git-wip-us.apache.org/repos/asf/accumulo/tree/48733ce8
Diff: http://git-wip-us.apache.org/repos/asf/accumulo/diff/48733ce8

Branch: refs/heads/1.7
Commit: 48733ce8cb9e89f1243e5e46d792010900086c7b
Parents: 4136bfa
Author: Sean Busbey <bus...@cloudera.com>
Authored: Tue Sep 6 11:52:37 2016 -0500
Committer: Sean Busbey <bus...@cloudera.com>
Committed: Wed Sep 14 16:35:31 2016 -0700

----------------------------------------------------------------------
 .../org/apache/accumulo/core/conf/Property.java |  7 ++++
 .../accumulo/core/conf/SiteConfiguration.java   | 24 ++++++++++++-
 .../accumulo/server/client/HdfsZooInstance.java | 36 +++++++++++++-------
 3 files changed, 53 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/accumulo/blob/48733ce8/core/src/main/java/org/apache/accumulo/core/conf/Property.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/conf/Property.java 
b/core/src/main/java/org/apache/accumulo/core/conf/Property.java
index 9d145e1..96adaeb 100644
--- a/core/src/main/java/org/apache/accumulo/core/conf/Property.java
+++ b/core/src/main/java/org/apache/accumulo/core/conf/Property.java
@@ -803,6 +803,13 @@ public enum Property {
         || key.startsWith(Property.TABLE_ARBITRARY_PROP_PREFIX.getKey());
   }
 
+  /**
+   * Properties we check the value of within the TabletServer request handling 
or maintenance processing loops.
+   */
+  public static final EnumSet<Property> HOT_PATH_PROPERTIES = 
EnumSet.of(Property.TSERV_CLIENT_TIMEOUT, 
Property.TSERV_TOTAL_MUTATION_QUEUE_MAX,
+      Property.TSERV_ARCHIVE_WALOGS, Property.GC_TRASH_IGNORE, 
Property.TSERV_MAJC_DELAY, Property.TABLE_MINC_LOGS_MAX, 
Property.TSERV_MAJC_MAXCONCURRENT,
+      Property.REPLICATION_WORKER_THREADS, Property.TABLE_DURABILITY, 
Property.INSTANCE_ZK_TIMEOUT, Property.TABLE_CLASSPATH);
+
   private static final EnumSet<Property> fixedProperties = 
EnumSet.of(Property.TSERV_CLIENTPORT, Property.TSERV_NATIVEMAP_ENABLED,
       Property.TSERV_SCAN_MAX_OPENFILES, Property.MASTER_CLIENTPORT, 
Property.GC_PORT);
 

http://git-wip-us.apache.org/repos/asf/accumulo/blob/48733ce8/core/src/main/java/org/apache/accumulo/core/conf/SiteConfiguration.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/accumulo/core/conf/SiteConfiguration.java 
b/core/src/main/java/org/apache/accumulo/core/conf/SiteConfiguration.java
index b2f5a18..07aaf9f 100644
--- a/core/src/main/java/org/apache/accumulo/core/conf/SiteConfiguration.java
+++ b/core/src/main/java/org/apache/accumulo/core/conf/SiteConfiguration.java
@@ -17,6 +17,8 @@
 package org.apache.accumulo.core.conf;
 
 import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.Map;
 import java.util.Map.Entry;
 
@@ -45,12 +47,31 @@ public class SiteConfiguration extends 
AccumuloConfiguration {
   private static SiteConfiguration instance = null;
 
   private static Configuration xmlConfig;
+  private final Map<String,String> staticConfigs;
 
   /**
    * Not for consumers. Call {@link 
SiteConfiguration#getInstance(AccumuloConfiguration)} instead
    */
   SiteConfiguration(AccumuloConfiguration parent) {
     this.parent = parent;
+    /*
+     * Make a read-only copy of static configs so we can avoid lock contention 
on the Hadoop Configuration object
+     */
+    final Configuration conf = getXmlConfig();
+    Map<String,String> temp = new HashMap<>((int) (Math.ceil(conf.size() / 
0.75f)), 0.75f);
+    for (Entry<String,String> entry : conf) {
+      temp.put(entry.getKey(), entry.getValue());
+    }
+    /*
+     * If any of the configs used in hot codepaths are unset here, set a null 
so that we'll default to the parent config without contending for the Hadoop
+     * Configuration object
+     */
+    for (Property hotConfig : Property.HOT_PATH_PROPERTIES) {
+      if (!(temp.containsKey(hotConfig.getKey()))) {
+        temp.put(hotConfig.getKey(), null);
+      }
+    }
+    staticConfigs = Collections.unmodifiableMap(temp);
   }
 
   /**
@@ -106,7 +127,8 @@ public class SiteConfiguration extends 
AccumuloConfiguration {
       }
     }
 
-    String value = getXmlConfig().get(key);
+    /* Check the available-on-load configs and fall-back to the 
possibly-update Configuration object. */
+    String value = staticConfigs.containsKey(key) ? staticConfigs.get(key) : 
getXmlConfig().get(key);
 
     if (value == null || !property.getType().isValidFormat(value)) {
       if (value != null)

http://git-wip-us.apache.org/repos/asf/accumulo/blob/48733ce8/server/base/src/main/java/org/apache/accumulo/server/client/HdfsZooInstance.java
----------------------------------------------------------------------
diff --git 
a/server/base/src/main/java/org/apache/accumulo/server/client/HdfsZooInstance.java
 
b/server/base/src/main/java/org/apache/accumulo/server/client/HdfsZooInstance.java
index 0d7aaf1..2dacf61 100644
--- 
a/server/base/src/main/java/org/apache/accumulo/server/client/HdfsZooInstance.java
+++ 
b/server/base/src/main/java/org/apache/accumulo/server/client/HdfsZooInstance.java
@@ -23,6 +23,7 @@ import java.nio.ByteBuffer;
 import java.util.Collections;
 import java.util.List;
 import java.util.UUID;
+import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.accumulo.core.Constants;
 import org.apache.accumulo.core.client.AccumuloException;
@@ -63,20 +64,19 @@ import com.google.common.base.Joiner;
  */
 public class HdfsZooInstance implements Instance {
 
+  private final AccumuloConfiguration site = SiteConfiguration.getInstance();
+
   private HdfsZooInstance() {
-    AccumuloConfiguration acuConf = SiteConfiguration.getInstance();
-    zooCache = new 
ZooCacheFactory().getZooCache(acuConf.get(Property.INSTANCE_ZK_HOST), (int) 
acuConf.getTimeInMillis(Property.INSTANCE_ZK_TIMEOUT));
+    zooCache = new 
ZooCacheFactory().getZooCache(site.get(Property.INSTANCE_ZK_HOST), (int) 
site.getTimeInMillis(Property.INSTANCE_ZK_TIMEOUT));
   }
 
-  private static HdfsZooInstance cachedHdfsZooInstance = null;
+  private static final HdfsZooInstance cachedHdfsZooInstance = new 
HdfsZooInstance();
 
-  public static synchronized Instance getInstance() {
-    if (cachedHdfsZooInstance == null)
-      cachedHdfsZooInstance = new HdfsZooInstance();
+  public static Instance getInstance() {
     return cachedHdfsZooInstance;
   }
 
-  private static ZooCache zooCache;
+  private final ZooCache zooCache;
   private static String instanceId = null;
   private static final Logger log = Logger.getLogger(HdfsZooInstance.class);
 
@@ -146,17 +146,17 @@ public class HdfsZooInstance implements Instance {
 
   @Override
   public String getZooKeepers() {
-    return SiteConfiguration.getInstance().get(Property.INSTANCE_ZK_HOST);
+    return site.get(Property.INSTANCE_ZK_HOST);
   }
 
   @Override
   public int getZooKeepersSessionTimeOut() {
-    return (int) 
SiteConfiguration.getInstance().getTimeInMillis(Property.INSTANCE_ZK_TIMEOUT);
+    return (int) site.getTimeInMillis(Property.INSTANCE_ZK_TIMEOUT);
   }
 
   @Override
   public Connector getConnector(String principal, AuthenticationToken token) 
throws AccumuloException, AccumuloSecurityException {
-    return new ConnectorImpl(new ClientContext(this, new 
Credentials(principal, token), SiteConfiguration.getInstance()));
+    return new ConnectorImpl(new ClientContext(this, new 
Credentials(principal, token), site));
   }
 
   @Deprecated
@@ -177,18 +177,28 @@ public class HdfsZooInstance implements Instance {
     return getConnector(user, TextUtil.getBytes(new Text(pass.toString())));
   }
 
-  private AccumuloConfiguration conf = null;
+  private final AtomicReference<AccumuloConfiguration> conf = new 
AtomicReference<>();
 
   @Deprecated
   @Override
   public AccumuloConfiguration getConfiguration() {
-    return conf = conf == null ? new 
ServerConfigurationFactory(this).getConfiguration() : conf;
+    AccumuloConfiguration conf = this.conf.get();
+    if (conf == null) {
+      // conf hasn't been set before, get an instance
+      conf = new ServerConfigurationFactory(this).getConfiguration();
+      // if the shared variable is still null, we're done.
+      if (!(this.conf.compareAndSet(null, conf))) {
+        // if it wasn't null, then we need to return the value that won.
+        conf = this.conf.get();
+      }
+    }
+    return conf;
   }
 
   @Override
   @Deprecated
   public void setConfiguration(AccumuloConfiguration conf) {
-    this.conf = conf;
+    this.conf.set(conf);
   }
 
   public static void main(String[] args) {

Reply via email to