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

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


The following commit(s) were added to refs/heads/main by this push:
     new c7b9c3dd4d Add multi-range Tablet info API (#6027)
c7b9c3dd4d is described below

commit c7b9c3dd4d5057a44302893f0a4afaff88619b72
Author: Dom G. <[email protected]>
AuthorDate: Mon Dec 22 13:52:55 2025 -0500

    Add multi-range Tablet info API (#6027)
    
    * Add multi-range Tablet info API to table ops and balancer
    * centralize tablet info retrieval in new class TabletInformationCollector
---
 .../core/client/admin/TableOperations.java         |  13 +-
 .../core/client/admin/TabletInformation.java       |   4 +-
 .../core/clientImpl/TableOperationsImpl.java       |  66 ++--------
 .../clientImpl/TabletInformationCollector.java     | 135 +++++++++++++++++++++
 .../core/spi/balancer/BalancerEnvironment.java     |  16 ++-
 .../manager/balancer/BalancerEnvironmentImpl.java  |  14 +++
 .../accumulo/monitor/next/InformationFetcher.java  |   4 +-
 .../shell/commands/GetAvailabilityCommand.java     |  15 ++-
 .../shell/commands/ListTabletsCommand.java         |   6 +-
 .../shell/commands/ListTabletsCommandTest.java     |   4 +-
 .../apache/accumulo/test/ComprehensiveITBase.java  |   2 +-
 .../test/ComprehensiveTableOperationsIT.java       |   4 +-
 .../org/apache/accumulo/test/ImportExportIT.java   |   7 +-
 .../apache/accumulo/test/TableOperationsIT.java    | 129 +++++++++++++++-----
 .../accumulo/test/ample/metadata/TestAmple.java    |   5 +-
 .../test/compaction/ExternalCompaction_1_IT.java   |   4 +-
 .../apache/accumulo/test/fate/FateTestUtil.java    |   7 +-
 .../test/functional/AddSplitIT_SimpleSuite.java    |  17 +--
 .../apache/accumulo/test/functional/BulkNewIT.java |   4 +-
 .../accumulo/test/functional/SplitMillionIT.java   |   3 +-
 .../test/functional/TabletAvailabilityIT.java      |   3 +-
 21 files changed, 335 insertions(+), 127 deletions(-)

diff --git 
a/core/src/main/java/org/apache/accumulo/core/client/admin/TableOperations.java 
b/core/src/main/java/org/apache/accumulo/core/client/admin/TableOperations.java
index 147383df11..5ab6a89e7c 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/client/admin/TableOperations.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/client/admin/TableOperations.java
@@ -1079,14 +1079,19 @@ public interface TableOperations {
   }
 
   /**
+   * @param ranges the row ranges of tablets to scan. Ranges can overlap and 
an attempt will be made
+   *        to merge this list. An empty list returns an empty stream; use
+   *        {@code List.of(RowRange.all())} to scan all tablets.
    * @param fields can optionally narrow the data retrieved per tablet, which 
can speed up streaming
    *        over tablets. If this list is empty then all fields are fetched.
-   * @return a stream of tablet information for tablets that fall in the 
specified range. The stream
-   *         may be backed by a scanner, so it's best to close the stream.
+   * @return a stream of tablet information for tablets that fall in the 
specified ranges. The
+   *         stream may be backed by a scanner, so it's best to close the 
stream. The stream has no
+   *         defined ordering.
    * @since 4.0.0
    */
-  default Stream<TabletInformation> getTabletInformation(final String 
tableName, final Range range,
-      TabletInformation.Field... fields) throws TableNotFoundException {
+  default Stream<TabletInformation> getTabletInformation(final String 
tableName,
+      final List<RowRange> ranges, TabletInformation.Field... fields)
+      throws TableNotFoundException {
     throw new UnsupportedOperationException();
   }
 
diff --git 
a/core/src/main/java/org/apache/accumulo/core/client/admin/TabletInformation.java
 
b/core/src/main/java/org/apache/accumulo/core/client/admin/TabletInformation.java
index adf0427231..7694a36200 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/client/admin/TabletInformation.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/client/admin/TabletInformation.java
@@ -18,9 +18,9 @@
  */
 package org.apache.accumulo.core.client.admin;
 
+import java.util.List;
 import java.util.Optional;
 
-import org.apache.accumulo.core.data.Range;
 import org.apache.accumulo.core.data.TabletId;
 
 /**
@@ -30,7 +30,7 @@ public interface TabletInformation {
 
   /**
    * Used to limit what information is obtained per tablet when calling
-   * {@link TableOperations#getTabletInformation(String, Range, Field...)}
+   * {@link TableOperations#getTabletInformation(String, List, Field...)}
    *
    * @since 4.0.0
    */
diff --git 
a/core/src/main/java/org/apache/accumulo/core/clientImpl/TableOperationsImpl.java
 
b/core/src/main/java/org/apache/accumulo/core/clientImpl/TableOperationsImpl.java
index a326f2336a..11a07f02d7 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/clientImpl/TableOperationsImpl.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/clientImpl/TableOperationsImpl.java
@@ -26,17 +26,11 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static java.util.concurrent.TimeUnit.SECONDS;
 import static java.util.stream.Collectors.toSet;
 import static 
org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.AVAILABILITY;
-import static 
org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.DIR;
 import static 
org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.ECOMP;
-import static 
org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.FILES;
 import static 
org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.HOSTING_REQUESTED;
-import static 
org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.LAST;
 import static 
org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.LOCATION;
-import static 
org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.LOGS;
-import static 
org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.MERGEABILITY;
 import static 
org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.OPID;
 import static 
org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.PREV_ROW;
-import static 
org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.SUSPEND;
 import static 
org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.TIME;
 import static org.apache.accumulo.core.util.LazySingletons.RANDOM;
 import static org.apache.accumulo.core.util.Validators.EXISTING_TABLE_NAME;
@@ -128,8 +122,6 @@ import org.apache.accumulo.core.conf.AccumuloConfiguration;
 import org.apache.accumulo.core.conf.ConfigurationCopy;
 import org.apache.accumulo.core.conf.Property;
 import org.apache.accumulo.core.data.ByteSequence;
-import org.apache.accumulo.core.data.Key;
-import org.apache.accumulo.core.data.PartialKey;
 import org.apache.accumulo.core.data.Range;
 import org.apache.accumulo.core.data.RowRange;
 import org.apache.accumulo.core.data.TableId;
@@ -151,8 +143,6 @@ import org.apache.accumulo.core.manager.thrift.TFateId;
 import org.apache.accumulo.core.manager.thrift.TFateInstanceType;
 import org.apache.accumulo.core.manager.thrift.TFateOperation;
 import org.apache.accumulo.core.metadata.SystemTables;
-import org.apache.accumulo.core.metadata.TServerInstance;
-import org.apache.accumulo.core.metadata.TabletState;
 import org.apache.accumulo.core.metadata.schema.TabletDeletedException;
 import org.apache.accumulo.core.metadata.schema.TabletMetadata;
 import org.apache.accumulo.core.metadata.schema.TabletMetadata.Location;
@@ -186,7 +176,6 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Joiner;
 import com.google.common.base.Preconditions;
-import com.google.common.base.Suppliers;
 
 public class TableOperationsImpl extends TableOperationsHelper {
 
@@ -2255,57 +2244,18 @@ public class TableOperationsImpl extends 
TableOperationsHelper {
   }
 
   @Override
-  public Stream<TabletInformation> getTabletInformation(final String 
tableName, final Range range,
-      TabletInformation.Field... fields) throws TableNotFoundException {
+  public Stream<TabletInformation> getTabletInformation(final String tableName,
+      final List<RowRange> ranges, TabletInformation.Field... fields)
+      throws TableNotFoundException {
     EXISTING_TABLE_NAME.validate(tableName);
+    Objects.requireNonNull(ranges, "ranges is null");
 
-    final Text scanRangeStart = (range.getStartKey() == null) ? null : 
range.getStartKey().getRow();
-    TableId tableId = context.getTableId(tableName);
-
-    List<TabletMetadata.ColumnType> columns = new ArrayList<>();
-    EnumSet<TabletInformation.Field> fieldSet =
-        fields.length == 0 ? EnumSet.allOf(TabletInformation.Field.class)
-            : EnumSet.noneOf(TabletInformation.Field.class);
-    Collections.addAll(fieldSet, fields);
-    if (fieldSet.contains(TabletInformation.Field.FILES)) {
-      Collections.addAll(columns, DIR, FILES, LOGS);
-    }
-    if (fieldSet.contains(TabletInformation.Field.LOCATION)) {
-      Collections.addAll(columns, LOCATION, LAST, SUSPEND);
-    }
-    if (fieldSet.contains(TabletInformation.Field.AVAILABILITY)) {
-      Collections.addAll(columns, AVAILABILITY);
-    }
-    if (fieldSet.contains(TabletInformation.Field.MERGEABILITY)) {
-      Collections.addAll(columns, MERGEABILITY);
-    }
-    columns.add(PREV_ROW);
-
-    TabletsMetadata tabletsMetadata =
-        
context.getAmple().readTablets().forTable(tableId).overlapping(scanRangeStart, 
true, null)
-            .fetch(columns.toArray(new 
TabletMetadata.ColumnType[0])).checkConsistency().build();
-
-    Set<TServerInstance> liveTserverSet = 
TabletMetadata.getLiveTServers(context);
+    EnumSet<TabletInformation.Field> fieldSet = fields.length == 0
+        ? EnumSet.allOf(TabletInformation.Field.class) : 
EnumSet.copyOf(Arrays.asList(fields));
 
-    var currentTime = Suppliers.memoize(() -> {
-      try {
-        return Duration.ofNanos(ThriftClientTypes.MANAGER.execute(context,
-            client -> client.getManagerTimeNanos(TraceUtil.traceInfo(), 
context.rpcCreds())));
-      } catch (AccumuloException | AccumuloSecurityException e) {
-        throw new IllegalStateException(e);
-      }
-    });
+    TableId tableId = context.getTableId(tableName);
 
-    return tabletsMetadata.stream().onClose(tabletsMetadata::close).peek(tm -> 
{
-      if (scanRangeStart != null && tm.getEndRow() != null
-          && tm.getEndRow().compareTo(scanRangeStart) < 0) {
-        log.debug("tablet {} is before scan start range: {}", tm.getExtent(), 
scanRangeStart);
-        throw new RuntimeException("Bug in ample or this code.");
-      }
-    }).takeWhile(tm -> tm.getPrevEndRow() == null
-        || !range.afterEndKey(new 
Key(tm.getPrevEndRow()).followingKey(PartialKey.ROW)))
-        .map(tm -> new TabletInformationImpl(tm,
-            () -> TabletState.compute(tm, liveTserverSet).toString(), 
currentTime));
+    return TabletInformationCollector.getTabletInformation(context, tableId, 
ranges, fieldSet);
   }
 
   @Override
diff --git 
a/core/src/main/java/org/apache/accumulo/core/clientImpl/TabletInformationCollector.java
 
b/core/src/main/java/org/apache/accumulo/core/clientImpl/TabletInformationCollector.java
new file mode 100644
index 0000000000..5e29b52c6b
--- /dev/null
+++ 
b/core/src/main/java/org/apache/accumulo/core/clientImpl/TabletInformationCollector.java
@@ -0,0 +1,135 @@
+/*
+ * 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
+ *
+ *   https://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.core.clientImpl;
+
+import static 
org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.DIR;
+import static 
org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.FILES;
+import static 
org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.LAST;
+import static 
org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.LOCATION;
+import static 
org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.LOGS;
+import static 
org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.SUSPEND;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+
+import org.apache.accumulo.core.client.admin.TabletInformation;
+import org.apache.accumulo.core.data.RowRange;
+import org.apache.accumulo.core.data.TableId;
+import org.apache.accumulo.core.metadata.TServerInstance;
+import org.apache.accumulo.core.metadata.TabletState;
+import org.apache.accumulo.core.metadata.schema.TabletMetadata;
+import org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType;
+import org.apache.hadoop.io.Text;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Suppliers;
+
+/**
+ * Utility to read tablet information for one or more ranges.
+ */
+public class TabletInformationCollector {
+
+  private static final Logger log = 
LoggerFactory.getLogger(TabletInformationCollector.class);
+
+  private TabletInformationCollector() {}
+
+  /**
+   * Fetch tablet information for the provided ranges. Ranges will be merged. 
The stream may be
+   * backed by a scanner, so it's best to close the stream. The stream has no 
defined ordering.
+   */
+  public static Stream<TabletInformation> getTabletInformation(ClientContext 
context,
+      TableId tableId, List<RowRange> ranges, EnumSet<TabletInformation.Field> 
fields) {
+    var mergedRanges = RowRange.mergeOverlapping(ranges);
+
+    EnumSet<ColumnType> columns = columnsForFields(fields);
+
+    Set<TServerInstance> liveTserverSet = 
TabletMetadata.getLiveTServers(context);
+
+    Supplier<Duration> currentTime = Suppliers.memoize(() -> {
+      try {
+        return context.instanceOperations().getManagerTime();
+      } catch (Exception e) {
+        throw new IllegalStateException(e);
+      }
+    });
+
+    List<Stream<TabletInformation>> tabletStreams = new ArrayList<>();
+    for (RowRange rowRange : mergedRanges) {
+
+      Text startRow = rowRange.getLowerBound();
+      Text endRow = rowRange.getUpperBound();
+      boolean startInclusive = rowRange.isLowerBoundInclusive();
+
+      var tm = context.getAmple().readTablets().forTable(tableId)
+          .overlapping(startRow, startInclusive, 
endRow).fetch(columns.toArray(ColumnType[]::new))
+          .checkConsistency().build();
+
+      // stop once the tablets are beyond the row range's upper bound
+      Predicate<TabletMetadata> notPastUpperBound = tme -> {
+        Text prevEndRow = tme.getPrevEndRow();
+        if (prevEndRow == null || endRow == null) {
+          return true;
+        }
+        return prevEndRow.compareTo(endRow) < 0;
+      };
+
+      Stream<TabletInformation> stream = 
tm.stream().onClose(tm::close).peek(tme -> {
+        if (startRow != null && tme.getEndRow() != null
+            && tme.getEndRow().compareTo(startRow) < 0) {
+          log.debug("tablet {} is before scan start range: {}", 
tme.getExtent(), startRow);
+          throw new RuntimeException("Bug in ample or this code.");
+        }
+      }).takeWhile(notPastUpperBound).map(tme -> new TabletInformationImpl(tme,
+          () -> TabletState.compute(tme, liveTserverSet).toString(), 
currentTime));
+      tabletStreams.add(stream);
+    }
+
+    return 
tabletStreams.stream().reduce(Stream::concat).orElseGet(Stream::empty);
+  }
+
+  /**
+   * @return the required {@link ColumnType}s that need to be fetched for the 
given set of
+   *         {@link TabletInformation.Field}
+   */
+  private static EnumSet<ColumnType> 
columnsForFields(EnumSet<TabletInformation.Field> fields) {
+    EnumSet<ColumnType> columns = EnumSet.noneOf(ColumnType.class);
+    columns.add(ColumnType.PREV_ROW);
+    if (fields.contains(TabletInformation.Field.FILES)) {
+      Collections.addAll(columns, DIR, FILES, LOGS);
+    }
+    if (fields.contains(TabletInformation.Field.LOCATION)) {
+      Collections.addAll(columns, LOCATION, LAST, SUSPEND);
+    }
+    if (fields.contains(TabletInformation.Field.AVAILABILITY)) {
+      columns.add(ColumnType.AVAILABILITY);
+    }
+    if (fields.contains(TabletInformation.Field.MERGEABILITY)) {
+      columns.add(ColumnType.MERGEABILITY);
+    }
+    return columns;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/accumulo/core/spi/balancer/BalancerEnvironment.java
 
b/core/src/main/java/org/apache/accumulo/core/spi/balancer/BalancerEnvironment.java
index 88aaf60d9a..cb4bc35e42 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/spi/balancer/BalancerEnvironment.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/spi/balancer/BalancerEnvironment.java
@@ -20,9 +20,12 @@ package org.apache.accumulo.core.spi.balancer;
 
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Stream;
 
 import org.apache.accumulo.core.client.AccumuloException;
 import org.apache.accumulo.core.client.AccumuloSecurityException;
+import org.apache.accumulo.core.client.admin.TabletInformation;
+import org.apache.accumulo.core.data.RowRange;
 import org.apache.accumulo.core.data.TableId;
 import org.apache.accumulo.core.data.TabletId;
 import org.apache.accumulo.core.spi.balancer.data.TabletServerId;
@@ -60,7 +63,9 @@ public interface BalancerEnvironment extends 
ServiceEnvironment {
   /**
    * Fetch the locations for each of {@code tableId}'s tablets from the 
metadata table. If there is
    * no location available for a given tablet, then the returned mapping will 
have a {@code null}
-   * value stored for the tablet id.
+   * value stored for the tablet id. If you don't need all tablets in the 
table, use
+   * {@link BalancerEnvironment#getTabletInformation(TableId, List, 
TabletInformation.Field...)}
+   * which is more efficient for the case when specific row ranges are needed.
    *
    * @param tableId The id of the table for which to retrieve tablets.
    * @return a mapping of {@link TabletId} to {@link TabletServerId} (or @null 
if no location is
@@ -86,4 +91,13 @@ public interface BalancerEnvironment extends 
ServiceEnvironment {
    * none is configured.
    */
   String tableContext(TableId tableId);
+
+  /**
+   * Retrieve tablet information for the provided list of row ranges. The 
stream may be backed by a
+   * scanner, so it's best to close the stream. The stream has no defined 
ordering.
+   *
+   * @since 4.0.0
+   */
+  Stream<TabletInformation> getTabletInformation(TableId tableId, 
List<RowRange> ranges,
+      TabletInformation.Field... fields);
 }
diff --git 
a/server/base/src/main/java/org/apache/accumulo/server/manager/balancer/BalancerEnvironmentImpl.java
 
b/server/base/src/main/java/org/apache/accumulo/server/manager/balancer/BalancerEnvironmentImpl.java
index cdab458649..f5aa8f6a4b 100644
--- 
a/server/base/src/main/java/org/apache/accumulo/server/manager/balancer/BalancerEnvironmentImpl.java
+++ 
b/server/base/src/main/java/org/apache/accumulo/server/manager/balancer/BalancerEnvironmentImpl.java
@@ -21,16 +21,22 @@ package org.apache.accumulo.server.manager.balancer;
 import static 
org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.LOCATION;
 import static 
org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.PREV_ROW;
 
+import java.util.Arrays;
+import java.util.EnumSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import org.apache.accumulo.core.classloader.ClassLoaderUtil;
 import org.apache.accumulo.core.client.AccumuloException;
 import org.apache.accumulo.core.client.AccumuloSecurityException;
+import org.apache.accumulo.core.client.admin.TabletInformation;
+import org.apache.accumulo.core.clientImpl.TabletInformationCollector;
 import org.apache.accumulo.core.clientImpl.thrift.ThriftSecurityException;
+import org.apache.accumulo.core.data.RowRange;
 import org.apache.accumulo.core.data.TableId;
 import org.apache.accumulo.core.data.TabletId;
 import org.apache.accumulo.core.dataImpl.TabletIdImpl;
@@ -111,6 +117,14 @@ public class BalancerEnvironmentImpl extends 
ServiceEnvironmentImpl implements B
     return null;
   }
 
+  @Override
+  public Stream<TabletInformation> getTabletInformation(TableId tableId, 
List<RowRange> ranges,
+      TabletInformation.Field... fields) {
+    EnumSet<TabletInformation.Field> fieldSet = fields.length == 0
+        ? EnumSet.allOf(TabletInformation.Field.class) : 
EnumSet.copyOf(Arrays.asList(fields));
+    return TabletInformationCollector.getTabletInformation(getContext(), 
tableId, ranges, fieldSet);
+  }
+
   @Override
   public String tableContext(TableId tableId) {
     return 
ClassLoaderUtil.tableContext(getContext().getTableConfiguration(tableId));
diff --git 
a/server/monitor/src/main/java/org/apache/accumulo/monitor/next/InformationFetcher.java
 
b/server/monitor/src/main/java/org/apache/accumulo/monitor/next/InformationFetcher.java
index af832ee3e1..4c528776a2 100644
--- 
a/server/monitor/src/main/java/org/apache/accumulo/monitor/next/InformationFetcher.java
+++ 
b/server/monitor/src/main/java/org/apache/accumulo/monitor/next/InformationFetcher.java
@@ -45,7 +45,7 @@ import 
org.apache.accumulo.core.client.admin.servers.ServerId.Type;
 import org.apache.accumulo.core.compaction.thrift.CompactionCoordinatorService;
 import org.apache.accumulo.core.compaction.thrift.TExternalCompactionList;
 import org.apache.accumulo.core.conf.Property;
-import org.apache.accumulo.core.data.Range;
+import org.apache.accumulo.core.data.RowRange;
 import org.apache.accumulo.core.data.TableId;
 import org.apache.accumulo.core.process.thrift.MetricResponse;
 import org.apache.accumulo.core.process.thrift.ServerProcessService.Client;
@@ -157,7 +157,7 @@ public class InformationFetcher implements 
RemovalListener<ServerId,MetricRespon
       try {
         final String tableName = ctx.getQualifiedTableName(tableId);
         try (Stream<TabletInformation> tablets =
-            this.ctx.tableOperations().getTabletInformation(tableName, new 
Range())) {
+            this.ctx.tableOperations().getTabletInformation(tableName, 
List.of(RowRange.all()))) {
           tablets.forEach(t -> summary.processTabletInformation(tableId, 
tableName, t));
         }
       } catch (TableNotFoundException e) {
diff --git 
a/shell/src/main/java/org/apache/accumulo/shell/commands/GetAvailabilityCommand.java
 
b/shell/src/main/java/org/apache/accumulo/shell/commands/GetAvailabilityCommand.java
index 3be57ba7f8..567403066d 100644
--- 
a/shell/src/main/java/org/apache/accumulo/shell/commands/GetAvailabilityCommand.java
+++ 
b/shell/src/main/java/org/apache/accumulo/shell/commands/GetAvailabilityCommand.java
@@ -18,7 +18,9 @@
  */
 package org.apache.accumulo.shell.commands;
 
-import org.apache.accumulo.core.data.Range;
+import java.util.List;
+
+import org.apache.accumulo.core.data.RowRange;
 import org.apache.accumulo.shell.Shell;
 import org.apache.commons.cli.CommandLine;
 import org.apache.commons.cli.Option;
@@ -30,7 +32,7 @@ public class GetAvailabilityCommand extends TableOperation {
   private Option optRow;
   private Option optStartRowExclusive;
   private Option optEndRowExclusive;
-  private Range range;
+  private RowRange range;
 
   @Override
   public String getName() {
@@ -46,8 +48,8 @@ public class GetAvailabilityCommand extends TableOperation {
   protected void doTableOp(Shell shellState, String tableName) throws 
Exception {
     shellState.getWriter().println("TABLE: " + tableName);
     shellState.getWriter().println("TABLET ID    AVAILABILITY");
-    try (var tabletInformation =
-        
shellState.getAccumuloClient().tableOperations().getTabletInformation(tableName,
 range)) {
+    try (var tabletInformation = 
shellState.getAccumuloClient().tableOperations()
+        .getTabletInformation(tableName, List.of(range))) {
       tabletInformation.forEach(p -> shellState.getWriter()
           .println(String.format("%-10s   %s", p.getTabletId(), 
p.getTabletAvailability())));
     }
@@ -65,13 +67,14 @@ public class GetAvailabilityCommand extends TableOperation {
     }
 
     if (cl.hasOption(optRow.getOpt())) {
-      this.range = new Range(new 
Text(cl.getOptionValue(optRow.getOpt()).getBytes(Shell.CHARSET)));
+      this.range =
+          RowRange.closed(new 
Text(cl.getOptionValue(optRow.getOpt()).getBytes(Shell.CHARSET)));
     } else {
       Text startRow = OptUtil.getStartRow(cl);
       Text endRow = OptUtil.getEndRow(cl);
       final boolean startInclusive = 
!cl.hasOption(optStartRowExclusive.getOpt());
       final boolean endInclusive = !cl.hasOption(optEndRowExclusive.getOpt());
-      this.range = new Range(startRow, startInclusive, endRow, endInclusive);
+      this.range = RowRange.range(startRow, startInclusive, endRow, 
endInclusive);
     }
     return super.execute(fullCommand, cl, shellState);
   }
diff --git 
a/shell/src/main/java/org/apache/accumulo/shell/commands/ListTabletsCommand.java
 
b/shell/src/main/java/org/apache/accumulo/shell/commands/ListTabletsCommand.java
index a0dc5a03a9..b5fe3d91ed 100644
--- 
a/shell/src/main/java/org/apache/accumulo/shell/commands/ListTabletsCommand.java
+++ 
b/shell/src/main/java/org/apache/accumulo/shell/commands/ListTabletsCommand.java
@@ -33,7 +33,7 @@ import 
org.apache.accumulo.core.client.NamespaceNotFoundException;
 import org.apache.accumulo.core.client.admin.TableOperations;
 import org.apache.accumulo.core.client.admin.TabletInformation;
 import org.apache.accumulo.core.data.NamespaceId;
-import org.apache.accumulo.core.data.Range;
+import org.apache.accumulo.core.data.RowRange;
 import org.apache.accumulo.core.util.NumUtil;
 import org.apache.accumulo.shell.Shell;
 import org.apache.accumulo.shell.Shell.Command;
@@ -76,8 +76,8 @@ public class ListTabletsCommand extends Command {
       String name = tableInfo.name;
       lines.add("TABLE: " + name);
 
-      try (Stream<TabletInformation> tabletInfoStream =
-          shellState.getContext().tableOperations().getTabletInformation(name, 
new Range())) {
+      try (Stream<TabletInformation> tabletInfoStream = 
shellState.getContext().tableOperations()
+          .getTabletInformation(name, List.of(RowRange.all()))) {
         final AtomicInteger counter = new AtomicInteger(1);
         tabletInfoStream.forEach(tabletInfo -> {
           int i = counter.getAndIncrement();
diff --git 
a/shell/src/test/java/org/apache/accumulo/shell/commands/ListTabletsCommandTest.java
 
b/shell/src/test/java/org/apache/accumulo/shell/commands/ListTabletsCommandTest.java
index b7bd5f1f66..569cf714de 100644
--- 
a/shell/src/test/java/org/apache/accumulo/shell/commands/ListTabletsCommandTest.java
+++ 
b/shell/src/test/java/org/apache/accumulo/shell/commands/ListTabletsCommandTest.java
@@ -39,7 +39,7 @@ import org.apache.accumulo.core.client.admin.TableOperations;
 import org.apache.accumulo.core.client.admin.TabletAvailability;
 import org.apache.accumulo.core.clientImpl.ClientContext;
 import org.apache.accumulo.core.clientImpl.TabletInformationImpl;
-import org.apache.accumulo.core.data.Range;
+import org.apache.accumulo.core.data.RowRange;
 import org.apache.accumulo.core.data.TableId;
 import org.apache.accumulo.core.dataImpl.KeyExtent;
 import org.apache.accumulo.core.metadata.ReferencedTabletFile;
@@ -193,7 +193,7 @@ public class ListTabletsCommandTest {
     EasyMock.expect(shellState.getContext()).andReturn(context).anyTimes();
     EasyMock.expect(client.tableOperations()).andReturn(tableOps).anyTimes();
     EasyMock.expect(context.tableOperations()).andReturn(tableOps).anyTimes();
-    EasyMock.expect(tableOps.getTabletInformation(tableName, new Range()))
+    EasyMock.expect(tableOps.getTabletInformation(tableName, 
List.of(RowRange.all())))
         .andReturn(Stream.of(tabletInformation));
 
     Map<String,String> idMap = new TreeMap<>();
diff --git 
a/test/src/main/java/org/apache/accumulo/test/ComprehensiveITBase.java 
b/test/src/main/java/org/apache/accumulo/test/ComprehensiveITBase.java
index c9367d7e59..798e33252c 100644
--- a/test/src/main/java/org/apache/accumulo/test/ComprehensiveITBase.java
+++ b/test/src/main/java/org/apache/accumulo/test/ComprehensiveITBase.java
@@ -1105,7 +1105,7 @@ public abstract class ComprehensiveITBase extends 
SharedMiniClusterBase {
         IteratorUtil.IteratorScope.scan));
 
     try (Stream<TabletInformation> tabletInfo =
-        client.tableOperations().getTabletInformation(table, new Range())) {
+        client.tableOperations().getTabletInformation(table, 
List.of(RowRange.all()))) {
       tabletInfo.forEach(tabletInformation -> {
         if (tabletInformation.getTabletId().getEndRow() == null) {
           assertEquals(expectedAvailabilityForDefaultTable,
diff --git 
a/test/src/main/java/org/apache/accumulo/test/ComprehensiveTableOperationsIT.java
 
b/test/src/main/java/org/apache/accumulo/test/ComprehensiveTableOperationsIT.java
index 004b00e8e5..100168f915 100644
--- 
a/test/src/main/java/org/apache/accumulo/test/ComprehensiveTableOperationsIT.java
+++ 
b/test/src/main/java/org/apache/accumulo/test/ComprehensiveTableOperationsIT.java
@@ -802,8 +802,8 @@ public class ComprehensiveTableOperationsIT extends 
SharedMiniClusterBase {
       // should not be able to unhost any system table
       assertThrows(AccumuloException.class,
           () -> ops.setTabletAvailability(sysTable, new Range(), 
TabletAvailability.UNHOSTED));
-      assertTrue(ops.getTabletInformation(sysTable, new 
Range()).findAny().isPresent());
-      ops.getTabletInformation(sysTable, new Range())
+      assertTrue(ops.getTabletInformation(sysTable, 
List.of(RowRange.all())).findAny().isPresent());
+      ops.getTabletInformation(sysTable, List.of(RowRange.all()))
           .forEach(ti -> assertEquals(TabletAvailability.HOSTED, 
ti.getTabletAvailability()));
     }
   }
diff --git a/test/src/main/java/org/apache/accumulo/test/ImportExportIT.java 
b/test/src/main/java/org/apache/accumulo/test/ImportExportIT.java
index e35bece0f2..a091f7cc74 100644
--- a/test/src/main/java/org/apache/accumulo/test/ImportExportIT.java
+++ b/test/src/main/java/org/apache/accumulo/test/ImportExportIT.java
@@ -55,6 +55,7 @@ import org.apache.accumulo.core.conf.Property;
 import org.apache.accumulo.core.data.Key;
 import org.apache.accumulo.core.data.Mutation;
 import org.apache.accumulo.core.data.Range;
+import org.apache.accumulo.core.data.RowRange;
 import org.apache.accumulo.core.data.TableId;
 import org.apache.accumulo.core.data.TabletId;
 import org.apache.accumulo.core.data.Value;
@@ -377,7 +378,7 @@ public class ImportExportIT extends AccumuloClusterHarness {
           TabletAvailability.UNHOSTED);
       setExpectedTabletAvailability(expectedTabletAvailability, srcTableId, 
null, "q",
           TabletAvailability.HOSTED);
-      verifyTabletAvailabilities(client, srcTable, new Range(), 
expectedTabletAvailability);
+      verifyTabletAvailabilities(client, srcTable, RowRange.all(), 
expectedTabletAvailability);
 
       // Add a split within each of the existing tablets. Adding 'd', 'm', and 
'v'
       splits = Sets.newTreeSet(Arrays.asList(new Text("d"), new Text("m"), new 
Text("v")));
@@ -397,7 +398,7 @@ public class ImportExportIT extends AccumuloClusterHarness {
           TabletAvailability.HOSTED);
       setExpectedTabletAvailability(expectedTabletAvailability, srcTableId, 
null, "v",
           TabletAvailability.HOSTED);
-      verifyTabletAvailabilities(client, srcTable, new Range(), 
expectedTabletAvailability);
+      verifyTabletAvailabilities(client, srcTable, RowRange.all(), 
expectedTabletAvailability);
 
       // Make a directory we can use to throw the export and import directories
       // Must exist on the filesystem the cluster is running.
@@ -444,7 +445,7 @@ public class ImportExportIT extends AccumuloClusterHarness {
       // Get all `file` colfams from the metadata table for the new table
       log.info("Imported into table with ID: {}", destTableId);
 
-      client.tableOperations().getTabletInformation(destTable, new Range())
+      client.tableOperations().getTabletInformation(destTable, 
List.of(RowRange.all()))
           .forEach(tabletInformation -> 
assertEquals(TabletAvailability.ONDEMAND,
               tabletInformation.getTabletAvailability(),
               "Expected all tablets in imported table to be ONDEMAND"));
diff --git a/test/src/main/java/org/apache/accumulo/test/TableOperationsIT.java 
b/test/src/main/java/org/apache/accumulo/test/TableOperationsIT.java
index c38e0fd212..7414e0a7cb 100644
--- a/test/src/main/java/org/apache/accumulo/test/TableOperationsIT.java
+++ b/test/src/main/java/org/apache/accumulo/test/TableOperationsIT.java
@@ -68,6 +68,7 @@ import org.apache.accumulo.core.data.Key;
 import org.apache.accumulo.core.data.Mutation;
 import org.apache.accumulo.core.data.PartialKey;
 import org.apache.accumulo.core.data.Range;
+import org.apache.accumulo.core.data.RowRange;
 import org.apache.accumulo.core.data.TableId;
 import org.apache.accumulo.core.data.TabletId;
 import org.apache.accumulo.core.data.Value;
@@ -569,17 +570,17 @@ public class TableOperationsIT extends 
AccumuloClusterHarness {
       Map<TabletId,TabletAvailability> expectedTabletAvailability = new 
HashMap<>();
       setExpectedTabletAvailability(expectedTabletAvailability, 
idMap.get(tableOnDemand), null,
           null, TabletAvailability.ONDEMAND);
-      verifyTabletAvailabilities(tableOnDemand, new Range(), 
expectedTabletAvailability);
+      verifyTabletAvailabilities(tableOnDemand, RowRange.all(), 
expectedTabletAvailability);
 
       expectedTabletAvailability.clear();
       setExpectedTabletAvailability(expectedTabletAvailability, 
idMap.get(tableHosted), null, null,
           TabletAvailability.HOSTED);
-      verifyTabletAvailabilities(tableHosted, new Range(), 
expectedTabletAvailability);
+      verifyTabletAvailabilities(tableHosted, RowRange.all(), 
expectedTabletAvailability);
 
       expectedTabletAvailability.clear();
       setExpectedTabletAvailability(expectedTabletAvailability, 
idMap.get(tableUnhosted), null,
           null, TabletAvailability.UNHOSTED);
-      verifyTabletAvailabilities(tableUnhosted, new Range(), 
expectedTabletAvailability);
+      verifyTabletAvailabilities(tableUnhosted, RowRange.all(), 
expectedTabletAvailability);
 
       verifyTablesWithSplits(tableOnDemandWithSplits, idMap, splits, 
TabletAvailability.ONDEMAND);
       verifyTablesWithSplits(tableHostedWithSplits, idMap, splits, 
TabletAvailability.HOSTED);
@@ -636,7 +637,7 @@ public class TableOperationsIT extends 
AccumuloClusterHarness {
           TabletAvailability.HOSTED);
       setExpectedTabletAvailability(expectedTabletAvailability, tableId, null, 
"s",
           TabletAvailability.UNHOSTED);
-      verifyTabletAvailabilities(tableName, new Range(), 
expectedTabletAvailability);
+      verifyTabletAvailabilities(tableName, RowRange.all(), 
expectedTabletAvailability);
     } finally {
       accumuloClient.tableOperations().delete(tableName);
     }
@@ -675,10 +676,10 @@ public class TableOperationsIT extends 
AccumuloClusterHarness {
       setExpectedTabletAvailability(expectedTabletAvailability, tableId, "d", 
null,
           TabletAvailability.HOSTED);
       // test using row as range constructor
-      verifyTabletAvailabilities(tableName, new Range("a"), 
expectedTabletAvailability);
+      verifyTabletAvailabilities(tableName, RowRange.closed("a"), 
expectedTabletAvailability);
 
       // test using startRowInclusive set to true
-      Range range = new Range(new Text("c"), true, new Text("c"), true);
+      RowRange range = RowRange.closed(new Text("c"));
       verifyTabletAvailabilities(tableName, range, expectedTabletAvailability);
 
       expectedTabletAvailability.clear();
@@ -687,7 +688,7 @@ public class TableOperationsIT extends 
AccumuloClusterHarness {
       setExpectedTabletAvailability(expectedTabletAvailability, tableId, "s", 
"m",
           TabletAvailability.HOSTED);
 
-      range = new Range(new Text("m"), new Text("p"));
+      range = RowRange.closed(new Text("m"), new Text("p"));
       verifyTabletAvailabilities(tableName, range, expectedTabletAvailability);
 
       expectedTabletAvailability.clear();
@@ -700,7 +701,7 @@ public class TableOperationsIT extends 
AccumuloClusterHarness {
       setExpectedTabletAvailability(expectedTabletAvailability, tableId, null, 
"s",
           TabletAvailability.ONDEMAND);
 
-      range = new Range("b", false, "t", true);
+      range = RowRange.openClosed("b", "t");
       verifyTabletAvailabilities(tableName, range, expectedTabletAvailability);
 
     } finally {
@@ -728,7 +729,7 @@ public class TableOperationsIT extends 
AccumuloClusterHarness {
       String tableId = idMap.get(tableName);
       setExpectedTabletAvailability(expectedTabletAvailability, tableId, null, 
null,
           TabletAvailability.HOSTED);
-      verifyTabletAvailabilities(tableName, new Range(), 
expectedTabletAvailability);
+      verifyTabletAvailabilities(tableName, RowRange.all(), 
expectedTabletAvailability);
 
       // Add splits after the fact
       SortedSet<Text> splits =
@@ -744,7 +745,7 @@ public class TableOperationsIT extends 
AccumuloClusterHarness {
           TabletAvailability.HOSTED);
       setExpectedTabletAvailability(expectedTabletAvailability, tableId, null, 
"r",
           TabletAvailability.HOSTED);
-      verifyTabletAvailabilities(tableName, new Range(), 
expectedTabletAvailability);
+      verifyTabletAvailabilities(tableName, RowRange.all(), 
expectedTabletAvailability);
     } finally {
       accumuloClient.tableOperations().delete(tableName);
     }
@@ -787,7 +788,7 @@ public class TableOperationsIT extends 
AccumuloClusterHarness {
           TabletAvailability.UNHOSTED);
       setExpectedTabletAvailability(expectedTabletAvailability, tableId, null, 
"q",
           TabletAvailability.HOSTED);
-      verifyTabletAvailabilities(tableName, new Range(), 
expectedTabletAvailability);
+      verifyTabletAvailabilities(tableName, RowRange.all(), 
expectedTabletAvailability);
 
       // Add a split within each of the existing tablets. Adding 'd', 'm', and 
'v'
       splits = Sets.newTreeSet(Arrays.asList(new Text("d"), new Text("m"), new 
Text("v")));
@@ -807,7 +808,7 @@ public class TableOperationsIT extends 
AccumuloClusterHarness {
           TabletAvailability.HOSTED);
       setExpectedTabletAvailability(expectedTabletAvailability, tableId, null, 
"v",
           TabletAvailability.HOSTED);
-      verifyTabletAvailabilities(tableName, new Range(), 
expectedTabletAvailability);
+      verifyTabletAvailabilities(tableName, RowRange.all(), 
expectedTabletAvailability);
     } finally {
       accumuloClient.tableOperations().delete(tableName);
     }
@@ -829,33 +830,33 @@ public class TableOperationsIT extends 
AccumuloClusterHarness {
         tabletAvailability);
     setExpectedTabletAvailability(expectedTabletAvailability, tableId, null, 
splitPts[2],
         tabletAvailability);
-    verifyTabletAvailabilities(tableName, new Range(), 
expectedTabletAvailability);
+    verifyTabletAvailabilities(tableName, RowRange.all(), 
expectedTabletAvailability);
 
     // verify individual tablets can be retrieved
     expectedTabletAvailability.clear();
     setExpectedTabletAvailability(expectedTabletAvailability, tableId, 
splitPts[0], null,
         tabletAvailability);
-    verifyTabletAvailabilities(tableName, new Range(null, new 
Text(splitPts[0])),
+    verifyTabletAvailabilities(tableName, RowRange.atMost(new 
Text(splitPts[0])),
         expectedTabletAvailability);
 
     expectedTabletAvailability.clear();
     setExpectedTabletAvailability(expectedTabletAvailability, tableId, 
splitPts[1], splitPts[0],
         tabletAvailability);
     verifyTabletAvailabilities(tableName,
-        new Range(new Text(splitPts[0]), false, new Text(splitPts[1]), true),
+        RowRange.openClosed(new Text(splitPts[0]), new Text(splitPts[1])),
         expectedTabletAvailability);
 
     expectedTabletAvailability.clear();
     setExpectedTabletAvailability(expectedTabletAvailability, tableId, 
splitPts[2], splitPts[1],
         tabletAvailability);
     verifyTabletAvailabilities(tableName,
-        new Range(new Text(splitPts[1]), false, new Text(splitPts[2]), true),
+        RowRange.openClosed(new Text(splitPts[1]), new Text(splitPts[2])),
         expectedTabletAvailability);
 
     expectedTabletAvailability.clear();
     setExpectedTabletAvailability(expectedTabletAvailability, tableId, null, 
splitPts[2],
         tabletAvailability);
-    verifyTabletAvailabilities(tableName, new Range(new Text(splitPts[2]), 
false, null, true),
+    verifyTabletAvailabilities(tableName, RowRange.greaterThan(new 
Text(splitPts[2])),
         expectedTabletAvailability);
 
     expectedTabletAvailability.clear();
@@ -864,24 +865,40 @@ public class TableOperationsIT extends 
AccumuloClusterHarness {
     setExpectedTabletAvailability(expectedTabletAvailability, tableId, 
splitPts[2], splitPts[1],
         tabletAvailability);
     verifyTabletAvailabilities(tableName,
-        new Range(new Text(splitPts[0]), false, new Text(splitPts[2]), true),
+        RowRange.openClosed(new Text(splitPts[0]), new Text(splitPts[2])),
         expectedTabletAvailability);
   }
 
-  public static void verifyTabletAvailabilities(String tableName, Range range,
+  public static void verifyTabletAvailabilities(String tableName, RowRange 
range,
       Map<TabletId,TabletAvailability> expectedAvailability) throws 
TableNotFoundException {
     verifyTabletAvailabilities(accumuloClient, tableName, range, 
expectedAvailability);
   }
 
   public static void verifyTabletAvailabilities(AccumuloClient client, String 
tableName,
-      Range range, Map<TabletId,TabletAvailability> expectedAvailability)
+      RowRange range, Map<TabletId,TabletAvailability> expectedAvailability)
       throws TableNotFoundException {
     Map<TabletId,TabletAvailability> seenAvailability =
-        client.tableOperations().getTabletInformation(tableName, 
range).collect(Collectors
+        client.tableOperations().getTabletInformation(tableName, 
List.of(range)).collect(Collectors
             .toMap(TabletInformation::getTabletId, 
TabletInformation::getTabletAvailability));
     assertEquals(expectedAvailability, seenAvailability);
   }
 
+  /**
+   * assert the given {@code List<String>} equals what's returned from
+   * {@link TableOperations#getTabletInformation(String, List, 
TabletInformation.Field...)} using
+   * the given RowRange
+   */
+  private static void assertEndRowsForRange(String tableName, RowRange range, 
List<String> expected)
+      throws TableNotFoundException {
+    try (var tablets = 
accumuloClient.tableOperations().getTabletInformation(tableName,
+        List.of(range), TabletInformation.Field.LOCATION)) {
+      var actual = 
tablets.map(TabletInformation::getTabletId).map(TabletId::getEndRow)
+          .map(er -> er == null ? "null" : er.toString()).toList();
+      assertEquals(expected, actual,
+          "Expected does not match actual. Expected: " + expected + " Actual: 
" + actual);
+    }
+  }
+
   public static void 
setExpectedTabletAvailability(Map<TabletId,TabletAvailability> expected,
       String id, String endRow, String prevEndRow, TabletAvailability 
availability) {
     KeyExtent ke = new KeyExtent(TableId.of(id), endRow == null ? null : new 
Text(endRow),
@@ -944,7 +961,7 @@ public class TableOperationsIT extends 
AccumuloClusterHarness {
       var tableId = 
TableId.of(accumuloClient.tableOperations().tableIdMap().get(tableName));
 
       try (var tablets = 
accumuloClient.tableOperations().getTabletInformation(tableName,
-          new Range(), TabletInformation.Field.LOCATION)) {
+          List.of(RowRange.all()), TabletInformation.Field.LOCATION)) {
         var tabletList = tablets.collect(Collectors.toList());
         assertEquals(9, tabletList.size());
         tabletList.forEach(ti -> {
@@ -962,7 +979,7 @@ public class TableOperationsIT extends 
AccumuloClusterHarness {
       }
 
       try (var tablets = 
accumuloClient.tableOperations().getTabletInformation(tableName,
-          new Range(), TabletInformation.Field.FILES)) {
+          List.of(RowRange.all()), TabletInformation.Field.FILES)) {
         var tabletList = tablets.collect(Collectors.toList());
         assertEquals(9, tabletList.size());
         tabletList.forEach(ti -> {
@@ -979,8 +996,9 @@ public class TableOperationsIT extends 
AccumuloClusterHarness {
         });
       }
 
-      try (var tablets = 
accumuloClient.tableOperations().getTabletInformation(tableName,
-          new Range(), TabletInformation.Field.FILES, 
TabletInformation.Field.LOCATION)) {
+      try (var tablets =
+          accumuloClient.tableOperations().getTabletInformation(tableName, 
List.of(RowRange.all()),
+              TabletInformation.Field.FILES, 
TabletInformation.Field.LOCATION)) {
         var tabletList = tablets.collect(Collectors.toList());
         assertEquals(9, tabletList.size());
         tabletList.forEach(ti -> {
@@ -998,7 +1016,7 @@ public class TableOperationsIT extends 
AccumuloClusterHarness {
       }
 
       try (var tablets = 
accumuloClient.tableOperations().getTabletInformation(tableName,
-          new Range(), TabletInformation.Field.AVAILABILITY)) {
+          List.of(RowRange.all()), TabletInformation.Field.AVAILABILITY)) {
         var tabletList = tablets.collect(Collectors.toList());
         assertEquals(9, tabletList.size());
         tabletList.forEach(ti -> {
@@ -1016,7 +1034,7 @@ public class TableOperationsIT extends 
AccumuloClusterHarness {
       }
 
       try (var tablets = 
accumuloClient.tableOperations().getTabletInformation(tableName,
-          new Range(), TabletInformation.Field.MERGEABILITY)) {
+          List.of(RowRange.all()), TabletInformation.Field.MERGEABILITY)) {
         var tabletList = tablets.collect(Collectors.toList());
         assertEquals(9, tabletList.size());
         tabletList.forEach(ti -> {
@@ -1037,6 +1055,63 @@ public class TableOperationsIT extends 
AccumuloClusterHarness {
         });
       }
 
+      // RowRange.range(null, true, X, true)
+      var unboundedStartRange = RowRange.atMost(new Text("4"));
+      List<String> expected = List.of("1", "2", "3", "4");
+      assertEndRowsForRange(tableName, unboundedStartRange, expected);
+
+      // RowRange.range(null, true, X, false)
+      var exclusiveEndRange = RowRange.lessThan(new Text("4"));
+      expected = List.of("1", "2", "3", "4");
+      assertEndRowsForRange(tableName, exclusiveEndRange, expected);
+
+      // RowRange.range(X, true, null, true)
+      var unboundedEndRange = RowRange.atLeast(new Text("6"));
+      expected = List.of("6", "7", "8", "null");
+      assertEndRowsForRange(tableName, unboundedEndRange, expected);
+
+      // RowRange.range(X, false, null, true)
+      var exclusiveStartRangeUnboundedEnd = RowRange.greaterThan(new 
Text("6"));
+      expected = List.of("7", "8", "null");
+      assertEndRowsForRange(tableName, exclusiveStartRangeUnboundedEnd, 
expected);
+
+      // RowRange.range(X, false, Y, true)
+      var exclusiveStartRange = RowRange.openClosed(new Text("4"), new 
Text("6"));
+      expected = List.of("5", "6");
+      assertEndRowsForRange(tableName, exclusiveStartRange, expected);
+
+      // RowRange.range(X, false, Y, false)
+      var exclusiveStartAndEndRange = RowRange.open(new Text("4"), new 
Text("6"));
+      expected = List.of("5", "6");
+      assertEndRowsForRange(tableName, exclusiveStartAndEndRange, expected);
+
+      // RowRange.range(X, true, Y, true)
+      var inclusiveStartRange = RowRange.closed(new Text("4"), new Text("6"));
+      expected = List.of("4", "5", "6");
+      assertEndRowsForRange(tableName, inclusiveStartRange, expected);
+
+      // RowRange.range(X, true, Y, false)
+      var inclusiveStartExclusiveEndRange = RowRange.closedOpen(new Text("4"), 
new Text("6"));
+      expected = List.of("4", "5", "6");
+      assertEndRowsForRange(tableName, inclusiveStartExclusiveEndRange, 
expected);
+
+      var fileFieldMissingRange = List.of(RowRange.closed(new Text("2"), new 
Text("4")));
+      try (var tablets = 
accumuloClient.tableOperations().getTabletInformation(tableName,
+          fileFieldMissingRange, TabletInformation.Field.LOCATION)) {
+        tablets.forEach(ti -> assertThrows(IllegalStateException.class, 
ti::getNumFiles));
+      }
+
+      var overlappingRange = RowRange.closed(new Text("2"), new Text("4"));
+      var overlappingRange2 = RowRange.closed(new Text("3"), new Text("5"));
+      var disjointRange = RowRange.closed(new Text("7"), new Text("8"));
+      try (var tablets = 
accumuloClient.tableOperations().getTabletInformation(tableName,
+          List.of(overlappingRange, overlappingRange2, disjointRange),
+          TabletInformation.Field.LOCATION)) {
+        var tabletIds = tablets.map(TabletInformation::getTabletId).toList();
+        var endRows = 
tabletIds.stream().map(TabletId::getEndRow).map(Text::toString).toList();
+        assertEquals(List.of("2", "3", "4", "5", "7", "8"), endRows);
+      }
+
     } finally {
       accumuloClient.tableOperations().delete(tableName);
     }
diff --git 
a/test/src/main/java/org/apache/accumulo/test/ample/metadata/TestAmple.java 
b/test/src/main/java/org/apache/accumulo/test/ample/metadata/TestAmple.java
index eeb8437a9e..0048d6ca4a 100644
--- a/test/src/main/java/org/apache/accumulo/test/ample/metadata/TestAmple.java
+++ b/test/src/main/java/org/apache/accumulo/test/ample/metadata/TestAmple.java
@@ -20,6 +20,7 @@ package org.apache.accumulo.test.ample.metadata;
 
 import java.time.Duration;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Objects;
@@ -41,7 +42,7 @@ import org.apache.accumulo.core.clientImpl.ClientContext;
 import org.apache.accumulo.core.conf.SiteConfiguration;
 import org.apache.accumulo.core.data.Key;
 import org.apache.accumulo.core.data.Mutation;
-import org.apache.accumulo.core.data.Range;
+import org.apache.accumulo.core.data.RowRange;
 import org.apache.accumulo.core.data.TableId;
 import org.apache.accumulo.core.data.Value;
 import org.apache.accumulo.core.dataImpl.KeyExtent;
@@ -300,7 +301,7 @@ public class TestAmple {
 
     TabletAvailability availability;
     try (var tabletStream = client.tableOperations()
-        .getTabletInformation(SystemTables.METADATA.tableName(), new Range())) 
{
+        .getTabletInformation(SystemTables.METADATA.tableName(), 
List.of(RowRange.all()))) {
       availability = 
tabletStream.map(TabletInformation::getTabletAvailability).distinct()
           .collect(MoreCollectors.onlyElement());
     }
diff --git 
a/test/src/main/java/org/apache/accumulo/test/compaction/ExternalCompaction_1_IT.java
 
b/test/src/main/java/org/apache/accumulo/test/compaction/ExternalCompaction_1_IT.java
index 2c84b7f4a5..264011fc7e 100644
--- 
a/test/src/main/java/org/apache/accumulo/test/compaction/ExternalCompaction_1_IT.java
+++ 
b/test/src/main/java/org/apache/accumulo/test/compaction/ExternalCompaction_1_IT.java
@@ -78,6 +78,7 @@ import org.apache.accumulo.core.data.Key;
 import org.apache.accumulo.core.data.Mutation;
 import org.apache.accumulo.core.data.Range;
 import org.apache.accumulo.core.data.ResourceGroupId;
+import org.apache.accumulo.core.data.RowRange;
 import org.apache.accumulo.core.data.TableId;
 import org.apache.accumulo.core.data.TabletId;
 import org.apache.accumulo.core.data.Value;
@@ -535,7 +536,8 @@ public class ExternalCompaction_1_IT extends 
SharedMiniClusterBase {
 
       List<TabletId> tabletIds;
       // start a compaction on each tablet
-      try (var tablets = client.tableOperations().getTabletInformation(table1, 
new Range())) {
+      try (var tablets =
+          client.tableOperations().getTabletInformation(table1, 
List.of(RowRange.all()))) {
         tabletIds = 
tablets.map(TabletInformation::getTabletId).collect(Collectors.toList());
       }
       // compact the even tablet with a modulus filter of 2
diff --git a/test/src/main/java/org/apache/accumulo/test/fate/FateTestUtil.java 
b/test/src/main/java/org/apache/accumulo/test/fate/FateTestUtil.java
index cdedec1fa2..afab29dcfe 100644
--- a/test/src/main/java/org/apache/accumulo/test/fate/FateTestUtil.java
+++ b/test/src/main/java/org/apache/accumulo/test/fate/FateTestUtil.java
@@ -22,6 +22,7 @@ import static 
org.apache.accumulo.harness.AccumuloITBase.ZOOKEEPER_TESTING_SERVE
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
 import java.io.File;
+import java.util.List;
 import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
 import java.util.stream.Collectors;
@@ -33,7 +34,7 @@ import 
org.apache.accumulo.core.client.admin.TabletInformation;
 import org.apache.accumulo.core.clientImpl.ClientContext;
 import org.apache.accumulo.core.conf.ConfigurationCopy;
 import org.apache.accumulo.core.conf.Property;
-import org.apache.accumulo.core.data.Range;
+import org.apache.accumulo.core.data.RowRange;
 import org.apache.accumulo.core.fate.Fate;
 import org.apache.accumulo.core.fate.FateId;
 import org.apache.accumulo.core.fate.FateKey;
@@ -64,8 +65,8 @@ public class FateTestUtil {
         
client.tableOperations().getTableProperties(SystemTables.FATE.tableName());
 
     TabletAvailability availability;
-    try (var tabletStream =
-        
client.tableOperations().getTabletInformation(SystemTables.FATE.tableName(), 
new Range())) {
+    try (var tabletStream = client.tableOperations()
+        .getTabletInformation(SystemTables.FATE.tableName(), 
List.of(RowRange.all()))) {
       availability = 
tabletStream.map(TabletInformation::getTabletAvailability).distinct()
           .collect(MoreCollectors.onlyElement());
     }
diff --git 
a/test/src/main/java/org/apache/accumulo/test/functional/AddSplitIT_SimpleSuite.java
 
b/test/src/main/java/org/apache/accumulo/test/functional/AddSplitIT_SimpleSuite.java
index d36a37a51c..c33c636954 100644
--- 
a/test/src/main/java/org/apache/accumulo/test/functional/AddSplitIT_SimpleSuite.java
+++ 
b/test/src/main/java/org/apache/accumulo/test/functional/AddSplitIT_SimpleSuite.java
@@ -27,6 +27,7 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map.Entry;
 import java.util.NavigableMap;
 import java.util.Optional;
@@ -50,7 +51,7 @@ import 
org.apache.accumulo.core.client.admin.TabletMergeabilityInfo;
 import org.apache.accumulo.core.clientImpl.TabletMergeabilityUtil;
 import org.apache.accumulo.core.data.Key;
 import org.apache.accumulo.core.data.Mutation;
-import org.apache.accumulo.core.data.Range;
+import org.apache.accumulo.core.data.RowRange;
 import org.apache.accumulo.core.data.TableId;
 import org.apache.accumulo.core.data.Value;
 import org.apache.accumulo.core.metadata.schema.TabletsMetadata;
@@ -205,14 +206,16 @@ public class AddSplitIT_SimpleSuite extends 
SharedMiniClusterBase {
       var split = new Text(String.format("%09d", 777));
       splits.put(split, TabletMergeability.after(Duration.ofMinutes(5)));
 
-      var originalTmi = c.tableOperations().getTabletInformation(tableName, 
new Range(split))
-          .findFirst().orElseThrow().getTabletMergeabilityInfo();
+      var originalTmi =
+          c.tableOperations().getTabletInformation(tableName, 
List.of(RowRange.closed(split)))
+              .findFirst().orElseThrow().getTabletMergeabilityInfo();
       assertTrue(originalTmi.getElapsed().orElseThrow().toNanos() > 0);
 
       // Update existing with same delay of 5 minutes
       c.tableOperations().putSplits(tableName, splits);
-      var updatedTmi = c.tableOperations().getTabletInformation(tableName, new 
Range(split))
-          .findFirst().orElseThrow().getTabletMergeabilityInfo();
+      var updatedTmi =
+          c.tableOperations().getTabletInformation(tableName, 
List.of(RowRange.closed(split)))
+              .findFirst().orElseThrow().getTabletMergeabilityInfo();
 
       // TabletMergeability setting should be the same but the new elapsed 
time should
       // be different (less time has passed as it was updated with a new 
insertion time)
@@ -244,7 +247,7 @@ public class AddSplitIT_SimpleSuite extends 
SharedMiniClusterBase {
       Thread.sleep(100);
       assertEquals(splits.keySet(), new 
TreeSet<>(c.tableOperations().listSplits(tableName)));
 
-      var tableInfo = c.tableOperations().getTabletInformation(tableName, new 
Range())
+      var tableInfo = c.tableOperations().getTabletInformation(tableName, 
List.of(RowRange.all()))
           .collect(Collectors.toMap(ti -> ti.getTabletId().getEndRow(), 
Function.identity()));
 
       // Set to always
@@ -372,7 +375,7 @@ public class AddSplitIT_SimpleSuite extends 
SharedMiniClusterBase {
   private void verifySplitsWithApi(AccumuloClient c, String tableName,
       SortedMap<Text,TabletMergeability> splits) throws TableNotFoundException 
{
     final Set<Text> addedSplits = new HashSet<>(splits.keySet());
-    c.tableOperations().getTabletInformation(tableName, new 
Range()).forEach(ti -> {
+    c.tableOperations().getTabletInformation(tableName, 
List.of(RowRange.all())).forEach(ti -> {
       var tmInfo = ti.getTabletMergeabilityInfo();
       var split = ti.getTabletId().getEndRow();
       // default tablet should always be set to always
diff --git 
a/test/src/main/java/org/apache/accumulo/test/functional/BulkNewIT.java 
b/test/src/main/java/org/apache/accumulo/test/functional/BulkNewIT.java
index 1c5648a5d9..271a410246 100644
--- a/test/src/main/java/org/apache/accumulo/test/functional/BulkNewIT.java
+++ b/test/src/main/java/org/apache/accumulo/test/functional/BulkNewIT.java
@@ -82,6 +82,7 @@ import org.apache.accumulo.core.data.LoadPlan;
 import org.apache.accumulo.core.data.LoadPlan.RangeType;
 import org.apache.accumulo.core.data.Mutation;
 import org.apache.accumulo.core.data.Range;
+import org.apache.accumulo.core.data.RowRange;
 import org.apache.accumulo.core.data.TableId;
 import org.apache.accumulo.core.data.Value;
 import org.apache.accumulo.core.data.constraints.Constraint;
@@ -1272,7 +1273,8 @@ public class BulkNewIT extends SharedMiniClusterBase {
    */
   private static Map<String,TabletAvailability> 
getTabletAvailabilities(AccumuloClient c,
       String tableName) throws TableNotFoundException {
-    try (var tabletsInfo = c.tableOperations().getTabletInformation(tableName, 
new Range())) {
+    try (var tabletsInfo =
+        c.tableOperations().getTabletInformation(tableName, 
List.of(RowRange.all()))) {
       return tabletsInfo.collect(Collectors.toMap(ti -> {
         var er = ti.getTabletId().getEndRow();
         return er == null ? "NULL" : er.toString();
diff --git 
a/test/src/main/java/org/apache/accumulo/test/functional/SplitMillionIT.java 
b/test/src/main/java/org/apache/accumulo/test/functional/SplitMillionIT.java
index 38479a5eb4..4bf4a3d451 100644
--- a/test/src/main/java/org/apache/accumulo/test/functional/SplitMillionIT.java
+++ b/test/src/main/java/org/apache/accumulo/test/functional/SplitMillionIT.java
@@ -42,6 +42,7 @@ import org.apache.accumulo.core.data.ByteSequence;
 import org.apache.accumulo.core.data.Key;
 import org.apache.accumulo.core.data.Mutation;
 import org.apache.accumulo.core.data.Range;
+import org.apache.accumulo.core.data.RowRange;
 import org.apache.accumulo.core.data.TableId;
 import org.apache.accumulo.core.data.Value;
 import org.apache.accumulo.core.iterators.Filter;
@@ -153,7 +154,7 @@ public class SplitMillionIT extends ConfigurableMacBase {
       long count;
       t1 = System.currentTimeMillis();
       try (var tabletInformation =
-          c.tableOperations().getTabletInformation(tableName, new Range())) {
+          c.tableOperations().getTabletInformation(tableName, 
List.of(RowRange.all()))) {
         count = tabletInformation.count();
       }
       t2 = System.currentTimeMillis();
diff --git 
a/test/src/main/java/org/apache/accumulo/test/functional/TabletAvailabilityIT.java
 
b/test/src/main/java/org/apache/accumulo/test/functional/TabletAvailabilityIT.java
index b8e1e4c288..6dbb58f21a 100644
--- 
a/test/src/main/java/org/apache/accumulo/test/functional/TabletAvailabilityIT.java
+++ 
b/test/src/main/java/org/apache/accumulo/test/functional/TabletAvailabilityIT.java
@@ -44,6 +44,7 @@ import 
org.apache.accumulo.core.client.admin.NewTableConfiguration;
 import org.apache.accumulo.core.client.admin.TabletAvailability;
 import org.apache.accumulo.core.data.Mutation;
 import org.apache.accumulo.core.data.Range;
+import org.apache.accumulo.core.data.RowRange;
 import org.apache.accumulo.core.metadata.SystemTables;
 import org.apache.accumulo.harness.AccumuloClusterHarness;
 import org.apache.hadoop.io.Text;
@@ -104,7 +105,7 @@ public class TabletAvailabilityIT extends 
AccumuloClusterHarness {
 
       // ensure tablet availability is as expected
       SortedMap<String,TabletAvailability> availabilitesSeen = new TreeMap<>();
-      client.tableOperations().getTabletInformation(table, new 
Range()).forEach(ti -> {
+      client.tableOperations().getTabletInformation(table, 
List.of(RowRange.all())).forEach(ti -> {
         if (ti.getTabletId().getEndRow() != null) {
           availabilitesSeen.put(ti.getTabletId().getEndRow().toString(),
               ti.getTabletAvailability());

Reply via email to