You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@accumulo.apache.org by kt...@apache.org on 2019/04/18 21:36:42 UTC

[accumulo] branch master updated: Avoid lock contention in table configuration (#1102)

This is an automated email from the ASF dual-hosted git repository.

kturner pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/accumulo.git


The following commit(s) were added to refs/heads/master by this push:
     new 89d36cf  Avoid lock contention in table configuration (#1102)
89d36cf is described below

commit 89d36cf48ee2256a4fdde30e27874f64e5225b7f
Author: Keith Turner <kt...@apache.org>
AuthorDate: Thu Apr 18 17:36:38 2019 -0400

    Avoid lock contention in table configuration (#1102)
    
    Lock contentions was observed in table configuration during profiling.
    This change replaces a syncronized pointer to a ZooCache with an
    AtomicReference.
---
 .../server/conf/NamespaceConfiguration.java        | 40 ++++++++++++++--------
 .../accumulo/server/conf/TableConfiguration.java   | 39 +++++++++++++--------
 2 files changed, 49 insertions(+), 30 deletions(-)

diff --git a/server/base/src/main/java/org/apache/accumulo/server/conf/NamespaceConfiguration.java b/server/base/src/main/java/org/apache/accumulo/server/conf/NamespaceConfiguration.java
index 50c15ea..b3e9d76 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/conf/NamespaceConfiguration.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/conf/NamespaceConfiguration.java
@@ -17,6 +17,7 @@
 package org.apache.accumulo.server.conf;
 
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Predicate;
 
 import org.apache.accumulo.core.Constants;
@@ -39,7 +40,7 @@ public class NamespaceConfiguration extends ObservableConfiguration {
   private static final Map<PropCacheKey,ZooCache> propCaches = new java.util.HashMap<>();
 
   private final AccumuloConfiguration parent;
-  private ZooCachePropertyAccessor propCacheAccessor = null;
+  private final AtomicReference<ZooCachePropertyAccessor> propCacheAccessor = new AtomicReference<>();
   protected NamespaceId namespaceId = null;
   protected ServerContext context;
   private ZooCacheFactory zcf = new ZooCacheFactory();
@@ -67,20 +68,27 @@ public class NamespaceConfiguration extends ObservableConfiguration {
     this.zcf = zcf;
   }
 
-  private synchronized ZooCachePropertyAccessor getPropCacheAccessor() {
-    if (propCacheAccessor == null) {
-      synchronized (propCaches) {
-        PropCacheKey key = new PropCacheKey(context.getInstanceID(), namespaceId.canonical());
-        ZooCache propCache = propCaches.get(key);
-        if (propCache == null) {
-          propCache = zcf.getZooCache(context.getZooKeepers(),
-              context.getZooKeepersSessionTimeOut(), new NamespaceConfWatcher(context));
-          propCaches.put(key, propCache);
-        }
-        propCacheAccessor = new ZooCachePropertyAccessor(propCache);
+  private ZooCache getZooCache() {
+    synchronized (propCaches) {
+      PropCacheKey key = new PropCacheKey(context.getInstanceID(), namespaceId.canonical());
+      ZooCache propCache = propCaches.get(key);
+      if (propCache == null) {
+        propCache = zcf.getZooCache(context.getZooKeepers(), context.getZooKeepersSessionTimeOut(),
+            new NamespaceConfWatcher(context));
+        propCaches.put(key, propCache);
       }
+      return propCache;
     }
-    return propCacheAccessor;
+  }
+
+  private ZooCachePropertyAccessor getPropCacheAccessor() {
+    // updateAndGet below always calls compare and set, so avoid if not null
+    ZooCachePropertyAccessor zcpa = propCacheAccessor.get();
+    if (zcpa != null)
+      return zcpa;
+
+    return propCacheAccessor
+        .updateAndGet(pca -> pca == null ? new ZooCachePropertyAccessor(getZooCache()) : pca);
   }
 
   private String getPath() {
@@ -155,8 +163,10 @@ public class NamespaceConfiguration extends ObservableConfiguration {
 
   @Override
   public synchronized void invalidateCache() {
-    if (propCacheAccessor != null) {
-      propCacheAccessor.invalidateCache();
+    ZooCachePropertyAccessor pca = propCacheAccessor.get();
+
+    if (pca != null) {
+      pca.invalidateCache();
     }
     // Else, if the accessor is null, we could lock and double-check
     // to see if it happened to be created so we could invalidate its cache
diff --git a/server/base/src/main/java/org/apache/accumulo/server/conf/TableConfiguration.java b/server/base/src/main/java/org/apache/accumulo/server/conf/TableConfiguration.java
index 7652604..c1bbfcd 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/conf/TableConfiguration.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/conf/TableConfiguration.java
@@ -54,7 +54,7 @@ public class TableConfiguration extends ObservableConfiguration {
 
   private static final Map<PropCacheKey,ZooCache> propCaches = new java.util.HashMap<>();
 
-  private ZooCachePropertyAccessor propCacheAccessor = null;
+  private final AtomicReference<ZooCachePropertyAccessor> propCacheAccessor = new AtomicReference<>();
   private final ServerContext context;
   private final NamespaceConfiguration parent;
   private ZooCacheFactory zcf = new ZooCacheFactory();
@@ -78,20 +78,27 @@ public class TableConfiguration extends ObservableConfiguration {
     this.zcf = zcf;
   }
 
-  private synchronized ZooCachePropertyAccessor getPropCacheAccessor() {
-    if (propCacheAccessor == null) {
-      synchronized (propCaches) {
-        PropCacheKey key = new PropCacheKey(context.getInstanceID(), tableId.canonical());
-        ZooCache propCache = propCaches.get(key);
-        if (propCache == null) {
-          propCache = zcf.getZooCache(context.getZooKeepers(),
-              context.getZooKeepersSessionTimeOut(), new TableConfWatcher(context));
-          propCaches.put(key, propCache);
-        }
-        propCacheAccessor = new ZooCachePropertyAccessor(propCache);
+  private ZooCache getZooCache() {
+    synchronized (propCaches) {
+      PropCacheKey key = new PropCacheKey(context.getInstanceID(), tableId.canonical());
+      ZooCache propCache = propCaches.get(key);
+      if (propCache == null) {
+        propCache = zcf.getZooCache(context.getZooKeepers(), context.getZooKeepersSessionTimeOut(),
+            new TableConfWatcher(context));
+        propCaches.put(key, propCache);
       }
+      return propCache;
     }
-    return propCacheAccessor;
+  }
+
+  private ZooCachePropertyAccessor getPropCacheAccessor() {
+    // updateAndGet below always calls compare and set, so avoid if not null
+    ZooCachePropertyAccessor zcpa = propCacheAccessor.get();
+    if (zcpa != null)
+      return zcpa;
+
+    return propCacheAccessor
+        .updateAndGet(pca -> pca == null ? new ZooCachePropertyAccessor(getZooCache()) : pca);
   }
 
   @Override
@@ -163,8 +170,10 @@ public class TableConfiguration extends ObservableConfiguration {
 
   @Override
   public synchronized void invalidateCache() {
-    if (propCacheAccessor != null) {
-      propCacheAccessor.invalidateCache();
+    ZooCachePropertyAccessor pca = propCacheAccessor.get();
+
+    if (pca != null) {
+      pca.invalidateCache();
     }
     // Else, if the accessor is null, we could lock and double-check
     // to see if it happened to be created so we could invalidate its cache