You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@helix.apache.org by jx...@apache.org on 2022/12/15 22:16:05 UTC

[helix] branch master updated: Improve AssignmentMetadataStore with double-checked locking (#2289)

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 3ca0620b6 Improve AssignmentMetadataStore with double-checked locking (#2289)
3ca0620b6 is described below

commit 3ca0620b61007f78a50ef1bcef7f50b86845f36e
Author: Qi (Quincy) Qu <qq...@linkedin.com>
AuthorDate: Thu Dec 15 17:15:59 2022 -0500

    Improve AssignmentMetadataStore with double-checked locking (#2289)
    
    Implement double-checked locking in AssignmentMetadataStore for better performance.
---
 .../rebalancer/waged/AssignmentMetadataStore.java  | 49 ++++++++++++----------
 1 file changed, 28 insertions(+), 21 deletions(-)

diff --git a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/AssignmentMetadataStore.java b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/AssignmentMetadataStore.java
index dd502893e..834fbad4e 100644
--- a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/AssignmentMetadataStore.java
+++ b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/AssignmentMetadataStore.java
@@ -45,11 +45,12 @@ public class AssignmentMetadataStore {
   private static final String BEST_POSSIBLE_KEY = "BEST_POSSIBLE";
   private static final ZkSerializer SERIALIZER = new ZNRecordJacksonSerializer();
 
-  private BucketDataAccessor _dataAccessor;
-  private String _baselinePath;
-  private String _bestPossiblePath;
-  protected Map<String, ResourceAssignment> _globalBaseline;
-  protected Map<String, ResourceAssignment> _bestPossibleAssignment;
+  private final BucketDataAccessor _dataAccessor;
+  private final String _baselinePath;
+  private final String _bestPossiblePath;
+  // volatile for double-checked locking
+  protected volatile Map<String, ResourceAssignment> _globalBaseline;
+  protected volatile Map<String, ResourceAssignment> _bestPossibleAssignment;
 
   AssignmentMetadataStore(String metadataStoreAddrs, String clusterName) {
     this(new ZkBucketDataAccessor(metadataStoreAddrs), clusterName);
@@ -61,36 +62,42 @@ public class AssignmentMetadataStore {
     _bestPossiblePath = String.format(BEST_POSSIBLE_TEMPLATE, clusterName, ASSIGNMENT_METADATA_KEY);
   }
 
-  public synchronized Map<String, ResourceAssignment> getBaseline() {
+  public Map<String, ResourceAssignment> getBaseline() {
     // Return the in-memory baseline. If null, read from ZK. This is to minimize reads from ZK
     if (_globalBaseline == null) {
-      try {
-        HelixProperty baseline =
-            _dataAccessor.compressedBucketRead(_baselinePath, HelixProperty.class);
-        _globalBaseline = splitAssignments(baseline);
-      } catch (ZkNoNodeException ex) {
-        // Metadata does not exist, so return an empty map
-        _globalBaseline = new HashMap<>();
+      // double-checked locking
+      synchronized (this) {
+        if (_globalBaseline == null) {
+          _globalBaseline = fetchAssignmentOrDefault(_baselinePath);
+        }
       }
     }
     return _globalBaseline;
   }
 
-  public synchronized Map<String, ResourceAssignment> getBestPossibleAssignment() {
+  public Map<String, ResourceAssignment> getBestPossibleAssignment() {
     // Return the in-memory baseline. If null, read from ZK. This is to minimize reads from ZK
     if (_bestPossibleAssignment == null) {
-      try {
-        HelixProperty baseline =
-            _dataAccessor.compressedBucketRead(_bestPossiblePath, HelixProperty.class);
-        _bestPossibleAssignment = splitAssignments(baseline);
-      } catch (ZkNoNodeException ex) {
-        // Metadata does not exist, so return an empty map
-        _bestPossibleAssignment = new HashMap<>();
+      // double-checked locking
+      synchronized (this) {
+        if (_bestPossibleAssignment == null) {
+          _bestPossibleAssignment = fetchAssignmentOrDefault(_bestPossiblePath);
+        }
       }
     }
     return _bestPossibleAssignment;
   }
 
+  private Map<String, ResourceAssignment> fetchAssignmentOrDefault(String path) {
+    try {
+      HelixProperty assignment = _dataAccessor.compressedBucketRead(path, HelixProperty.class);
+      return splitAssignments(assignment);
+    } catch (ZkNoNodeException ex) {
+      // Metadata does not exist, so return an empty map
+      return new HashMap<>();
+    }
+  }
+
   /**
    * @return true if a new baseline was persisted.
    * @throws HelixException if the method failed to persist the baseline.