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

ctubbsii 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 9af60ea  Use sets instead of arrays for volumes (#1551)
9af60ea is described below

commit 9af60eacc570ccc807201cb0673123c67d3e6d07
Author: Christopher Tubbs <[email protected]>
AuthorDate: Fri Mar 6 12:04:11 2020 -0500

    Use sets instead of arrays for volumes (#1551)
    
    * Use sets instead of arrays for volumes
    
    Originally ACCUMULO-3376, this change replaces the use of `String[]`
    with `Set<String>` throughout the VolumeChooser and VolumeManager code.
    This makes the API for VolumeChooser a bit more friendly, making it
    easier to use Streams and lambdas to filter and transform volumes
    throughout the code.
    
    This change also adds some more sanity checks on the instance volumes
    configuration (checking for empty list and duplicates).
    
    This also includes a utility to warn about planned API changes in
    internal pluggable code (such as the VolumeChooser), but without being
    too spammy.
    
    Update the default `VolumeChooser.choosable()` to return the full set of
    volumes, so that all are checked for flush and sync support on tserver
    startup. This choosable mechanism is a bit dubious anyway, because
    choosers could make different decisions over time (in response to
    configuration changes, for example) than they do at startup. So,
    defaulting to checking for the maximal set seems like a better strategy
    out-of-the-box.
    
    Make ServerConstants.baseUris unmodifiable.
    
    * Update 
server/master/src/main/java/org/apache/accumulo/master/tableOps/tableImport/CreateImportDir.java
    
    Co-Authored-By: Mike Miller <[email protected]>
    
    Co-authored-by: Mike Miller <[email protected]>
---
 .../accumulo/core/volume/VolumeConfiguration.java  | 43 ++++++++++++----------
 .../apache/accumulo/server/ServerConstants.java    | 25 +++++++------
 .../server/fs/InterfaceEvolutionWarner.java        | 42 +++++++++++++++++++++
 .../accumulo/server/fs/PerTableVolumeChooser.java  |  5 ++-
 .../accumulo/server/fs/PreferredVolumeChooser.java | 29 ++++++++-------
 .../accumulo/server/fs/RandomVolumeChooser.java    |  8 ++--
 .../server/fs/SpaceAwareVolumeChooser.java         | 18 ++++-----
 .../apache/accumulo/server/fs/VolumeChooser.java   | 38 ++++++++++++++++---
 .../apache/accumulo/server/fs/VolumeManager.java   |  7 ++--
 .../accumulo/server/fs/VolumeManagerImpl.java      | 17 ++++-----
 .../apache/accumulo/server/init/Initialize.java    | 15 ++++----
 .../apache/accumulo/server/util/ZooKeeperMain.java |  2 +-
 .../org/apache/accumulo/server/util/ZooZap.java    |  2 +-
 .../accumulo/server/ServerConstantsTest.java       | 33 ++++++++---------
 .../server/fs/PreferredVolumeChooserTest.java      | 40 ++++++--------------
 .../server/fs/SpaceAwareVolumeChooserTest.java     |  3 +-
 .../accumulo/server/fs/VolumeManagerImplTest.java  | 13 ++++---
 .../tableOps/tableImport/CreateImportDir.java      |  7 ++--
 .../org/apache/accumulo/tserver/TabletServer.java  |  4 +-
 .../org/apache/accumulo/tserver/log/DfsLogger.java |  4 +-
 .../tserver/TabletServerSyncCheckTest.java         |  5 ++-
 .../apache/accumulo/test/FairVolumeChooser.java    | 14 ++++---
 .../accumulo/test/functional/SplitRecoveryIT.java  |  4 +-
 23 files changed, 218 insertions(+), 160 deletions(-)

diff --git 
a/core/src/main/java/org/apache/accumulo/core/volume/VolumeConfiguration.java 
b/core/src/main/java/org/apache/accumulo/core/volume/VolumeConfiguration.java
index 5f4080d..fc2ab67 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/volume/VolumeConfiguration.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/volume/VolumeConfiguration.java
@@ -23,6 +23,10 @@ import static java.util.Objects.requireNonNull;
 import java.io.IOException;
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 import org.apache.accumulo.core.conf.AccumuloConfiguration;
 import org.apache.accumulo.core.conf.Property;
@@ -87,18 +91,17 @@ public class VolumeConfiguration {
     return baseDir;
   }
 
-  public static String[] getVolumeUris(AccumuloConfiguration conf, 
Configuration hadoopConfig) {
+  public static Set<String> getVolumeUris(AccumuloConfiguration conf, 
Configuration hadoopConfig) {
     String ns = conf.get(Property.INSTANCE_VOLUMES);
 
-    String[] configuredBaseDirs;
+    // preserve configuration order using LinkedHashSet
+    ArrayList<String> configuredBaseDirs = new ArrayList<>();
 
     if (ns == null || ns.isEmpty()) {
       // Fall back to using the old config values
-      configuredBaseDirs = new String[] {getConfiguredBaseDir(conf, 
hadoopConfig)};
+      configuredBaseDirs.add(getConfiguredBaseDir(conf, hadoopConfig));
     } else {
       String[] namespaces = ns.split(",");
-      configuredBaseDirs = new String[namespaces.length];
-      int i = 0;
       for (String namespace : namespaces) {
         if (!namespace.contains(":")) {
           throw new IllegalArgumentException("Expected fully qualified URI for 
"
@@ -107,7 +110,7 @@ public class VolumeConfiguration {
 
         try {
           // pass through URI to unescape hex encoded chars (e.g. convert %2C 
to "," char)
-          configuredBaseDirs[i++] = new Path(new URI(namespace)).toString();
+          configuredBaseDirs.add(new Path(new URI(namespace)).toString());
         } catch (URISyntaxException e) {
           throw new 
IllegalArgumentException(Property.INSTANCE_VOLUMES.getKey() + " contains "
               + namespace + " which has a syntax error", e);
@@ -115,21 +118,23 @@ public class VolumeConfiguration {
       }
     }
 
-    return configuredBaseDirs;
+    LinkedHashSet<String> deduplicated = new LinkedHashSet<>();
+    deduplicated.addAll(configuredBaseDirs);
+    if (deduplicated.isEmpty()) {
+      throw new IllegalArgumentException(
+          Property.INSTANCE_VOLUMES.getKey() + " contains no volumes (" + ns + 
")");
+    }
+    if (deduplicated.size() < configuredBaseDirs.size()) {
+      throw new IllegalArgumentException(
+          Property.INSTANCE_VOLUMES.getKey() + " contains duplicate volumes (" 
+ ns + ")");
+    }
+    return deduplicated;
   }
 
-  public static String[] prefix(String[] bases, String suffix) {
-    if (suffix.startsWith("/"))
-      suffix = suffix.substring(1);
-    String[] result = new String[bases.length];
-    for (int i = 0; i < bases.length; i++) {
-      if (bases[i].endsWith("/")) {
-        result[i] = bases[i] + suffix;
-      } else {
-        result[i] = bases[i] + "/" + suffix;
-      }
-    }
-    return result;
+  public static Set<String> prefix(Set<String> bases, String suffix) {
+    String actualSuffix = suffix.startsWith("/") ? suffix.substring(1) : 
suffix;
+    return bases.stream().map(base -> base + (base.endsWith("/") ? "" : "/") + 
actualSuffix)
+        .collect(Collectors.toCollection(LinkedHashSet::new));
   }
 
   /**
diff --git 
a/server/base/src/main/java/org/apache/accumulo/server/ServerConstants.java 
b/server/base/src/main/java/org/apache/accumulo/server/ServerConstants.java
index 27dc4eb..1610f98 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/ServerConstants.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/ServerConstants.java
@@ -23,6 +23,7 @@ import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Set;
 
@@ -80,33 +81,35 @@ public class ServerConstants {
       Set.of(SHORTEN_RFILE_KEYS, CRYPTO_CHANGES, DATA_VERSION);
   public static final Set<Integer> NEEDS_UPGRADE = Sets.difference(CAN_RUN, 
Set.of(DATA_VERSION));
 
-  private static String[] baseUris = null;
+  private static Set<String> baseUris = null;
 
   private static List<Pair<Path,Path>> replacementsList = null;
 
-  public static String[] getBaseUris(ServerContext context) {
+  public static Set<String> getBaseUris(ServerContext context) {
     return getBaseUris(context.getConfiguration(), context.getHadoopConf());
   }
 
   // these are functions to delay loading the Accumulo configuration unless we 
must
-  public static synchronized String[] getBaseUris(AccumuloConfiguration conf,
+  public static synchronized Set<String> getBaseUris(AccumuloConfiguration 
conf,
       Configuration hadoopConf) {
     if (baseUris == null) {
-      baseUris = checkBaseUris(conf, hadoopConf,
-          VolumeConfiguration.getVolumeUris(conf, hadoopConf), false);
+      baseUris = Collections.unmodifiableSet(checkBaseUris(conf, hadoopConf,
+          VolumeConfiguration.getVolumeUris(conf, hadoopConf), false));
     }
 
     return baseUris;
   }
 
-  public static String[] checkBaseUris(AccumuloConfiguration conf, 
Configuration hadoopConf,
-      String[] configuredBaseDirs, boolean ignore) {
+  public static Set<String> checkBaseUris(AccumuloConfiguration conf, 
Configuration hadoopConf,
+      Set<String> configuredBaseDirs, boolean ignore) {
     // all base dirs must have same instance id and data version, any dirs 
that have neither should
     // be ignored
     String firstDir = null;
     String firstIid = null;
     Integer firstVersion = null;
-    ArrayList<String> baseDirsList = new ArrayList<>();
+    // preserve order from configuration (to match user expectations a bit 
when volumes get sent to
+    // user-implemented VolumeChoosers)
+    LinkedHashSet<String> baseDirsList = new LinkedHashSet<>();
     for (String baseDir : configuredBaseDirs) {
       Path path = new Path(baseDir, INSTANCE_ID_DIR);
       String currentIid;
@@ -145,18 +148,18 @@ public class ServerConstants {
       throw new RuntimeException("None of the configured paths are 
initialized.");
     }
 
-    return baseDirsList.toArray(new String[baseDirsList.size()]);
+    return baseDirsList;
   }
 
   public static final String TABLE_DIR = "tables";
   public static final String RECOVERY_DIR = "recovery";
   public static final String WAL_DIR = "wal";
 
-  public static String[] getTablesDirs(ServerContext context) {
+  public static Set<String> getTablesDirs(ServerContext context) {
     return VolumeConfiguration.prefix(getBaseUris(context), TABLE_DIR);
   }
 
-  public static String[] getRecoveryDirs(ServerContext context) {
+  public static Set<String> getRecoveryDirs(ServerContext context) {
     return VolumeConfiguration.prefix(getBaseUris(context), RECOVERY_DIR);
   }
 
diff --git 
a/server/base/src/main/java/org/apache/accumulo/server/fs/InterfaceEvolutionWarner.java
 
b/server/base/src/main/java/org/apache/accumulo/server/fs/InterfaceEvolutionWarner.java
new file mode 100644
index 0000000..004c7c4
--- /dev/null
+++ 
b/server/base/src/main/java/org/apache/accumulo/server/fs/InterfaceEvolutionWarner.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.accumulo.server.fs;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class InterfaceEvolutionWarner {
+
+  private static final Logger LOG = 
LoggerFactory.getLogger("accumulo.api.evolution");
+  private static final ConcurrentHashMap<String,Boolean> classesWarned = new 
ConcurrentHashMap<>();
+
+  static void warnOnce(Class<?> userClass, Class<?> interfaceClass, String 
interfaceMethod,
+      String version) {
+    String userClassName = userClass.getName();
+    String interfaceSignature = interfaceClass.getName() + "#" + 
interfaceMethod;
+    // don't warn multiple times for the same user class and interface method 
signature
+    String key = userClassName + ":" + interfaceSignature;
+    if (classesWarned.putIfAbsent(key, Boolean.TRUE) == null) {
+      LOG.warn("{} must override {} by {}", userClassName, interfaceSignature, 
version);
+    }
+  }
+
+}
diff --git 
a/server/base/src/main/java/org/apache/accumulo/server/fs/PerTableVolumeChooser.java
 
b/server/base/src/main/java/org/apache/accumulo/server/fs/PerTableVolumeChooser.java
index a99d60e..784ed79 100644
--- 
a/server/base/src/main/java/org/apache/accumulo/server/fs/PerTableVolumeChooser.java
+++ 
b/server/base/src/main/java/org/apache/accumulo/server/fs/PerTableVolumeChooser.java
@@ -18,6 +18,7 @@
  */
 package org.apache.accumulo.server.fs;
 
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.accumulo.core.data.TableId;
@@ -52,14 +53,14 @@ public class PerTableVolumeChooser implements VolumeChooser 
{
       getCustomPropertySuffix(ChooserScope.DEFAULT);
 
   @Override
-  public String choose(VolumeChooserEnvironment env, String[] options)
+  public String choose(VolumeChooserEnvironment env, Set<String> options)
       throws VolumeChooserException {
     log.trace("{}.choose", getClass().getSimpleName());
     return getDelegateChooser(env).choose(env, options);
   }
 
   @Override
-  public String[] choosable(VolumeChooserEnvironment env, String[] options)
+  public Set<String> choosable(VolumeChooserEnvironment env, Set<String> 
options)
       throws VolumeChooserException {
     return getDelegateChooser(env).choosable(env, options);
   }
diff --git 
a/server/base/src/main/java/org/apache/accumulo/server/fs/PreferredVolumeChooser.java
 
b/server/base/src/main/java/org/apache/accumulo/server/fs/PreferredVolumeChooser.java
index 332207a..b246a6e 100644
--- 
a/server/base/src/main/java/org/apache/accumulo/server/fs/PreferredVolumeChooser.java
+++ 
b/server/base/src/main/java/org/apache/accumulo/server/fs/PreferredVolumeChooser.java
@@ -19,6 +19,7 @@
 package org.apache.accumulo.server.fs;
 
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.Set;
 import java.util.stream.Collectors;
 
@@ -47,7 +48,7 @@ public class PreferredVolumeChooser extends 
RandomVolumeChooser {
       getCustomPropertySuffix(ChooserScope.DEFAULT);
 
   @Override
-  public String choose(VolumeChooserEnvironment env, String[] options)
+  public String choose(VolumeChooserEnvironment env, Set<String> options)
       throws VolumeChooserException {
     log.trace("{}.choose", getClass().getSimpleName());
     // Randomly choose the volume from the preferred volumes
@@ -57,20 +58,21 @@ public class PreferredVolumeChooser extends 
RandomVolumeChooser {
   }
 
   @Override
-  public String[] choosable(VolumeChooserEnvironment env, String[] options)
+  public Set<String> choosable(VolumeChooserEnvironment env, Set<String> 
options)
       throws VolumeChooserException {
     return getPreferredVolumes(env, options);
   }
 
   // visible (not private) for testing
-  String[] getPreferredVolumes(VolumeChooserEnvironment env, String[] options) 
{
+  Set<String> getPreferredVolumes(VolumeChooserEnvironment env, Set<String> 
options) {
     if (env.getScope() == ChooserScope.TABLE) {
       return getPreferredVolumesForTable(env, options);
     }
     return getPreferredVolumesForScope(env, options);
   }
 
-  private String[] getPreferredVolumesForTable(VolumeChooserEnvironment env, 
String[] options) {
+  private Set<String> getPreferredVolumesForTable(VolumeChooserEnvironment env,
+      Set<String> options) {
     log.trace("Looking up property {} + for Table id: {}", 
TABLE_CUSTOM_SUFFIX, env.getTableId());
 
     String preferredVolumes =
@@ -86,15 +88,15 @@ public class PreferredVolumeChooser extends 
RandomVolumeChooser {
     // throw an error if volumes not specified or empty
     if (preferredVolumes == null || preferredVolumes.isEmpty()) {
       String msg = "Property " + TABLE_CUSTOM_SUFFIX + " or " + 
DEFAULT_SCOPED_PREFERRED_VOLUMES
-          + " must be a subset of " + Arrays.toString(options) + " to use the "
-          + getClass().getSimpleName();
+          + " must be a subset of " + options + " to use the " + 
getClass().getSimpleName();
       throw new VolumeChooserException(msg);
     }
 
     return parsePreferred(TABLE_CUSTOM_SUFFIX, preferredVolumes, options);
   }
 
-  private String[] getPreferredVolumesForScope(VolumeChooserEnvironment env, 
String[] options) {
+  private Set<String> getPreferredVolumesForScope(VolumeChooserEnvironment env,
+      Set<String> options) {
     ChooserScope scope = env.getScope();
     String property = getCustomPropertySuffix(scope);
     log.trace("Looking up property {} for scope: {}", property, scope);
@@ -112,8 +114,7 @@ public class PreferredVolumeChooser extends 
RandomVolumeChooser {
       // volumes
       if (preferredVolumes == null || preferredVolumes.isEmpty()) {
         String msg = "Property " + property + " or " + 
DEFAULT_SCOPED_PREFERRED_VOLUMES
-            + " must be a subset of " + Arrays.toString(options) + " to use 
the "
-            + getClass().getSimpleName();
+            + " must be a subset of " + options + " to use the " + 
getClass().getSimpleName();
         throw new VolumeChooserException(msg);
       }
 
@@ -123,7 +124,8 @@ public class PreferredVolumeChooser extends 
RandomVolumeChooser {
     return parsePreferred(property, preferredVolumes, options);
   }
 
-  private String[] parsePreferred(String property, String preferredVolumes, 
String[] options) {
+  private Set<String> parsePreferred(String property, String preferredVolumes,
+      Set<String> options) {
     log.trace("Found {} = {}", property, preferredVolumes);
 
     Set<String> preferred =
@@ -135,12 +137,11 @@ public class PreferredVolumeChooser extends 
RandomVolumeChooser {
     }
     // preferred volumes should also exist in the original options (typically, 
from
     // instance.volumes)
-    Set<String> optionsList = 
Arrays.stream(options).collect(Collectors.toSet());
-    if (!preferred.stream().allMatch(optionsList::contains)) {
-      String msg = "Some volumes in " + preferred + " are not valid volumes 
from " + optionsList;
+    if (Collections.disjoint(preferred, options)) {
+      String msg = "Some volumes in " + preferred + " are not valid volumes 
from " + options;
       throw new VolumeChooserException(msg);
     }
 
-    return preferred.toArray(new String[preferred.size()]);
+    return preferred;
   }
 }
diff --git 
a/server/base/src/main/java/org/apache/accumulo/server/fs/RandomVolumeChooser.java
 
b/server/base/src/main/java/org/apache/accumulo/server/fs/RandomVolumeChooser.java
index 7c7f848..8628e33 100644
--- 
a/server/base/src/main/java/org/apache/accumulo/server/fs/RandomVolumeChooser.java
+++ 
b/server/base/src/main/java/org/apache/accumulo/server/fs/RandomVolumeChooser.java
@@ -20,18 +20,20 @@ package org.apache.accumulo.server.fs;
 
 import java.security.SecureRandom;
 import java.util.Random;
+import java.util.Set;
 
 public class RandomVolumeChooser implements VolumeChooser {
   protected final Random random = new SecureRandom();
 
   @Override
-  public String choose(VolumeChooserEnvironment env, String[] options)
+  public String choose(VolumeChooserEnvironment env, Set<String> options)
       throws VolumeChooserException {
-    return options[random.nextInt(options.length)];
+    String[] optionsArray = options.toArray(new String[0]);
+    return optionsArray[random.nextInt(optionsArray.length)];
   }
 
   @Override
-  public String[] choosable(VolumeChooserEnvironment env, String[] options)
+  public Set<String> choosable(VolumeChooserEnvironment env, Set<String> 
options)
       throws VolumeChooserException {
     return options;
   }
diff --git 
a/server/base/src/main/java/org/apache/accumulo/server/fs/SpaceAwareVolumeChooser.java
 
b/server/base/src/main/java/org/apache/accumulo/server/fs/SpaceAwareVolumeChooser.java
index 875d484..b17c47b 100644
--- 
a/server/base/src/main/java/org/apache/accumulo/server/fs/SpaceAwareVolumeChooser.java
+++ 
b/server/base/src/main/java/org/apache/accumulo/server/fs/SpaceAwareVolumeChooser.java
@@ -19,10 +19,9 @@
 package org.apache.accumulo.server.fs;
 
 import java.io.IOException;
-import java.util.Arrays;
-import java.util.List;
 import java.util.NavigableMap;
 import java.util.Random;
+import java.util.Set;
 import java.util.TreeMap;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
@@ -48,24 +47,21 @@ public class SpaceAwareVolumeChooser extends 
PreferredVolumeChooser {
 
   // Default time to wait in ms. Defaults to 5 min
   private long defaultComputationCacheDuration = 300000;
-  private LoadingCache<List<String>,WeightedRandomCollection> choiceCache = 
null;
+  private LoadingCache<Set<String>,WeightedRandomCollection> choiceCache = 
null;
 
   private static final Logger log = 
LoggerFactory.getLogger(SpaceAwareVolumeChooser.class);
 
   @Override
-  public String choose(VolumeChooserEnvironment env, String[] options)
+  public String choose(VolumeChooserEnvironment env, Set<String> options)
       throws VolumeChooserException {
-
-    options = getPreferredVolumes(env, options);
-
     try {
-      return getCache(env).get(Arrays.asList(options)).next();
+      return getCache(env).get(getPreferredVolumes(env, options)).next();
     } catch (ExecutionException e) {
       throw new IllegalStateException("Execution exception when attempting to 
cache choice", e);
     }
   }
 
-  private synchronized LoadingCache<List<String>,WeightedRandomCollection>
+  private synchronized LoadingCache<Set<String>,WeightedRandomCollection>
       getCache(VolumeChooserEnvironment env) {
 
     if (choiceCache == null) {
@@ -78,7 +74,7 @@ public class SpaceAwareVolumeChooser extends 
PreferredVolumeChooser {
           .expireAfterWrite(computationCacheDuration, TimeUnit.MILLISECONDS)
           .build(new CacheLoader<>() {
             @Override
-            public WeightedRandomCollection load(List<String> key) {
+            public WeightedRandomCollection load(Set<String> key) {
               return new WeightedRandomCollection(key, env, random);
             }
           });
@@ -92,7 +88,7 @@ public class SpaceAwareVolumeChooser extends 
PreferredVolumeChooser {
     private final Random random;
     private double total = 0;
 
-    public WeightedRandomCollection(List<String> options, 
VolumeChooserEnvironment env,
+    public WeightedRandomCollection(Set<String> options, 
VolumeChooserEnvironment env,
         Random random) {
       this.random = random;
 
diff --git 
a/server/base/src/main/java/org/apache/accumulo/server/fs/VolumeChooser.java 
b/server/base/src/main/java/org/apache/accumulo/server/fs/VolumeChooser.java
index 0660cae..f3abd73 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/fs/VolumeChooser.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/fs/VolumeChooser.java
@@ -18,6 +18,8 @@
  */
 package org.apache.accumulo.server.fs;
 
+import java.util.Set;
+
 import org.apache.accumulo.core.conf.Property;
 import org.apache.accumulo.core.volume.Volume;
 
@@ -43,16 +45,42 @@ public interface VolumeChooser {
    * @throws VolumeChooserException
    *           if there is an error choosing (this is a RuntimeException); 
this does not preclude
    *           other RuntimeExceptions from occurring
+   * @deprecated since 2.1.0; override {@link 
#choose(VolumeChooserEnvironment, Set)} instead. This
+   *             method will be removed in 3.0
    */
-  String choose(VolumeChooserEnvironment env, String[] options) throws 
VolumeChooserException;
+  @Deprecated
+  default String choose(VolumeChooserEnvironment env, String[] options)
+      throws VolumeChooserException {
+    throw new UnsupportedOperationException("This method will be removed in 
3.0");
+  }
 
   /**
-   * Return the subset of volume options that could possibly be chosen by this 
chooser.
+   * Choose a volume from the provided options.
    *
    * @param env
    *          the server environment provided by the calling framework
    * @param options
    *          the list of volumes to choose from
+   * @return one of the options
+   * @throws VolumeChooserException
+   *           if there is an error choosing (this is a RuntimeException); 
this does not preclude
+   *           other RuntimeExceptions from occurring
+   */
+  default String choose(VolumeChooserEnvironment env, Set<String> options)
+      throws VolumeChooserException {
+    InterfaceEvolutionWarner.warnOnce(getClass(), VolumeChooser.class,
+        "choose(VolumeChooserEnvironment,Set)", "3.0");
+    return choose(env, options.toArray(new String[0]));
+  }
+
+  /**
+   * Return the subset of volumes that could possibly be chosen by this 
chooser across all
+   * invocations of {@link #choose(VolumeChooserEnvironment, Set)}.
+   *
+   * @param env
+   *          the server environment provided by the calling framework
+   * @param options
+   *          the subset of volumes to choose from
    * @return array of valid options
    * @throws VolumeChooserException
    *           if there is an error choosing (this is a RuntimeException); 
this does not preclude
@@ -60,10 +88,10 @@ public interface VolumeChooser {
    *
    * @since 2.1.0
    */
-  default String[] choosable(VolumeChooserEnvironment env, String[] options)
+  default Set<String> choosable(VolumeChooserEnvironment env, Set<String> 
options)
       throws VolumeChooserException {
-    throw new UnsupportedOperationException("This volume chooser does not 
support a new "
-        + "method added in 2.1.0.  Please let the author of the chooser 
know.");
+    // assume that all options are possible to be chosen by this chooser
+    return options;
   }
 
   class VolumeChooserException extends RuntimeException {
diff --git 
a/server/base/src/main/java/org/apache/accumulo/server/fs/VolumeManager.java 
b/server/base/src/main/java/org/apache/accumulo/server/fs/VolumeManager.java
index 407b8ba..9c0634f 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/fs/VolumeManager.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/fs/VolumeManager.java
@@ -22,6 +22,7 @@ import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.net.UnknownHostException;
 import java.util.Collection;
+import java.util.Set;
 
 import org.apache.accumulo.core.conf.AccumuloConfiguration;
 import org.apache.accumulo.core.volume.Volume;
@@ -130,7 +131,7 @@ public interface VolumeManager {
   Volume getVolumeByPath(Path path);
 
   // return the item in options that is in the same volume as source
-  Path matchingFileSystem(Path source, String[] options);
+  Path matchingFileSystem(Path source, Set<String> options);
 
   // forward to the appropriate FileSystem object
   FileStatus[] listStatus(Path path) throws IOException;
@@ -164,10 +165,10 @@ public interface VolumeManager {
   ContentSummary getContentSummary(Path dir) throws IOException;
 
   // decide on which of the given locations to create a new file
-  String choose(VolumeChooserEnvironment env, String[] options);
+  String choose(VolumeChooserEnvironment env, Set<String> options);
 
   // return all valid locations to create a new file
-  String[] choosable(VolumeChooserEnvironment env, String[] options);
+  Set<String> choosable(VolumeChooserEnvironment env, Set<String> options);
 
   // are sync and flush supported for the given path
   boolean canSyncAndFlush(Path path);
diff --git 
a/server/base/src/main/java/org/apache/accumulo/server/fs/VolumeManagerImpl.java
 
b/server/base/src/main/java/org/apache/accumulo/server/fs/VolumeManagerImpl.java
index c320c9b..2e3b31e 100644
--- 
a/server/base/src/main/java/org/apache/accumulo/server/fs/VolumeManagerImpl.java
+++ 
b/server/base/src/main/java/org/apache/accumulo/server/fs/VolumeManagerImpl.java
@@ -30,6 +30,7 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Set;
 
 import org.apache.accumulo.core.conf.AccumuloConfiguration;
 import org.apache.accumulo.core.conf.DefaultConfiguration;
@@ -38,7 +39,6 @@ import org.apache.accumulo.core.volume.NonConfiguredVolume;
 import org.apache.accumulo.core.volume.Volume;
 import org.apache.accumulo.core.volume.VolumeConfiguration;
 import org.apache.accumulo.server.fs.VolumeChooser.VolumeChooserException;
-import org.apache.commons.lang3.ArrayUtils;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.ContentSummary;
 import org.apache.hadoop.fs.CreateFlag;
@@ -385,10 +385,10 @@ public class VolumeManagerImpl implements VolumeManager {
   }
 
   @Override
-  public Path matchingFileSystem(Path source, String[] options) {
+  public Path matchingFileSystem(Path source, Set<String> options) {
     try {
       if (ViewFSUtils.isViewFS(source, hadoopConf)) {
-        return ViewFSUtils.matchingFileSystem(source, options, hadoopConf);
+        return ViewFSUtils.matchingFileSystem(source, options.toArray(new 
String[0]), hadoopConf);
       }
     } catch (IOException e) {
       throw new RuntimeException(e);
@@ -413,11 +413,10 @@ public class VolumeManagerImpl implements VolumeManager {
   }
 
   @Override
-  public String choose(VolumeChooserEnvironment env, String[] options) {
+  public String choose(VolumeChooserEnvironment env, Set<String> options) {
     final String choice;
     choice = chooser.choose(env, options);
-
-    if (!(ArrayUtils.contains(options, choice))) {
+    if (!options.contains(choice)) {
       String msg = "The configured volume chooser, '" + chooser.getClass()
           + "', or one of its delegates returned a volume not in the set of 
options provided";
       throw new VolumeChooserException(msg);
@@ -427,11 +426,11 @@ public class VolumeManagerImpl implements VolumeManager {
   }
 
   @Override
-  public String[] choosable(VolumeChooserEnvironment env, String[] options) {
-    final String[] choices = chooser.choosable(env, options);
+  public Set<String> choosable(VolumeChooserEnvironment env, Set<String> 
options) {
+    final Set<String> choices = chooser.choosable(env, options);
 
     for (String choice : choices) {
-      if (!(ArrayUtils.contains(options, choice))) {
+      if (!options.contains(choice)) {
         String msg = "The configured volume chooser, '" + chooser.getClass()
             + "', or one of its delegates returned a volume not in the set of 
options provided";
         throw new VolumeChooserException(msg);
diff --git 
a/server/base/src/main/java/org/apache/accumulo/server/init/Initialize.java 
b/server/base/src/main/java/org/apache/accumulo/server/init/Initialize.java
index 0b180f5..1dc0e74 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/init/Initialize.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/init/Initialize.java
@@ -361,7 +361,7 @@ public class Initialize implements KeywordExecutable {
 
     UUID uuid = UUID.randomUUID();
     // the actual disk locations of the root table and tablets
-    String[] configuredVolumes = VolumeConfiguration.getVolumeUris(siteConfig, 
hadoopConf);
+    Set<String> configuredVolumes = 
VolumeConfiguration.getVolumeUris(siteConfig, hadoopConf);
     String instanceName = 
instanceNamePath.substring(getInstanceNamePrefix().length());
     ServerContext serverContext = new ServerContext(siteConfig, instanceName, 
uuid.toString());
     VolumeChooserEnvironment chooserEnv =
@@ -483,7 +483,7 @@ public class Initialize implements KeywordExecutable {
     }
   }
 
-  private static void initDirs(VolumeManager fs, UUID uuid, String[] baseDirs, 
boolean print)
+  private static void initDirs(VolumeManager fs, UUID uuid, Set<String> 
baseDirs, boolean print)
       throws IOException {
     for (String baseDir : baseDirs) {
       fs.mkdirs(new Path(new Path(baseDir, ServerConstants.VERSION_DIR),
@@ -892,14 +892,13 @@ public class Initialize implements KeywordExecutable {
   private static void addVolumes(VolumeManager fs, SiteConfiguration 
siteConfig,
       Configuration hadoopConf) throws IOException {
 
-    String[] volumeURIs = VolumeConfiguration.getVolumeUris(siteConfig, 
hadoopConf);
+    Set<String> volumeURIs = VolumeConfiguration.getVolumeUris(siteConfig, 
hadoopConf);
 
-    HashSet<String> initializedDirs = new HashSet<>();
-    initializedDirs.addAll(
-        Arrays.asList(ServerConstants.checkBaseUris(siteConfig, hadoopConf, 
volumeURIs, true)));
+    Set<String> initializedDirs =
+        ServerConstants.checkBaseUris(siteConfig, hadoopConf, volumeURIs, 
true);
 
     HashSet<String> uinitializedDirs = new HashSet<>();
-    uinitializedDirs.addAll(Arrays.asList(volumeURIs));
+    uinitializedDirs.addAll(volumeURIs);
     uinitializedDirs.removeAll(initializedDirs);
 
     Path aBasePath = new Path(initializedDirs.iterator().next());
@@ -925,7 +924,7 @@ public class Initialize implements KeywordExecutable {
           + ServerUtil.getAccumuloPersistentVersion(fs));
     }
 
-    initDirs(fs, uuid, uinitializedDirs.toArray(new 
String[uinitializedDirs.size()]), true);
+    initDirs(fs, uuid, uinitializedDirs, true);
   }
 
   static class Opts extends Help {
diff --git 
a/server/base/src/main/java/org/apache/accumulo/server/util/ZooKeeperMain.java 
b/server/base/src/main/java/org/apache/accumulo/server/util/ZooKeeperMain.java
index d462657..701e6d6 100644
--- 
a/server/base/src/main/java/org/apache/accumulo/server/util/ZooKeeperMain.java
+++ 
b/server/base/src/main/java/org/apache/accumulo/server/util/ZooKeeperMain.java
@@ -68,7 +68,7 @@ public class ZooKeeperMain implements KeywordExecutable {
     opts.parseArgs(ZooKeeperMain.class.getName(), args);
     try (var context = new ServerContext(SiteConfiguration.auto())) {
       FileSystem fs = 
context.getVolumeManager().getDefaultVolume().getFileSystem();
-      String baseDir = ServerConstants.getBaseUris(context)[0];
+      String baseDir = ServerConstants.getBaseUris(context).iterator().next();
       System.out.println("Using " + fs.makeQualified(new Path(baseDir + 
"/instance_id"))
           + " to lookup accumulo instance");
       if (opts.servers == null) {
diff --git 
a/server/base/src/main/java/org/apache/accumulo/server/util/ZooZap.java 
b/server/base/src/main/java/org/apache/accumulo/server/util/ZooZap.java
index 280e8d8..4adaa6d 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/util/ZooZap.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/util/ZooZap.java
@@ -75,7 +75,7 @@ public class ZooZap {
       SecurityUtil.serverLogin(siteConf);
     }
 
-    String volDir = VolumeConfiguration.getVolumeUris(siteConf, hadoopConf)[0];
+    String volDir = VolumeConfiguration.getVolumeUris(siteConf, 
hadoopConf).iterator().next();
     Path instanceDir = new Path(volDir, "instance_id");
     String iid = VolumeManager.getInstanceIDFromHdfs(instanceDir, siteConf, 
hadoopConf);
     ZooReaderWriter zoo = new ZooReaderWriter(siteConf);
diff --git 
a/server/base/src/test/java/org/apache/accumulo/server/ServerConstantsTest.java 
b/server/base/src/test/java/org/apache/accumulo/server/ServerConstantsTest.java
index 3e8e22b..fe517bd 100644
--- 
a/server/base/src/test/java/org/apache/accumulo/server/ServerConstantsTest.java
+++ 
b/server/base/src/test/java/org/apache/accumulo/server/ServerConstantsTest.java
@@ -23,10 +23,12 @@ import static org.junit.Assert.fail;
 
 import java.io.File;
 import java.io.IOException;
-import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Set;
 import java.util.UUID;
+import java.util.stream.Collectors;
 
 import org.apache.accumulo.core.conf.AccumuloConfiguration;
 import org.apache.accumulo.core.conf.DefaultConfiguration;
@@ -75,50 +77,45 @@ public class ServerConstantsTest {
         Arrays.asList(ServerConstants.DATA_VERSION, 
ServerConstants.DATA_VERSION, null)));
   }
 
-  private void verifyAllPass(ArrayList<String> paths) {
-    assertEquals(paths, Arrays.asList(ServerConstants.checkBaseUris(conf, 
hadoopConf,
-        paths.toArray(new String[paths.size()]), true)));
-    assertEquals(paths, Arrays.asList(ServerConstants.checkBaseUris(conf, 
hadoopConf,
-        paths.toArray(new String[paths.size()]), false)));
+  private void verifyAllPass(Set<String> paths) {
+    assertEquals(paths, ServerConstants.checkBaseUris(conf, hadoopConf, paths, 
true));
+    assertEquals(paths, ServerConstants.checkBaseUris(conf, hadoopConf, paths, 
false));
   }
 
-  private void verifySomePass(ArrayList<String> paths) {
-    assertEquals(paths.subList(0, 2), 
Arrays.asList(ServerConstants.checkBaseUris(conf, hadoopConf,
-        paths.toArray(new String[paths.size()]), true)));
+  private void verifySomePass(Set<String> paths) {
+    Set<String> subset = paths.stream().limit(2).collect(Collectors.toSet());
+    assertEquals(subset, ServerConstants.checkBaseUris(conf, hadoopConf, 
paths, true));
     try {
-      ServerConstants.checkBaseUris(conf, hadoopConf, paths.toArray(new 
String[paths.size()]),
-          false);
+      ServerConstants.checkBaseUris(conf, hadoopConf, paths, false);
       fail();
     } catch (Exception e) {
       // ignored
     }
   }
 
-  private void verifyError(ArrayList<String> paths) {
+  private void verifyError(Set<String> paths) {
     try {
-      ServerConstants.checkBaseUris(conf, hadoopConf, paths.toArray(new 
String[paths.size()]),
-          true);
+      ServerConstants.checkBaseUris(conf, hadoopConf, paths, true);
       fail();
     } catch (Exception e) {
       // ignored
     }
 
     try {
-      ServerConstants.checkBaseUris(conf, hadoopConf, paths.toArray(new 
String[paths.size()]),
-          false);
+      ServerConstants.checkBaseUris(conf, hadoopConf, paths, false);
       fail();
     } catch (Exception e) {
       // ignored
     }
   }
 
-  private ArrayList<String> init(File newFile, List<String> uuids, 
List<Integer> dataVersions)
+  private Set<String> init(File newFile, List<String> uuids, List<Integer> 
dataVersions)
       throws IllegalArgumentException, IOException {
     String base = newFile.toURI().toString();
 
     LocalFileSystem fs = FileSystem.getLocal(new Configuration());
 
-    ArrayList<String> accumuloPaths = new ArrayList<>();
+    LinkedHashSet<String> accumuloPaths = new LinkedHashSet<>();
 
     for (int i = 0; i < uuids.size(); i++) {
       String volume = "v" + i;
diff --git 
a/server/base/src/test/java/org/apache/accumulo/server/fs/PreferredVolumeChooserTest.java
 
b/server/base/src/test/java/org/apache/accumulo/server/fs/PreferredVolumeChooserTest.java
index f1b1364..1167af9 100644
--- 
a/server/base/src/test/java/org/apache/accumulo/server/fs/PreferredVolumeChooserTest.java
+++ 
b/server/base/src/test/java/org/apache/accumulo/server/fs/PreferredVolumeChooserTest.java
@@ -23,10 +23,10 @@ import static org.easymock.EasyMock.createStrictMock;
 import static org.easymock.EasyMock.expect;
 import static org.easymock.EasyMock.replay;
 import static org.easymock.EasyMock.verify;
-import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 
-import java.util.Arrays;
+import java.util.Set;
 
 import org.apache.accumulo.core.data.TableId;
 import org.apache.accumulo.core.spi.common.ServiceEnvironment;
@@ -47,7 +47,7 @@ public class PreferredVolumeChooserTest {
     return "volume.preferred." + scope.name().toLowerCase();
   }
 
-  private static final String[] ALL_OPTIONS = {"1", "2", "3"};
+  private static final Set<String> ALL_OPTIONS = Set.of("1", "2", "3");
 
   private ServiceEnvironment serviceEnv;
   private Configuration tableConf;
@@ -74,7 +74,7 @@ public class PreferredVolumeChooserTest {
     verify(serviceEnv, tableConf, systemConf);
   }
 
-  private String[] chooseForTable() {
+  private Set<String> chooseForTable() {
     VolumeChooserEnvironment env =
         new VolumeChooserEnvironmentImpl(TableId.of("testTable"), null, null) {
           @Override
@@ -85,7 +85,7 @@ public class PreferredVolumeChooserTest {
     return chooser.getPreferredVolumes(env, ALL_OPTIONS);
   }
 
-  private String[] choose(ChooserScope scope) {
+  private Set<String> choose(ChooserScope scope) {
     VolumeChooserEnvironment env = new VolumeChooserEnvironmentImpl(scope, 
null) {
       @Override
       public ServiceEnvironment getServiceEnv() {
@@ -99,10 +99,7 @@ public class PreferredVolumeChooserTest {
   public void testTableScopeUsingTableProperty() {
     expect(tableConf.getTableCustom(TABLE_CUSTOM_SUFFIX)).andReturn("2,1");
     replay(serviceEnv, tableConf, systemConf);
-
-    String[] volumes = chooseForTable();
-    Arrays.sort(volumes);
-    assertArrayEquals(new String[] {"1", "2"}, volumes);
+    assertEquals(Set.of("1", "2"), chooseForTable());
   }
 
   @Test
@@ -111,10 +108,7 @@ public class PreferredVolumeChooserTest {
     
expect(systemConf.getCustom(getCustomPropertySuffix(ChooserScope.DEFAULT))).andReturn("3,2")
         .once();
     replay(serviceEnv, tableConf, systemConf);
-
-    String[] volumes = chooseForTable();
-    Arrays.sort(volumes);
-    assertArrayEquals(new String[] {"2", "3"}, volumes);
+    assertEquals(Set.of("2", "3"), chooseForTable());
   }
 
   @Test
@@ -156,10 +150,7 @@ public class PreferredVolumeChooserTest {
     
expect(systemConf.getCustom(getCustomPropertySuffix(ChooserScope.LOGGER))).andReturn("2,1")
         .once();
     replay(serviceEnv, tableConf, systemConf);
-
-    String[] volumes = choose(ChooserScope.LOGGER);
-    Arrays.sort(volumes);
-    assertArrayEquals(new String[] {"1", "2"}, volumes);
+    assertEquals(Set.of("1", "2"), choose(ChooserScope.LOGGER));
   }
 
   @Test
@@ -169,10 +160,7 @@ public class PreferredVolumeChooserTest {
     
expect(systemConf.getCustom(getCustomPropertySuffix(ChooserScope.DEFAULT))).andReturn("3,2")
         .once();
     replay(serviceEnv, tableConf, systemConf);
-
-    String[] volumes = choose(ChooserScope.LOGGER);
-    Arrays.sort(volumes);
-    assertArrayEquals(new String[] {"2", "3"}, volumes);
+    assertEquals(Set.of("2", "3"), choose(ChooserScope.LOGGER));
   }
 
   @Test
@@ -217,10 +205,7 @@ public class PreferredVolumeChooserTest {
     
expect(systemConf.getCustom(getCustomPropertySuffix(ChooserScope.INIT))).andReturn("2,1")
         .once();
     replay(serviceEnv, tableConf, systemConf);
-
-    String[] volumes = choose(ChooserScope.INIT);
-    Arrays.sort(volumes);
-    assertArrayEquals(new String[] {"1", "2"}, volumes);
+    assertEquals(Set.of("1", "2"), choose(ChooserScope.INIT));
   }
 
   @Test
@@ -229,10 +214,7 @@ public class PreferredVolumeChooserTest {
     
expect(systemConf.getCustom(getCustomPropertySuffix(ChooserScope.DEFAULT))).andReturn("3,2")
         .once();
     replay(serviceEnv, tableConf, systemConf);
-
-    String[] volumes = choose(ChooserScope.INIT);
-    Arrays.sort(volumes);
-    assertArrayEquals(new String[] {"2", "3"}, volumes);
+    assertEquals(Set.of("2", "3"), choose(ChooserScope.INIT));
   }
 
 }
diff --git 
a/server/base/src/test/java/org/apache/accumulo/server/fs/SpaceAwareVolumeChooserTest.java
 
b/server/base/src/test/java/org/apache/accumulo/server/fs/SpaceAwareVolumeChooserTest.java
index 7943b3a..3b789a3 100644
--- 
a/server/base/src/test/java/org/apache/accumulo/server/fs/SpaceAwareVolumeChooserTest.java
+++ 
b/server/base/src/test/java/org/apache/accumulo/server/fs/SpaceAwareVolumeChooserTest.java
@@ -21,6 +21,7 @@ package org.apache.accumulo.server.fs;
 import static org.junit.Assert.assertEquals;
 
 import java.io.IOException;
+import java.util.Set;
 
 import org.apache.accumulo.core.spi.common.ServiceEnvironment;
 import org.apache.accumulo.core.spi.common.ServiceEnvironment.Configuration;
@@ -50,7 +51,7 @@ public class SpaceAwareVolumeChooserTest {
   String volumeTwo = "hdfs://nn2:8020/applications/accumulo/tables";
 
   // Different volumes with different paths
-  String[] tableDirs = {volumeOne, volumeTwo};
+  Set<String> tableDirs = Set.of(volumeOne, volumeTwo);
 
   int vol1Count = 0;
   int vol2Count = 0;
diff --git 
a/server/base/src/test/java/org/apache/accumulo/server/fs/VolumeManagerImplTest.java
 
b/server/base/src/test/java/org/apache/accumulo/server/fs/VolumeManagerImplTest.java
index 32d51856..db93f0f 100644
--- 
a/server/base/src/test/java/org/apache/accumulo/server/fs/VolumeManagerImplTest.java
+++ 
b/server/base/src/test/java/org/apache/accumulo/server/fs/VolumeManagerImplTest.java
@@ -22,6 +22,7 @@ import static org.junit.Assert.assertTrue;
 
 import java.util.Arrays;
 import java.util.List;
+import java.util.Set;
 
 import org.apache.accumulo.core.conf.ConfigurationCopy;
 import org.apache.accumulo.core.conf.Property;
@@ -67,13 +68,13 @@ public class VolumeManagerImplTest {
 
   public static class WrongVolumeChooser implements VolumeChooser {
     @Override
-    public String choose(VolumeChooserEnvironment env, String[] options) {
+    public String choose(VolumeChooserEnvironment env, Set<String> options) {
       return "file://totally-not-given/";
     }
 
     @Override
-    public String[] choosable(VolumeChooserEnvironment env, String[] options) {
-      return new String[] {"file://totally-not-given"};
+    public Set<String> choosable(VolumeChooserEnvironment env, Set<String> 
options) {
+      return Set.of("file://totally-not-given");
     }
   }
 
@@ -83,16 +84,16 @@ public class VolumeManagerImplTest {
   // Expected to throw a runtime exception when the WrongVolumeChooser picks 
an invalid volume.
   @Test
   public void chooseFromOptions() throws Exception {
-    List<String> volumes = Arrays.asList("file://one/", "file://two/", 
"file://three/");
+    Set<String> volumes = Set.of("file://one/", "file://two/", 
"file://three/");
     ConfigurationCopy conf = new ConfigurationCopy();
-    conf.set(INSTANCE_DFS_URI, volumes.get(0));
+    conf.set(INSTANCE_DFS_URI, volumes.iterator().next());
     conf.set(Property.INSTANCE_VOLUMES, String.join(",", volumes));
     conf.set(Property.GENERAL_VOLUME_CHOOSER, 
WrongVolumeChooser.class.getName());
     thrown.expect(RuntimeException.class);
     VolumeManager vm = VolumeManagerImpl.get(conf, hadoopConf);
     VolumeChooserEnvironment chooserEnv =
         new VolumeChooserEnvironmentImpl(TableId.of("sometable"), null, null);
-    String choice = vm.choose(chooserEnv, volumes.toArray(new String[0]));
+    String choice = vm.choose(chooserEnv, volumes);
     assertTrue("shouldn't see invalid options from misbehaving chooser.", 
volumes.contains(choice));
   }
 }
diff --git 
a/server/master/src/main/java/org/apache/accumulo/master/tableOps/tableImport/CreateImportDir.java
 
b/server/master/src/main/java/org/apache/accumulo/master/tableOps/tableImport/CreateImportDir.java
index 8f23c0e..a6ae987 100644
--- 
a/server/master/src/main/java/org/apache/accumulo/master/tableOps/tableImport/CreateImportDir.java
+++ 
b/server/master/src/main/java/org/apache/accumulo/master/tableOps/tableImport/CreateImportDir.java
@@ -19,7 +19,7 @@
 package org.apache.accumulo.master.tableOps.tableImport;
 
 import java.io.IOException;
-import java.util.Arrays;
+import java.util.Set;
 
 import org.apache.accumulo.core.Constants;
 import org.apache.accumulo.fate.Repo;
@@ -47,10 +47,9 @@ class CreateImportDir extends MasterRepo {
     UniqueNameAllocator namer = master.getContext().getUniqueNameAllocator();
 
     Path exportDir = new Path(tableInfo.exportDir);
-    String[] tableDirs = ServerConstants.getTablesDirs(master.getContext());
+    Set<String> tableDirs = ServerConstants.getTablesDirs(master.getContext());
 
-    log.info("Looking for matching filesystem for " + exportDir + " from 
options "
-        + Arrays.toString(tableDirs));
+    log.info("Looking for matching filesystem for {} from options {}", 
exportDir, tableDirs);
     Path base = master.getFileSystem().matchingFileSystem(exportDir, 
tableDirs);
     if (base == null) {
       throw new IOException(tableInfo.exportDir + " is not in a volume 
configured for Accumulo");
diff --git 
a/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServer.java 
b/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServer.java
index c9a27ce..a097399 100644
--- a/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServer.java
+++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServer.java
@@ -3006,11 +3006,11 @@ public class TabletServer extends AbstractServer {
   private void checkWalCanSync(ServerContext context) {
     VolumeChooserEnvironment chooserEnv =
         new 
VolumeChooserEnvironmentImpl(VolumeChooserEnvironment.ChooserScope.LOGGER, 
context);
-    String[] prefixes;
+    Set<String> prefixes;
     var options = ServerConstants.getBaseUris(context);
     try {
       prefixes = fs.choosable(chooserEnv, options);
-    } catch (Exception e) {
+    } catch (RuntimeException e) {
       log.warn("Unable to determine if WAL directories ({}) support sync or 
flush. "
           + "Data loss may occur.", Arrays.asList(options), e);
       return;
diff --git 
a/server/tserver/src/main/java/org/apache/accumulo/tserver/log/DfsLogger.java 
b/server/tserver/src/main/java/org/apache/accumulo/tserver/log/DfsLogger.java
index 4b0bc82..07c04cd 100644
--- 
a/server/tserver/src/main/java/org/apache/accumulo/tserver/log/DfsLogger.java
+++ 
b/server/tserver/src/main/java/org/apache/accumulo/tserver/log/DfsLogger.java
@@ -63,7 +63,6 @@ import org.apache.accumulo.core.util.Pair;
 import org.apache.accumulo.fate.util.LoggingRunnable;
 import org.apache.accumulo.server.ServerConstants;
 import org.apache.accumulo.server.ServerContext;
-import org.apache.accumulo.server.fs.VolumeChooserEnvironment;
 import org.apache.accumulo.server.fs.VolumeChooserEnvironment.ChooserScope;
 import org.apache.accumulo.server.fs.VolumeChooserEnvironmentImpl;
 import org.apache.accumulo.server.fs.VolumeManager;
@@ -424,8 +423,7 @@ public class DfsLogger implements Comparable<DfsLogger> {
     log.debug("DfsLogger.open() begin");
     VolumeManager fs = conf.getFileSystem();
 
-    VolumeChooserEnvironment chooserEnv =
-        new VolumeChooserEnvironmentImpl(ChooserScope.LOGGER, context);
+    var chooserEnv = new VolumeChooserEnvironmentImpl(ChooserScope.LOGGER, 
context);
     logPath = fs.choose(chooserEnv, ServerConstants.getBaseUris(context)) + 
Path.SEPARATOR
         + ServerConstants.WAL_DIR + Path.SEPARATOR + logger + Path.SEPARATOR + 
filename;
 
diff --git 
a/server/tserver/src/test/java/org/apache/accumulo/tserver/TabletServerSyncCheckTest.java
 
b/server/tserver/src/test/java/org/apache/accumulo/tserver/TabletServerSyncCheckTest.java
index ba1d1e4..b47d817 100644
--- 
a/server/tserver/src/test/java/org/apache/accumulo/tserver/TabletServerSyncCheckTest.java
+++ 
b/server/tserver/src/test/java/org/apache/accumulo/tserver/TabletServerSyncCheckTest.java
@@ -20,6 +20,7 @@ package org.apache.accumulo.tserver;
 
 import java.util.Collections;
 import java.util.Map;
+import java.util.Set;
 
 import org.apache.accumulo.core.conf.ConfigurationCopy;
 import org.apache.accumulo.core.volume.Volume;
@@ -133,7 +134,7 @@ public class TabletServerSyncCheckTest {
     }
 
     @Override
-    public Path matchingFileSystem(Path source, String[] options) {
+    public Path matchingFileSystem(Path source, Set<String> options) {
       return null;
     }
 
@@ -183,7 +184,7 @@ public class TabletServerSyncCheckTest {
     }
 
     @Override
-    public String choose(VolumeChooserEnvironment env, String[] options) {
+    public String choose(VolumeChooserEnvironment env, Set<String> options) {
       return null;
     }
 
diff --git a/test/src/main/java/org/apache/accumulo/test/FairVolumeChooser.java 
b/test/src/main/java/org/apache/accumulo/test/FairVolumeChooser.java
index 591166d..0fa4c27 100644
--- a/test/src/main/java/org/apache/accumulo/test/FairVolumeChooser.java
+++ b/test/src/main/java/org/apache/accumulo/test/FairVolumeChooser.java
@@ -18,6 +18,7 @@
  */
 package org.apache.accumulo.test;
 
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.accumulo.server.fs.VolumeChooser;
@@ -32,25 +33,26 @@ public class FairVolumeChooser implements VolumeChooser {
       new ConcurrentHashMap<>();
 
   @Override
-  public String choose(VolumeChooserEnvironment env, String[] options) {
+  public String choose(VolumeChooserEnvironment env, Set<String> options) {
     int currentChoice;
-    Integer lastChoice = optionLengthToLastChoice.get(options.length);
+    String[] optionsArray = options.toArray(new String[0]);
+    Integer lastChoice = optionLengthToLastChoice.get(optionsArray.length);
     if (lastChoice == null) {
       currentChoice = 0;
     } else {
       currentChoice = lastChoice + 1;
-      if (currentChoice >= options.length) {
+      if (currentChoice >= optionsArray.length) {
         currentChoice = 0;
       }
     }
 
-    optionLengthToLastChoice.put(options.length, currentChoice);
+    optionLengthToLastChoice.put(optionsArray.length, currentChoice);
 
-    return options[currentChoice];
+    return optionsArray[currentChoice];
   }
 
   @Override
-  public String[] choosable(VolumeChooserEnvironment env, String[] options) {
+  public Set<String> choosable(VolumeChooserEnvironment env, Set<String> 
options) {
     return options;
   }
 }
diff --git 
a/test/src/main/java/org/apache/accumulo/test/functional/SplitRecoveryIT.java 
b/test/src/main/java/org/apache/accumulo/test/functional/SplitRecoveryIT.java
index 83b53e8..c0760fa 100644
--- 
a/test/src/main/java/org/apache/accumulo/test/functional/SplitRecoveryIT.java
+++ 
b/test/src/main/java/org/apache/accumulo/test/functional/SplitRecoveryIT.java
@@ -152,8 +152,8 @@ public class SplitRecoveryIT extends ConfigurableMacBase {
       KeyExtent extent = extents[i];
 
       String dirName = "dir_" + i;
-      String tdir =
-          ServerConstants.getTablesDirs(context)[0] + "/" + 
extent.getTableId() + "/" + dirName;
+      String tdir = ServerConstants.getTablesDirs(context).iterator().next() + 
"/"
+          + extent.getTableId() + "/" + dirName;
       MetadataTableUtil.addTablet(extent, dirName, context, TimeType.LOGICAL, 
zl);
       SortedMap<TabletFile,DataFileValue> mapFiles = new TreeMap<>();
       mapFiles.put(new TabletFile(new Path(tdir + "/" + RFile.EXTENSION + 
"_000_000")),

Reply via email to