phet commented on code in PR #3765:
URL: https://github.com/apache/gobblin/pull/3765#discussion_r1322242245


##########
gobblin-utility/src/main/java/org/apache/gobblin/util/HostUtils.java:
##########
@@ -32,4 +33,16 @@ public static String getHostName() {
   public static String getPrincipalUsingHostname(String name, String realm) {
     return name + "/" + getHostName() + "@" + realm;
   }
+
+  /**
+   * Given a host name return an optional containing the InetAddress object if 
one can be constructed for the input
+   * // TODO: provide details about expected hostName format

Review Comment:
   may be no need to stipulate, given the type
   
   ... perhaps rename the function to `getInetAddressForHostName`?



##########
gobblin-api/src/main/java/org/apache/gobblin/configuration/ConfigurationKeys.java:
##########
@@ -103,6 +103,11 @@ public class ConfigurationKeys {
   public static final String 
DEFAULT_SCHEDULER_LEASE_DETERMINATION_STORE_DB_TABLE = 
"gobblin_scheduler_lease_determination_store";
   // Refers to the event we originally tried to acquire a lease which achieved 
`consensus` among participants through
   // the database
+  public static final String MULTI_ACTIVE_LEASE_ARBITER_HOST_TO_BIT_MASK_MAP = 
MYSQL_LEASE_ARBITER_PREFIX + ".hostToBitMaskMap";

Review Comment:
   since this is not interpreted by the `MysqlMALeaseArbiter`, it shouldn't 
borrow that class's config prefix.  let's make a prefix just for the class 
reading this config.  (that will clue in config maintainers that it's 
unnecessary once the class itself is no longer being used.)



##########
gobblin-runtime/src/main/java/org/apache/gobblin/runtime/api/MysqlMultiActiveLeaseArbiterTestingDecorator.java:
##########
@@ -0,0 +1,206 @@
+package org.apache.gobblin.runtime.api;
+
+import com.google.common.base.Optional;
+import com.typesafe.config.Config;
+import java.io.IOException;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.HashMap;
+import javax.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.gobblin.configuration.ConfigurationKeys;
+import org.apache.gobblin.util.ConfigUtils;
+import org.apache.gobblin.util.HostUtils;
+
+
+/**
+ * This class is a decorator for {@link MysqlMultiActiveLeaseArbiter} used to 
model scenarios where a lease owner fails
+ * to complete a lease intermittently (representing a variety of slowness or 
failure cases that can result on the
+ * participant side, network connectivity, or database).
+ *
+ * It will fail on calls to {@link 
MysqlMultiActiveLeaseArbiter.recordLeaseSuccess()} where a function of the lease
+ * obtained timestamp matches a bitmask of the host. Ideally, each participant 
should fail on different calls (with
+ * limited overlap if we want to test that). We use a deterministic method of 
failing some calls to complete a lease
+ * success with the following methodology. We take the binary representation 
of the lease obtained timestamp, scatter
+ * its bits through bit interleaving of the first and second halves of the 
binary representation to differentiate
+ * behavior of consecutive timestamps, and compare the last N digits 
(determined through config) to the bit mask of the
+ * host. If the bitwise AND comparison to the host bit mask equals the bitmask 
we fail the call.
+ */
+@Slf4j
+public class MysqlMultiActiveLeaseArbiterTestingDecorator extends 
MysqlMultiActiveLeaseArbiter {
+  private final int bitMaskLength;
+  private final int numHosts;
+  private final HashMap<Integer, Integer> hostIdToBitMask = new HashMap();
+
+  @Inject
+  public MysqlMultiActiveLeaseArbiterTestingDecorator(Config config) throws 
IOException {
+    super(config);
+    bitMaskLength = ConfigUtils.getInt(config, 
ConfigurationKeys.MULTI_ACTIVE_LEASE_ARBITER_BIT_MASK_LENGTH,
+        ConfigurationKeys.DEFAULT_MULTI_ACTIVE_LEASE_ARBITER_BIT_MASK_LENGTH);
+    numHosts = ConfigUtils.getInt(config, 
ConfigurationKeys.MULTI_ACTIVE_LEASE_ARBITER_TESTING_DECORATOR_NUM_HOSTS,
+        
ConfigurationKeys.DEFAULT_MULTI_ACTIVE_LEASE_ARBITER_TESTING_DECORATOR_NUM_HOSTS);
+    initializeHostToBitMaskMap(config);
+  }
+
+  /**
+   * Extract bit mask from input config if one is present. Otherwise set the 
default bitmask for each host id which
+   * does not have overlapping bits between two hosts so that a given status 
will not fail on multiple hosts.
+   * @param config expected to contain a mapping of host address to bitmap in 
format
+   *              "host1:bitMask1,host2:bitMask2,...,hostN:bitMaskN"
+   * Note: that if the mapping format is incorrect or there are fewer than 
`bitMaskLength` mappings provide we utilize
+   *               the default to prevent unintended consequences of 
overlapping bit masks.
+   */
+  protected void initializeHostToBitMaskMap(Config config) {
+    // Set default bit masks for each hosts
+    // TODO: change this to parse default from Configuration.Keys property or 
is that unnecessary?
+    hostIdToBitMask.put(1, 0b0001);
+    hostIdToBitMask.put(2, 0b0010);
+    hostIdToBitMask.put(3, 0b0100);
+    hostIdToBitMask.put(4, 0b1000);
+
+    // If a valid mapping is provided in config, then we overwrite all the 
default values.
+    if 
(config.hasPath(ConfigurationKeys.MULTI_ACTIVE_LEASE_ARBITER_HOST_TO_BIT_MASK_MAP))
 {
+      String stringMap = 
config.getString(ConfigurationKeys.MULTI_ACTIVE_LEASE_ARBITER_HOST_TO_BIT_MASK_MAP);
+      Optional<HashMap<InetAddress,Integer>> addressToBitMapOptional = 
validateStringMap(stringMap, numHosts, bitMaskLength);
+      if (addressToBitMapOptional.isPresent()) {
+        for (InetAddress inetAddress : addressToBitMapOptional.get().keySet()) 
{
+          hostIdToBitMask.put(getHostIdFromAddress(inetAddress), 
addressToBitMapOptional.get().get(inetAddress));
+        }
+      }
+    }
+  }
+
+  protected static Optional<HashMap<InetAddress,Integer>> 
validateStringMap(String stringMap, int numHosts, int bitMaskLength) {
+    // TODO: Refactor to increase abstraction
+    String[] hostAddressToMap = stringMap.split(",");
+    if (hostAddressToMap.length < numHosts) {
+      log.warn("Host address to bit mask map expected to be in format "
+          + "`host1:bitMask1,host2:bitMask2,...,hostN:bitMaskN` with at least 
" + numHosts + " hosts necessary. Using "
+          + "default.");
+      return Optional.absent();
+    }
+    HashMap<InetAddress,Integer> addressToBitmap = new HashMap<>();
+    for (String mapping : hostAddressToMap) {
+      String[] keyAndValue = mapping.split(":");
+      if (keyAndValue.length != 2) {
+        log.warn("Host address to bit mask map should be separated by `:`. 
Expected format "
+            + "`host1:bitMask1,host2:bitMask2,...,hostN:bitMaskN`. Using 
default.");
+      }
+      Optional<InetAddress> addressOptional = 
HostUtils.getAddressForHostName(keyAndValue[0]);
+      if (!addressOptional.isPresent()) {
+        log.warn("Invalid hostname format in configuration. Using default.");
+        return Optional.absent();
+      }
+      if (!isValidBitMask(keyAndValue[1], bitMaskLength)) {
+        log.warn("Invalid bit mask format in configuration, expected to be " + 
bitMaskLength + " digit binary number "
+            + "ie: `1010`. Using default.");
+        return Optional.absent();
+      }
+      addressToBitmap.put(addressOptional.get(), 
Integer.valueOf(keyAndValue[1], 2));
+    }
+    return Optional.of(addressToBitmap);
+  }
+
+  protected static boolean isValidBitMask(String input, int bitMaskLength) {
+    // Check if the string contains only 0s and 1s
+    if (!input.matches("[01]+")) {
+      return false;
+    }
+    // Check if the string is exactly `bitMaskLength` characters long
+    if (input.length() != bitMaskLength) {
+      return false;
+    }
+    return true;
+  }
+
+  /**
+   * Retrieve the host id as a number between 1 through `numHosts` by using 
the host address's hashcode.
+   * @return
+   */
+  protected int getHostIdFromAddress(InetAddress address) {
+      return (address.hashCode() % numHosts) + 1;
+  }

Review Comment:
   I don't understand the concept of host ID... please explain.
   
   I'd imagine each host would be identified by its specific hostname and the 
configured bitmask it should use keyed by that name



##########
gobblin-runtime/src/main/java/org/apache/gobblin/runtime/api/MysqlMultiActiveLeaseArbiterTestingDecorator.java:
##########
@@ -0,0 +1,206 @@
+package org.apache.gobblin.runtime.api;
+
+import com.google.common.base.Optional;
+import com.typesafe.config.Config;
+import java.io.IOException;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.HashMap;
+import javax.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.gobblin.configuration.ConfigurationKeys;
+import org.apache.gobblin.util.ConfigUtils;
+import org.apache.gobblin.util.HostUtils;
+
+
+/**
+ * This class is a decorator for {@link MysqlMultiActiveLeaseArbiter} used to 
model scenarios where a lease owner fails
+ * to complete a lease intermittently (representing a variety of slowness or 
failure cases that can result on the
+ * participant side, network connectivity, or database).
+ *
+ * It will fail on calls to {@link 
MysqlMultiActiveLeaseArbiter.recordLeaseSuccess()} where a function of the lease
+ * obtained timestamp matches a bitmask of the host. Ideally, each participant 
should fail on different calls (with
+ * limited overlap if we want to test that). We use a deterministic method of 
failing some calls to complete a lease
+ * success with the following methodology. We take the binary representation 
of the lease obtained timestamp, scatter
+ * its bits through bit interleaving of the first and second halves of the 
binary representation to differentiate
+ * behavior of consecutive timestamps, and compare the last N digits 
(determined through config) to the bit mask of the
+ * host. If the bitwise AND comparison to the host bit mask equals the bitmask 
we fail the call.
+ */
+@Slf4j
+public class MysqlMultiActiveLeaseArbiterTestingDecorator extends 
MysqlMultiActiveLeaseArbiter {
+  private final int bitMaskLength;
+  private final int numHosts;
+  private final HashMap<Integer, Integer> hostIdToBitMask = new HashMap();

Review Comment:
   shouldn't there be only one MALA instance per host?  if so, it shouldn't 
need to worry about any host bitmask but its own, so probably an 
`Optional<Integer>`.



##########
gobblin-api/src/main/java/org/apache/gobblin/configuration/ConfigurationKeys.java:
##########
@@ -103,6 +103,11 @@ public class ConfigurationKeys {
   public static final String 
DEFAULT_SCHEDULER_LEASE_DETERMINATION_STORE_DB_TABLE = 
"gobblin_scheduler_lease_determination_store";
   // Refers to the event we originally tried to acquire a lease which achieved 
`consensus` among participants through
   // the database
+  public static final String MULTI_ACTIVE_LEASE_ARBITER_HOST_TO_BIT_MASK_MAP = 
MYSQL_LEASE_ARBITER_PREFIX + ".hostToBitMaskMap";
+  public static final String MULTI_ACTIVE_LEASE_ARBITER_BIT_MASK_LENGTH = 
MYSQL_LEASE_ARBITER_PREFIX + ".bitMaskLength";

Review Comment:
   usually `BIT_MASK` is one word, so `BITMASK` and `bitmask`



##########
gobblin-runtime/src/main/java/org/apache/gobblin/runtime/api/MysqlMultiActiveLeaseArbiterTestingDecorator.java:
##########
@@ -0,0 +1,206 @@
+package org.apache.gobblin.runtime.api;
+
+import com.google.common.base.Optional;
+import com.typesafe.config.Config;
+import java.io.IOException;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.HashMap;
+import javax.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.gobblin.configuration.ConfigurationKeys;
+import org.apache.gobblin.util.ConfigUtils;
+import org.apache.gobblin.util.HostUtils;
+
+
+/**
+ * This class is a decorator for {@link MysqlMultiActiveLeaseArbiter} used to 
model scenarios where a lease owner fails
+ * to complete a lease intermittently (representing a variety of slowness or 
failure cases that can result on the
+ * participant side, network connectivity, or database).
+ *
+ * It will fail on calls to {@link 
MysqlMultiActiveLeaseArbiter.recordLeaseSuccess()} where a function of the lease
+ * obtained timestamp matches a bitmask of the host. Ideally, each participant 
should fail on different calls (with
+ * limited overlap if we want to test that). We use a deterministic method of 
failing some calls to complete a lease
+ * success with the following methodology. We take the binary representation 
of the lease obtained timestamp, scatter
+ * its bits through bit interleaving of the first and second halves of the 
binary representation to differentiate
+ * behavior of consecutive timestamps, and compare the last N digits 
(determined through config) to the bit mask of the
+ * host. If the bitwise AND comparison to the host bit mask equals the bitmask 
we fail the call.
+ */
+@Slf4j
+public class MysqlMultiActiveLeaseArbiterTestingDecorator extends 
MysqlMultiActiveLeaseArbiter {
+  private final int bitMaskLength;
+  private final int numHosts;
+  private final HashMap<Integer, Integer> hostIdToBitMask = new HashMap();
+
+  @Inject
+  public MysqlMultiActiveLeaseArbiterTestingDecorator(Config config) throws 
IOException {
+    super(config);
+    bitMaskLength = ConfigUtils.getInt(config, 
ConfigurationKeys.MULTI_ACTIVE_LEASE_ARBITER_BIT_MASK_LENGTH,
+        ConfigurationKeys.DEFAULT_MULTI_ACTIVE_LEASE_ARBITER_BIT_MASK_LENGTH);
+    numHosts = ConfigUtils.getInt(config, 
ConfigurationKeys.MULTI_ACTIVE_LEASE_ARBITER_TESTING_DECORATOR_NUM_HOSTS,
+        
ConfigurationKeys.DEFAULT_MULTI_ACTIVE_LEASE_ARBITER_TESTING_DECORATOR_NUM_HOSTS);
+    initializeHostToBitMaskMap(config);
+  }
+
+  /**
+   * Extract bit mask from input config if one is present. Otherwise set the 
default bitmask for each host id which
+   * does not have overlapping bits between two hosts so that a given status 
will not fail on multiple hosts.
+   * @param config expected to contain a mapping of host address to bitmap in 
format
+   *              "host1:bitMask1,host2:bitMask2,...,hostN:bitMaskN"
+   * Note: that if the mapping format is incorrect or there are fewer than 
`bitMaskLength` mappings provide we utilize
+   *               the default to prevent unintended consequences of 
overlapping bit masks.
+   */
+  protected void initializeHostToBitMaskMap(Config config) {
+    // Set default bit masks for each hosts
+    // TODO: change this to parse default from Configuration.Keys property or 
is that unnecessary?
+    hostIdToBitMask.put(1, 0b0001);
+    hostIdToBitMask.put(2, 0b0010);
+    hostIdToBitMask.put(3, 0b0100);
+    hostIdToBitMask.put(4, 0b1000);
+
+    // If a valid mapping is provided in config, then we overwrite all the 
default values.
+    if 
(config.hasPath(ConfigurationKeys.MULTI_ACTIVE_LEASE_ARBITER_HOST_TO_BIT_MASK_MAP))
 {
+      String stringMap = 
config.getString(ConfigurationKeys.MULTI_ACTIVE_LEASE_ARBITER_HOST_TO_BIT_MASK_MAP);
+      Optional<HashMap<InetAddress,Integer>> addressToBitMapOptional = 
validateStringMap(stringMap, numHosts, bitMaskLength);
+      if (addressToBitMapOptional.isPresent()) {
+        for (InetAddress inetAddress : addressToBitMapOptional.get().keySet()) 
{
+          hostIdToBitMask.put(getHostIdFromAddress(inetAddress), 
addressToBitMapOptional.get().get(inetAddress));
+        }
+      }
+    }
+  }
+
+  protected static Optional<HashMap<InetAddress,Integer>> 
validateStringMap(String stringMap, int numHosts, int bitMaskLength) {
+    // TODO: Refactor to increase abstraction
+    String[] hostAddressToMap = stringMap.split(",");
+    if (hostAddressToMap.length < numHosts) {
+      log.warn("Host address to bit mask map expected to be in format "
+          + "`host1:bitMask1,host2:bitMask2,...,hostN:bitMaskN` with at least 
" + numHosts + " hosts necessary. Using "
+          + "default.");
+      return Optional.absent();
+    }
+    HashMap<InetAddress,Integer> addressToBitmap = new HashMap<>();
+    for (String mapping : hostAddressToMap) {
+      String[] keyAndValue = mapping.split(":");
+      if (keyAndValue.length != 2) {
+        log.warn("Host address to bit mask map should be separated by `:`. 
Expected format "
+            + "`host1:bitMask1,host2:bitMask2,...,hostN:bitMaskN`. Using 
default.");
+      }
+      Optional<InetAddress> addressOptional = 
HostUtils.getAddressForHostName(keyAndValue[0]);
+      if (!addressOptional.isPresent()) {
+        log.warn("Invalid hostname format in configuration. Using default.");
+        return Optional.absent();
+      }
+      if (!isValidBitMask(keyAndValue[1], bitMaskLength)) {
+        log.warn("Invalid bit mask format in configuration, expected to be " + 
bitMaskLength + " digit binary number "
+            + "ie: `1010`. Using default.");
+        return Optional.absent();
+      }
+      addressToBitmap.put(addressOptional.get(), 
Integer.valueOf(keyAndValue[1], 2));
+    }
+    return Optional.of(addressToBitmap);
+  }
+
+  protected static boolean isValidBitMask(String input, int bitMaskLength) {
+    // Check if the string contains only 0s and 1s
+    if (!input.matches("[01]+")) {
+      return false;
+    }
+    // Check if the string is exactly `bitMaskLength` characters long
+    if (input.length() != bitMaskLength) {
+      return false;
+    }
+    return true;
+  }
+
+  /**
+   * Retrieve the host id as a number between 1 through `numHosts` by using 
the host address's hashcode.
+   * @return
+   */
+  protected int getHostIdFromAddress(InetAddress address) {
+      return (address.hashCode() % numHosts) + 1;
+  }
+
+  /**
+   * Returns bit mask for given host
+   * @param hostId
+   * @return
+   */
+  protected int getBitMaskForHostId(int hostId) {
+    return this.hostIdToBitMask.get(hostId);
+  }
+
+  /**
+   * Return bit mask for the current host
+   */
+  protected int getBitMaskForHost() throws UnknownHostException {
+    return 
getBitMaskForHostId(getHostIdFromAddress(Inet6Address.getLocalHost()));
+  }
+
+  /**
+   * Apply a deterministic function to the input status to evaluate whether 
this host should fail to complete a lease
+   * for testing purposes.
+   */
+  @Override
+  public boolean recordLeaseSuccess(LeaseObtainedStatus status) throws 
IOException {
+    // Get host bit mask
+    int bitMask = getBitMaskForHost();
+    if (shouldFailLeaseCompletionAttempt(status, bitMask, bitMaskLength)) {
+      log.info("Multi-active lease arbiter lease attempt: [{}, eventTimestamp: 
{}] - FAILED to complete in testing "
+          + "scenario");
+      return false;
+    } else {
+      return super.recordLeaseSuccess(status);
+    }
+  }
+
+  /**
+   * Applies bitmask to lease acquisition timestamp of a status parameter 
provided to evaluate if the lease attempt to
+   * this host should fail
+   * @param status {@link 
org.apache.gobblin.runtime.api.MultiActiveLeaseArbiter.LeaseObtainedStatus}
+   * @param bitmask 4-bit binary integer used to compare against modified 
lease acquisition timestamp
+   * @return true if the host should fail the lease completion attempt
+   */
+  protected static boolean 
shouldFailLeaseCompletionAttempt(LeaseObtainedStatus status, int bitmask,

Review Comment:
   likely should be `@VisibleForTesting`



##########
gobblin-runtime/src/main/java/org/apache/gobblin/runtime/api/MysqlMultiActiveLeaseArbiterTestingDecorator.java:
##########
@@ -0,0 +1,206 @@
+package org.apache.gobblin.runtime.api;
+
+import com.google.common.base.Optional;
+import com.typesafe.config.Config;
+import java.io.IOException;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.HashMap;
+import javax.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.gobblin.configuration.ConfigurationKeys;
+import org.apache.gobblin.util.ConfigUtils;
+import org.apache.gobblin.util.HostUtils;
+
+
+/**
+ * This class is a decorator for {@link MysqlMultiActiveLeaseArbiter} used to 
model scenarios where a lease owner fails
+ * to complete a lease intermittently (representing a variety of slowness or 
failure cases that can result on the
+ * participant side, network connectivity, or database).
+ *
+ * It will fail on calls to {@link 
MysqlMultiActiveLeaseArbiter.recordLeaseSuccess()} where a function of the lease
+ * obtained timestamp matches a bitmask of the host. Ideally, each participant 
should fail on different calls (with
+ * limited overlap if we want to test that). We use a deterministic method of 
failing some calls to complete a lease
+ * success with the following methodology. We take the binary representation 
of the lease obtained timestamp, scatter
+ * its bits through bit interleaving of the first and second halves of the 
binary representation to differentiate
+ * behavior of consecutive timestamps, and compare the last N digits 
(determined through config) to the bit mask of the
+ * host. If the bitwise AND comparison to the host bit mask equals the bitmask 
we fail the call.
+ */
+@Slf4j
+public class MysqlMultiActiveLeaseArbiterTestingDecorator extends 
MysqlMultiActiveLeaseArbiter {
+  private final int bitMaskLength;
+  private final int numHosts;
+  private final HashMap<Integer, Integer> hostIdToBitMask = new HashMap();
+
+  @Inject
+  public MysqlMultiActiveLeaseArbiterTestingDecorator(Config config) throws 
IOException {
+    super(config);
+    bitMaskLength = ConfigUtils.getInt(config, 
ConfigurationKeys.MULTI_ACTIVE_LEASE_ARBITER_BIT_MASK_LENGTH,
+        ConfigurationKeys.DEFAULT_MULTI_ACTIVE_LEASE_ARBITER_BIT_MASK_LENGTH);
+    numHosts = ConfigUtils.getInt(config, 
ConfigurationKeys.MULTI_ACTIVE_LEASE_ARBITER_TESTING_DECORATOR_NUM_HOSTS,
+        
ConfigurationKeys.DEFAULT_MULTI_ACTIVE_LEASE_ARBITER_TESTING_DECORATOR_NUM_HOSTS);
+    initializeHostToBitMaskMap(config);
+  }
+
+  /**
+   * Extract bit mask from input config if one is present. Otherwise set the 
default bitmask for each host id which
+   * does not have overlapping bits between two hosts so that a given status 
will not fail on multiple hosts.
+   * @param config expected to contain a mapping of host address to bitmap in 
format
+   *              "host1:bitMask1,host2:bitMask2,...,hostN:bitMaskN"
+   * Note: that if the mapping format is incorrect or there are fewer than 
`bitMaskLength` mappings provide we utilize
+   *               the default to prevent unintended consequences of 
overlapping bit masks.
+   */
+  protected void initializeHostToBitMaskMap(Config config) {
+    // Set default bit masks for each hosts
+    // TODO: change this to parse default from Configuration.Keys property or 
is that unnecessary?
+    hostIdToBitMask.put(1, 0b0001);
+    hostIdToBitMask.put(2, 0b0010);
+    hostIdToBitMask.put(3, 0b0100);
+    hostIdToBitMask.put(4, 0b1000);
+
+    // If a valid mapping is provided in config, then we overwrite all the 
default values.
+    if 
(config.hasPath(ConfigurationKeys.MULTI_ACTIVE_LEASE_ARBITER_HOST_TO_BIT_MASK_MAP))
 {
+      String stringMap = 
config.getString(ConfigurationKeys.MULTI_ACTIVE_LEASE_ARBITER_HOST_TO_BIT_MASK_MAP);
+      Optional<HashMap<InetAddress,Integer>> addressToBitMapOptional = 
validateStringMap(stringMap, numHosts, bitMaskLength);
+      if (addressToBitMapOptional.isPresent()) {
+        for (InetAddress inetAddress : addressToBitMapOptional.get().keySet()) 
{
+          hostIdToBitMask.put(getHostIdFromAddress(inetAddress), 
addressToBitMapOptional.get().get(inetAddress));
+        }
+      }
+    }
+  }
+
+  protected static Optional<HashMap<InetAddress,Integer>> 
validateStringMap(String stringMap, int numHosts, int bitMaskLength) {
+    // TODO: Refactor to increase abstraction
+    String[] hostAddressToMap = stringMap.split(",");
+    if (hostAddressToMap.length < numHosts) {
+      log.warn("Host address to bit mask map expected to be in format "
+          + "`host1:bitMask1,host2:bitMask2,...,hostN:bitMaskN` with at least 
" + numHosts + " hosts necessary. Using "
+          + "default.");
+      return Optional.absent();
+    }
+    HashMap<InetAddress,Integer> addressToBitmap = new HashMap<>();
+    for (String mapping : hostAddressToMap) {
+      String[] keyAndValue = mapping.split(":");
+      if (keyAndValue.length != 2) {
+        log.warn("Host address to bit mask map should be separated by `:`. 
Expected format "
+            + "`host1:bitMask1,host2:bitMask2,...,hostN:bitMaskN`. Using 
default.");
+      }
+      Optional<InetAddress> addressOptional = 
HostUtils.getAddressForHostName(keyAndValue[0]);
+      if (!addressOptional.isPresent()) {
+        log.warn("Invalid hostname format in configuration. Using default.");
+        return Optional.absent();
+      }
+      if (!isValidBitMask(keyAndValue[1], bitMaskLength)) {
+        log.warn("Invalid bit mask format in configuration, expected to be " + 
bitMaskLength + " digit binary number "
+            + "ie: `1010`. Using default.");
+        return Optional.absent();
+      }
+      addressToBitmap.put(addressOptional.get(), 
Integer.valueOf(keyAndValue[1], 2));
+    }
+    return Optional.of(addressToBitmap);
+  }
+
+  protected static boolean isValidBitMask(String input, int bitMaskLength) {
+    // Check if the string contains only 0s and 1s
+    if (!input.matches("[01]+")) {
+      return false;
+    }
+    // Check if the string is exactly `bitMaskLength` characters long
+    if (input.length() != bitMaskLength) {
+      return false;
+    }
+    return true;
+  }
+
+  /**
+   * Retrieve the host id as a number between 1 through `numHosts` by using 
the host address's hashcode.
+   * @return
+   */
+  protected int getHostIdFromAddress(InetAddress address) {
+      return (address.hashCode() % numHosts) + 1;
+  }
+
+  /**
+   * Returns bit mask for given host
+   * @param hostId
+   * @return
+   */
+  protected int getBitMaskForHostId(int hostId) {
+    return this.hostIdToBitMask.get(hostId);
+  }
+
+  /**
+   * Return bit mask for the current host
+   */
+  protected int getBitMaskForHost() throws UnknownHostException {
+    return 
getBitMaskForHostId(getHostIdFromAddress(Inet6Address.getLocalHost()));
+  }
+
+  /**
+   * Apply a deterministic function to the input status to evaluate whether 
this host should fail to complete a lease
+   * for testing purposes.
+   */
+  @Override
+  public boolean recordLeaseSuccess(LeaseObtainedStatus status) throws 
IOException {
+    // Get host bit mask
+    int bitMask = getBitMaskForHost();
+    if (shouldFailLeaseCompletionAttempt(status, bitMask, bitMaskLength)) {
+      log.info("Multi-active lease arbiter lease attempt: [{}, eventTimestamp: 
{}] - FAILED to complete in testing "
+          + "scenario");
+      return false;
+    } else {
+      return super.recordLeaseSuccess(status);
+    }
+  }
+
+  /**
+   * Applies bitmask to lease acquisition timestamp of a status parameter 
provided to evaluate if the lease attempt to
+   * this host should fail
+   * @param status {@link 
org.apache.gobblin.runtime.api.MultiActiveLeaseArbiter.LeaseObtainedStatus}
+   * @param bitmask 4-bit binary integer used to compare against modified 
lease acquisition timestamp
+   * @return true if the host should fail the lease completion attempt
+   */
+  protected static boolean 
shouldFailLeaseCompletionAttempt(LeaseObtainedStatus status, int bitmask,
+      int bitMaskLength) {
+    // Convert event timestamp to binary
+    Long.toString(status.getLeaseAcquisitionTimestamp()).getBytes();

Review Comment:
   remove this (since not assigned)



##########
gobblin-runtime/src/main/java/org/apache/gobblin/runtime/api/MysqlMultiActiveLeaseArbiterTestingDecorator.java:
##########
@@ -0,0 +1,206 @@
+package org.apache.gobblin.runtime.api;
+
+import com.google.common.base.Optional;
+import com.typesafe.config.Config;
+import java.io.IOException;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.HashMap;
+import javax.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.gobblin.configuration.ConfigurationKeys;
+import org.apache.gobblin.util.ConfigUtils;
+import org.apache.gobblin.util.HostUtils;
+
+
+/**
+ * This class is a decorator for {@link MysqlMultiActiveLeaseArbiter} used to 
model scenarios where a lease owner fails
+ * to complete a lease intermittently (representing a variety of slowness or 
failure cases that can result on the
+ * participant side, network connectivity, or database).
+ *
+ * It will fail on calls to {@link 
MysqlMultiActiveLeaseArbiter.recordLeaseSuccess()} where a function of the lease
+ * obtained timestamp matches a bitmask of the host. Ideally, each participant 
should fail on different calls (with
+ * limited overlap if we want to test that). We use a deterministic method of 
failing some calls to complete a lease
+ * success with the following methodology. We take the binary representation 
of the lease obtained timestamp, scatter
+ * its bits through bit interleaving of the first and second halves of the 
binary representation to differentiate
+ * behavior of consecutive timestamps, and compare the last N digits 
(determined through config) to the bit mask of the
+ * host. If the bitwise AND comparison to the host bit mask equals the bitmask 
we fail the call.
+ */
+@Slf4j
+public class MysqlMultiActiveLeaseArbiterTestingDecorator extends 
MysqlMultiActiveLeaseArbiter {

Review Comment:
   the name `TestingDecorator` suggests nothing about behavior.  Decorator 
seems a relevant pattern, and suggests reusability, but it's more important to 
name how/why it decorates than to state vaguely that decoration is afoot.
   
   how about `FailureInjectingMALeaseArbiter` or 
`FailureInjectingMALeaseArbiterDecorator`?
   
   Also, on the subject of reuse, why base this specifically on 
`MysqlMALeaseArbiter`, rather the `MALeaseArbiter` interface/base class?  as 
currently written, this is not truly a decorator, but rather an extension to 
`MysqlMALA`.  (often, in java, a decorator would implement an interface, but 
almost never extend a concrete derived class that already implements it.)
   
   to be a decorator, the ctor should either take a `MALeaseArbiter` instance 
to delegate to or else create one internally.  here, I suggest the latter, 
which means this class (itself named within config) should itself read its own 
(prefixed) config to indicate the class name it should internally create an 
instance of. 



##########
gobblin-runtime/src/main/java/org/apache/gobblin/runtime/api/MysqlMultiActiveLeaseArbiterTestingDecorator.java:
##########
@@ -0,0 +1,206 @@
+package org.apache.gobblin.runtime.api;
+
+import com.google.common.base.Optional;
+import com.typesafe.config.Config;
+import java.io.IOException;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.HashMap;
+import javax.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.gobblin.configuration.ConfigurationKeys;
+import org.apache.gobblin.util.ConfigUtils;
+import org.apache.gobblin.util.HostUtils;
+
+
+/**
+ * This class is a decorator for {@link MysqlMultiActiveLeaseArbiter} used to 
model scenarios where a lease owner fails
+ * to complete a lease intermittently (representing a variety of slowness or 
failure cases that can result on the
+ * participant side, network connectivity, or database).
+ *
+ * It will fail on calls to {@link 
MysqlMultiActiveLeaseArbiter.recordLeaseSuccess()} where a function of the lease
+ * obtained timestamp matches a bitmask of the host. Ideally, each participant 
should fail on different calls (with
+ * limited overlap if we want to test that). We use a deterministic method of 
failing some calls to complete a lease
+ * success with the following methodology. We take the binary representation 
of the lease obtained timestamp, scatter
+ * its bits through bit interleaving of the first and second halves of the 
binary representation to differentiate
+ * behavior of consecutive timestamps, and compare the last N digits 
(determined through config) to the bit mask of the
+ * host. If the bitwise AND comparison to the host bit mask equals the bitmask 
we fail the call.
+ */
+@Slf4j
+public class MysqlMultiActiveLeaseArbiterTestingDecorator extends 
MysqlMultiActiveLeaseArbiter {
+  private final int bitMaskLength;
+  private final int numHosts;
+  private final HashMap<Integer, Integer> hostIdToBitMask = new HashMap();
+
+  @Inject
+  public MysqlMultiActiveLeaseArbiterTestingDecorator(Config config) throws 
IOException {
+    super(config);
+    bitMaskLength = ConfigUtils.getInt(config, 
ConfigurationKeys.MULTI_ACTIVE_LEASE_ARBITER_BIT_MASK_LENGTH,
+        ConfigurationKeys.DEFAULT_MULTI_ACTIVE_LEASE_ARBITER_BIT_MASK_LENGTH);
+    numHosts = ConfigUtils.getInt(config, 
ConfigurationKeys.MULTI_ACTIVE_LEASE_ARBITER_TESTING_DECORATOR_NUM_HOSTS,
+        
ConfigurationKeys.DEFAULT_MULTI_ACTIVE_LEASE_ARBITER_TESTING_DECORATOR_NUM_HOSTS);
+    initializeHostToBitMaskMap(config);
+  }
+
+  /**
+   * Extract bit mask from input config if one is present. Otherwise set the 
default bitmask for each host id which
+   * does not have overlapping bits between two hosts so that a given status 
will not fail on multiple hosts.
+   * @param config expected to contain a mapping of host address to bitmap in 
format
+   *              "host1:bitMask1,host2:bitMask2,...,hostN:bitMaskN"
+   * Note: that if the mapping format is incorrect or there are fewer than 
`bitMaskLength` mappings provide we utilize
+   *               the default to prevent unintended consequences of 
overlapping bit masks.
+   */
+  protected void initializeHostToBitMaskMap(Config config) {
+    // Set default bit masks for each hosts
+    // TODO: change this to parse default from Configuration.Keys property or 
is that unnecessary?
+    hostIdToBitMask.put(1, 0b0001);
+    hostIdToBitMask.put(2, 0b0010);
+    hostIdToBitMask.put(3, 0b0100);
+    hostIdToBitMask.put(4, 0b1000);
+
+    // If a valid mapping is provided in config, then we overwrite all the 
default values.
+    if 
(config.hasPath(ConfigurationKeys.MULTI_ACTIVE_LEASE_ARBITER_HOST_TO_BIT_MASK_MAP))
 {
+      String stringMap = 
config.getString(ConfigurationKeys.MULTI_ACTIVE_LEASE_ARBITER_HOST_TO_BIT_MASK_MAP);
+      Optional<HashMap<InetAddress,Integer>> addressToBitMapOptional = 
validateStringMap(stringMap, numHosts, bitMaskLength);
+      if (addressToBitMapOptional.isPresent()) {
+        for (InetAddress inetAddress : addressToBitMapOptional.get().keySet()) 
{
+          hostIdToBitMask.put(getHostIdFromAddress(inetAddress), 
addressToBitMapOptional.get().get(inetAddress));
+        }
+      }
+    }
+  }
+
+  protected static Optional<HashMap<InetAddress,Integer>> 
validateStringMap(String stringMap, int numHosts, int bitMaskLength) {
+    // TODO: Refactor to increase abstraction
+    String[] hostAddressToMap = stringMap.split(",");
+    if (hostAddressToMap.length < numHosts) {
+      log.warn("Host address to bit mask map expected to be in format "
+          + "`host1:bitMask1,host2:bitMask2,...,hostN:bitMaskN` with at least 
" + numHosts + " hosts necessary. Using "
+          + "default.");
+      return Optional.absent();
+    }
+    HashMap<InetAddress,Integer> addressToBitmap = new HashMap<>();
+    for (String mapping : hostAddressToMap) {
+      String[] keyAndValue = mapping.split(":");
+      if (keyAndValue.length != 2) {
+        log.warn("Host address to bit mask map should be separated by `:`. 
Expected format "
+            + "`host1:bitMask1,host2:bitMask2,...,hostN:bitMaskN`. Using 
default.");
+      }
+      Optional<InetAddress> addressOptional = 
HostUtils.getAddressForHostName(keyAndValue[0]);
+      if (!addressOptional.isPresent()) {
+        log.warn("Invalid hostname format in configuration. Using default.");
+        return Optional.absent();
+      }
+      if (!isValidBitMask(keyAndValue[1], bitMaskLength)) {
+        log.warn("Invalid bit mask format in configuration, expected to be " + 
bitMaskLength + " digit binary number "
+            + "ie: `1010`. Using default.");
+        return Optional.absent();
+      }
+      addressToBitmap.put(addressOptional.get(), 
Integer.valueOf(keyAndValue[1], 2));
+    }
+    return Optional.of(addressToBitmap);
+  }
+
+  protected static boolean isValidBitMask(String input, int bitMaskLength) {
+    // Check if the string contains only 0s and 1s
+    if (!input.matches("[01]+")) {
+      return false;
+    }
+    // Check if the string is exactly `bitMaskLength` characters long
+    if (input.length() != bitMaskLength) {
+      return false;
+    }
+    return true;
+  }
+
+  /**
+   * Retrieve the host id as a number between 1 through `numHosts` by using 
the host address's hashcode.
+   * @return
+   */
+  protected int getHostIdFromAddress(InetAddress address) {
+      return (address.hashCode() % numHosts) + 1;
+  }
+
+  /**
+   * Returns bit mask for given host
+   * @param hostId
+   * @return
+   */
+  protected int getBitMaskForHostId(int hostId) {
+    return this.hostIdToBitMask.get(hostId);
+  }
+
+  /**
+   * Return bit mask for the current host
+   */
+  protected int getBitMaskForHost() throws UnknownHostException {
+    return 
getBitMaskForHostId(getHostIdFromAddress(Inet6Address.getLocalHost()));
+  }
+
+  /**
+   * Apply a deterministic function to the input status to evaluate whether 
this host should fail to complete a lease
+   * for testing purposes.
+   */
+  @Override
+  public boolean recordLeaseSuccess(LeaseObtainedStatus status) throws 
IOException {
+    // Get host bit mask
+    int bitMask = getBitMaskForHost();
+    if (shouldFailLeaseCompletionAttempt(status, bitMask, bitMaskLength)) {
+      log.info("Multi-active lease arbiter lease attempt: [{}, eventTimestamp: 
{}] - FAILED to complete in testing "
+          + "scenario");
+      return false;
+    } else {
+      return super.recordLeaseSuccess(status);
+    }
+  }
+
+  /**
+   * Applies bitmask to lease acquisition timestamp of a status parameter 
provided to evaluate if the lease attempt to
+   * this host should fail
+   * @param status {@link 
org.apache.gobblin.runtime.api.MultiActiveLeaseArbiter.LeaseObtainedStatus}
+   * @param bitmask 4-bit binary integer used to compare against modified 
lease acquisition timestamp
+   * @return true if the host should fail the lease completion attempt
+   */
+  protected static boolean 
shouldFailLeaseCompletionAttempt(LeaseObtainedStatus status, int bitmask,
+      int bitMaskLength) {
+    // Convert event timestamp to binary
+    Long.toString(status.getLeaseAcquisitionTimestamp()).getBytes();
+    String binaryString = 
Long.toBinaryString(status.getLeaseAcquisitionTimestamp());
+    // Scatter binary bits
+    String scatteredBinaryString = scatterBinaryStringBits(binaryString);
+    // Take last `bitMaskLength`` bits of the string
+    int length = scatteredBinaryString.length();
+    String shortenedBinaryString = 
scatteredBinaryString.substring(length-bitMaskLength, length);

Review Comment:
   let's do binary entirely with numbers (no strings).  e.g.:
   ```
   boolean shouldFail = 0 != (
       (scatterTimestamp(ts) & considerationMask)
       & hostBitmask
   )
   ```



##########
gobblin-runtime/src/main/java/org/apache/gobblin/runtime/api/MysqlMultiActiveLeaseArbiterTestingDecorator.java:
##########
@@ -0,0 +1,206 @@
+package org.apache.gobblin.runtime.api;
+
+import com.google.common.base.Optional;
+import com.typesafe.config.Config;
+import java.io.IOException;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.HashMap;
+import javax.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.gobblin.configuration.ConfigurationKeys;
+import org.apache.gobblin.util.ConfigUtils;
+import org.apache.gobblin.util.HostUtils;
+
+
+/**
+ * This class is a decorator for {@link MysqlMultiActiveLeaseArbiter} used to 
model scenarios where a lease owner fails
+ * to complete a lease intermittently (representing a variety of slowness or 
failure cases that can result on the
+ * participant side, network connectivity, or database).
+ *
+ * It will fail on calls to {@link 
MysqlMultiActiveLeaseArbiter.recordLeaseSuccess()} where a function of the lease
+ * obtained timestamp matches a bitmask of the host. Ideally, each participant 
should fail on different calls (with
+ * limited overlap if we want to test that). We use a deterministic method of 
failing some calls to complete a lease
+ * success with the following methodology. We take the binary representation 
of the lease obtained timestamp, scatter
+ * its bits through bit interleaving of the first and second halves of the 
binary representation to differentiate
+ * behavior of consecutive timestamps, and compare the last N digits 
(determined through config) to the bit mask of the
+ * host. If the bitwise AND comparison to the host bit mask equals the bitmask 
we fail the call.
+ */
+@Slf4j
+public class MysqlMultiActiveLeaseArbiterTestingDecorator extends 
MysqlMultiActiveLeaseArbiter {
+  private final int bitMaskLength;

Review Comment:
   I suggest reading the length, but converting it to the actual mask, since 
that's what we need to use; e.g.:
   ```
   int considerationMask =
       (1 << (bitmaskLength + 1)) - 1
   // alt.: (~0) >>> (32 - bitmaskLength)
   ```



##########
gobblin-runtime/src/main/java/org/apache/gobblin/runtime/api/MysqlMultiActiveLeaseArbiterTestingDecorator.java:
##########
@@ -0,0 +1,206 @@
+package org.apache.gobblin.runtime.api;
+
+import com.google.common.base.Optional;
+import com.typesafe.config.Config;
+import java.io.IOException;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.HashMap;
+import javax.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.gobblin.configuration.ConfigurationKeys;
+import org.apache.gobblin.util.ConfigUtils;
+import org.apache.gobblin.util.HostUtils;
+
+
+/**
+ * This class is a decorator for {@link MysqlMultiActiveLeaseArbiter} used to 
model scenarios where a lease owner fails
+ * to complete a lease intermittently (representing a variety of slowness or 
failure cases that can result on the
+ * participant side, network connectivity, or database).
+ *
+ * It will fail on calls to {@link 
MysqlMultiActiveLeaseArbiter.recordLeaseSuccess()} where a function of the lease
+ * obtained timestamp matches a bitmask of the host. Ideally, each participant 
should fail on different calls (with
+ * limited overlap if we want to test that). We use a deterministic method of 
failing some calls to complete a lease
+ * success with the following methodology. We take the binary representation 
of the lease obtained timestamp, scatter
+ * its bits through bit interleaving of the first and second halves of the 
binary representation to differentiate
+ * behavior of consecutive timestamps, and compare the last N digits 
(determined through config) to the bit mask of the

Review Comment:
   I really like the idea of scattering (to avoid long runs of on/off).  while 
I have very little background in number theory, the idea of interleaving 
high-order with low-order bits intuitively concerns me... so not sure if I'm 
missing something.
   
   here's my logic: when representing millis as a java long, we can essentially 
consider the high-order bits to be constants, since the lowest of the long's 
high bits [32:63] only changes once every 10^9 secs.  after interleaving, 
wouldn't odd position bits nearly never change, while even-positions would.  
the assignment:
   ```
   host0:0001,host1:0010,host2:0100,host3:1000
   ```
   would give drastically different probability for `host1` and `host3`, than 
for `host0`, and `host2`--right?
   
   instead I suggest bit "scattering" by passing the number through a hash 
digest, like MD5 or SHA1



##########
gobblin-runtime/src/main/java/org/apache/gobblin/runtime/api/MysqlMultiActiveLeaseArbiterTestingDecorator.java:
##########
@@ -0,0 +1,206 @@
+package org.apache.gobblin.runtime.api;
+
+import com.google.common.base.Optional;
+import com.typesafe.config.Config;
+import java.io.IOException;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.HashMap;
+import javax.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.gobblin.configuration.ConfigurationKeys;
+import org.apache.gobblin.util.ConfigUtils;
+import org.apache.gobblin.util.HostUtils;
+
+
+/**
+ * This class is a decorator for {@link MysqlMultiActiveLeaseArbiter} used to 
model scenarios where a lease owner fails
+ * to complete a lease intermittently (representing a variety of slowness or 
failure cases that can result on the
+ * participant side, network connectivity, or database).
+ *
+ * It will fail on calls to {@link 
MysqlMultiActiveLeaseArbiter.recordLeaseSuccess()} where a function of the lease
+ * obtained timestamp matches a bitmask of the host. Ideally, each participant 
should fail on different calls (with
+ * limited overlap if we want to test that). We use a deterministic method of 
failing some calls to complete a lease
+ * success with the following methodology. We take the binary representation 
of the lease obtained timestamp, scatter
+ * its bits through bit interleaving of the first and second halves of the 
binary representation to differentiate
+ * behavior of consecutive timestamps, and compare the last N digits 
(determined through config) to the bit mask of the
+ * host. If the bitwise AND comparison to the host bit mask equals the bitmask 
we fail the call.
+ */
+@Slf4j
+public class MysqlMultiActiveLeaseArbiterTestingDecorator extends 
MysqlMultiActiveLeaseArbiter {
+  private final int bitMaskLength;
+  private final int numHosts;
+  private final HashMap<Integer, Integer> hostIdToBitMask = new HashMap();
+
+  @Inject
+  public MysqlMultiActiveLeaseArbiterTestingDecorator(Config config) throws 
IOException {
+    super(config);
+    bitMaskLength = ConfigUtils.getInt(config, 
ConfigurationKeys.MULTI_ACTIVE_LEASE_ARBITER_BIT_MASK_LENGTH,
+        ConfigurationKeys.DEFAULT_MULTI_ACTIVE_LEASE_ARBITER_BIT_MASK_LENGTH);
+    numHosts = ConfigUtils.getInt(config, 
ConfigurationKeys.MULTI_ACTIVE_LEASE_ARBITER_TESTING_DECORATOR_NUM_HOSTS,
+        
ConfigurationKeys.DEFAULT_MULTI_ACTIVE_LEASE_ARBITER_TESTING_DECORATOR_NUM_HOSTS);
+    initializeHostToBitMaskMap(config);
+  }
+
+  /**
+   * Extract bit mask from input config if one is present. Otherwise set the 
default bitmask for each host id which
+   * does not have overlapping bits between two hosts so that a given status 
will not fail on multiple hosts.
+   * @param config expected to contain a mapping of host address to bitmap in 
format
+   *              "host1:bitMask1,host2:bitMask2,...,hostN:bitMaskN"
+   * Note: that if the mapping format is incorrect or there are fewer than 
`bitMaskLength` mappings provide we utilize
+   *               the default to prevent unintended consequences of 
overlapping bit masks.
+   */
+  protected void initializeHostToBitMaskMap(Config config) {
+    // Set default bit masks for each hosts
+    // TODO: change this to parse default from Configuration.Keys property or 
is that unnecessary?
+    hostIdToBitMask.put(1, 0b0001);
+    hostIdToBitMask.put(2, 0b0010);
+    hostIdToBitMask.put(3, 0b0100);
+    hostIdToBitMask.put(4, 0b1000);

Review Comment:
   seems more than unnecessary, and actually confusing.  if a host is not named 
in the config, it's bitmask should match nothing.  AFA behavior, such hosts 
should play it straight and not inject any failure



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


Reply via email to