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

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


The following commit(s) were added to refs/heads/elasticity by this push:
     new 6596c5c493 implements setting time for hosted tablets (#4054)
6596c5c493 is described below

commit 6596c5c4935b9e5c7faf6ad6a61c118ed67c099d
Author: Keith Turner <ktur...@apache.org>
AuthorDate: Wed Dec 13 09:05:17 2023 -0500

    implements setting time for hosted tablets (#4054)
    
    Updates the bulk load code to support setting time for hosted tablets.
    There is still work to do to persist the changes. If tablet is unloaded
    uncleanly it may loose the bulk import timestamp updates.
    
    Will make the changes for persisting in a follow on commit.
---
 .../thrift/TabletServerClientService.java          | 1369 ++++++++++++++++++++
 core/src/main/thrift/tabletserver.thrift           |    7 +
 .../tableOps/bulkVer2/CleanUpBulkImport.java       |    8 +-
 .../manager/tableOps/bulkVer2/LoadFiles.java       |  165 ++-
 .../accumulo/tserver/TabletClientHandler.java      |   24 +
 .../org/apache/accumulo/tserver/tablet/Tablet.java |   17 +
 .../apache/accumulo/test/ScanConsistencyIT.java    |    2 -
 .../apache/accumulo/test/functional/BulkNewIT.java |   78 +-
 .../accumulo/test/performance/NullTserver.java     |    6 +
 9 files changed, 1641 insertions(+), 35 deletions(-)

diff --git 
a/core/src/main/thrift-gen-java/org/apache/accumulo/core/tabletserver/thrift/TabletServerClientService.java
 
b/core/src/main/thrift-gen-java/org/apache/accumulo/core/tabletserver/thrift/TabletServerClientService.java
index 20fd406ada..9eb4e3ea7e 100644
--- 
a/core/src/main/thrift-gen-java/org/apache/accumulo/core/tabletserver/thrift/TabletServerClientService.java
+++ 
b/core/src/main/thrift-gen-java/org/apache/accumulo/core/tabletserver/thrift/TabletServerClientService.java
@@ -57,6 +57,8 @@ public class TabletServerClientService {
 
     public java.util.List<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent> 
refreshTablets(org.apache.accumulo.core.clientImpl.thrift.TInfo tinfo, 
org.apache.accumulo.core.securityImpl.thrift.TCredentials credentials, 
java.util.List<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent> 
tabletsToRefresh) throws org.apache.thrift.TException;
 
+    public 
java.util.Map<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent,java.lang.Long>
 allocateTimestamps(org.apache.accumulo.core.clientImpl.thrift.TInfo tinfo, 
org.apache.accumulo.core.securityImpl.thrift.TCredentials credentials, 
java.util.List<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent> tablets, 
int numStamps) throws org.apache.thrift.TException;
+
   }
 
   public interface AsyncIface {
@@ -89,6 +91,8 @@ public class TabletServerClientService {
 
     public void 
refreshTablets(org.apache.accumulo.core.clientImpl.thrift.TInfo tinfo, 
org.apache.accumulo.core.securityImpl.thrift.TCredentials credentials, 
java.util.List<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent> 
tabletsToRefresh, 
org.apache.thrift.async.AsyncMethodCallback<java.util.List<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent>>
 resultHandler) throws org.apache.thrift.TException;
 
+    public void 
allocateTimestamps(org.apache.accumulo.core.clientImpl.thrift.TInfo tinfo, 
org.apache.accumulo.core.securityImpl.thrift.TCredentials credentials, 
java.util.List<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent> tablets, 
int numStamps, 
org.apache.thrift.async.AsyncMethodCallback<java.util.Map<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent,java.lang.Long>>
 resultHandler) throws org.apache.thrift.TException;
+
   }
 
   public static class Client extends org.apache.thrift.TServiceClient 
implements Iface {
@@ -472,6 +476,33 @@ public class TabletServerClientService {
       throw new 
org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT,
 "refreshTablets failed: unknown result");
     }
 
+    @Override
+    public 
java.util.Map<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent,java.lang.Long>
 allocateTimestamps(org.apache.accumulo.core.clientImpl.thrift.TInfo tinfo, 
org.apache.accumulo.core.securityImpl.thrift.TCredentials credentials, 
java.util.List<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent> tablets, 
int numStamps) throws org.apache.thrift.TException
+    {
+      send_allocateTimestamps(tinfo, credentials, tablets, numStamps);
+      return recv_allocateTimestamps();
+    }
+
+    public void 
send_allocateTimestamps(org.apache.accumulo.core.clientImpl.thrift.TInfo tinfo, 
org.apache.accumulo.core.securityImpl.thrift.TCredentials credentials, 
java.util.List<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent> tablets, 
int numStamps) throws org.apache.thrift.TException
+    {
+      allocateTimestamps_args args = new allocateTimestamps_args();
+      args.setTinfo(tinfo);
+      args.setCredentials(credentials);
+      args.setTablets(tablets);
+      args.setNumStamps(numStamps);
+      sendBase("allocateTimestamps", args);
+    }
+
+    public 
java.util.Map<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent,java.lang.Long>
 recv_allocateTimestamps() throws org.apache.thrift.TException
+    {
+      allocateTimestamps_result result = new allocateTimestamps_result();
+      receiveBase(result, "allocateTimestamps");
+      if (result.isSetSuccess()) {
+        return result.success;
+      }
+      throw new 
org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT,
 "allocateTimestamps failed: unknown result");
+    }
+
   }
   public static class AsyncClient extends org.apache.thrift.async.TAsyncClient 
implements AsyncIface {
     public static class Factory implements 
org.apache.thrift.async.TAsyncClientFactory<AsyncClient> {
@@ -1069,6 +1100,50 @@ public class TabletServerClientService {
       }
     }
 
+    @Override
+    public void 
allocateTimestamps(org.apache.accumulo.core.clientImpl.thrift.TInfo tinfo, 
org.apache.accumulo.core.securityImpl.thrift.TCredentials credentials, 
java.util.List<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent> tablets, 
int numStamps, 
org.apache.thrift.async.AsyncMethodCallback<java.util.Map<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent,java.lang.Long>>
 resultHandler) throws org.apache.thrift.TException {
+      checkReady();
+      allocateTimestamps_call method_call = new allocateTimestamps_call(tinfo, 
credentials, tablets, numStamps, resultHandler, this, ___protocolFactory, 
___transport);
+      this.___currentMethod = method_call;
+      ___manager.call(method_call);
+    }
+
+    public static class allocateTimestamps_call extends 
org.apache.thrift.async.TAsyncMethodCall<java.util.Map<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent,java.lang.Long>>
 {
+      private org.apache.accumulo.core.clientImpl.thrift.TInfo tinfo;
+      private org.apache.accumulo.core.securityImpl.thrift.TCredentials 
credentials;
+      private 
java.util.List<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent> tablets;
+      private int numStamps;
+      public 
allocateTimestamps_call(org.apache.accumulo.core.clientImpl.thrift.TInfo tinfo, 
org.apache.accumulo.core.securityImpl.thrift.TCredentials credentials, 
java.util.List<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent> tablets, 
int numStamps, 
org.apache.thrift.async.AsyncMethodCallback<java.util.Map<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent,java.lang.Long>>
 resultHandler, org.apache.thrift.async.TAsyncClient client, 
org.apache.thrift.protocol.TProtocolFactory proto [...]
+        super(client, protocolFactory, transport, resultHandler, false);
+        this.tinfo = tinfo;
+        this.credentials = credentials;
+        this.tablets = tablets;
+        this.numStamps = numStamps;
+      }
+
+      @Override
+      public void write_args(org.apache.thrift.protocol.TProtocol prot) throws 
org.apache.thrift.TException {
+        prot.writeMessageBegin(new 
org.apache.thrift.protocol.TMessage("allocateTimestamps", 
org.apache.thrift.protocol.TMessageType.CALL, 0));
+        allocateTimestamps_args args = new allocateTimestamps_args();
+        args.setTinfo(tinfo);
+        args.setCredentials(credentials);
+        args.setTablets(tablets);
+        args.setNumStamps(numStamps);
+        args.write(prot);
+        prot.writeMessageEnd();
+      }
+
+      @Override
+      public 
java.util.Map<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent,java.lang.Long>
 getResult() throws org.apache.thrift.TException {
+        if (getState() != 
org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) {
+          throw new java.lang.IllegalStateException("Method call not 
finished!");
+        }
+        org.apache.thrift.transport.TMemoryInputTransport memoryTransport = 
new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array());
+        org.apache.thrift.protocol.TProtocol prot = 
client.getProtocolFactory().getProtocol(memoryTransport);
+        return (new Client(prot)).recv_allocateTimestamps();
+      }
+    }
+
   }
 
   public static class Processor<I extends Iface> extends 
org.apache.thrift.TBaseProcessor<I> implements org.apache.thrift.TProcessor {
@@ -1096,6 +1171,7 @@ public class TabletServerClientService {
       processMap.put("startGetSummariesFromFiles", new 
startGetSummariesFromFiles());
       processMap.put("contiuneGetSummaries", new contiuneGetSummaries());
       processMap.put("refreshTablets", new refreshTablets());
+      processMap.put("allocateTimestamps", new allocateTimestamps());
       return processMap;
     }
 
@@ -1526,6 +1602,34 @@ public class TabletServerClientService {
       }
     }
 
+    public static class allocateTimestamps<I extends Iface> extends 
org.apache.thrift.ProcessFunction<I, allocateTimestamps_args> {
+      public allocateTimestamps() {
+        super("allocateTimestamps");
+      }
+
+      @Override
+      public allocateTimestamps_args getEmptyArgsInstance() {
+        return new allocateTimestamps_args();
+      }
+
+      @Override
+      protected boolean isOneway() {
+        return false;
+      }
+
+      @Override
+      protected boolean rethrowUnhandledExceptions() {
+        return false;
+      }
+
+      @Override
+      public allocateTimestamps_result getResult(I iface, 
allocateTimestamps_args args) throws org.apache.thrift.TException {
+        allocateTimestamps_result result = new allocateTimestamps_result();
+        result.success = iface.allocateTimestamps(args.tinfo, 
args.credentials, args.tablets, args.numStamps);
+        return result;
+      }
+    }
+
   }
 
   public static class AsyncProcessor<I extends AsyncIface> extends 
org.apache.thrift.TBaseAsyncProcessor<I> {
@@ -1553,6 +1657,7 @@ public class TabletServerClientService {
       processMap.put("startGetSummariesFromFiles", new 
startGetSummariesFromFiles());
       processMap.put("contiuneGetSummaries", new contiuneGetSummaries());
       processMap.put("refreshTablets", new refreshTablets());
+      processMap.put("allocateTimestamps", new allocateTimestamps());
       return processMap;
     }
 
@@ -2452,6 +2557,73 @@ public class TabletServerClientService {
       }
     }
 
+    public static class allocateTimestamps<I extends AsyncIface> extends 
org.apache.thrift.AsyncProcessFunction<I, allocateTimestamps_args, 
java.util.Map<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent,java.lang.Long>>
 {
+      public allocateTimestamps() {
+        super("allocateTimestamps");
+      }
+
+      @Override
+      public allocateTimestamps_args getEmptyArgsInstance() {
+        return new allocateTimestamps_args();
+      }
+
+      @Override
+      public 
org.apache.thrift.async.AsyncMethodCallback<java.util.Map<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent,java.lang.Long>>
 getResultHandler(final 
org.apache.thrift.server.AbstractNonblockingServer.AsyncFrameBuffer fb, final 
int seqid) {
+        final org.apache.thrift.AsyncProcessFunction fcall = this;
+        return new 
org.apache.thrift.async.AsyncMethodCallback<java.util.Map<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent,java.lang.Long>>()
 { 
+          @Override
+          public void 
onComplete(java.util.Map<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent,java.lang.Long>
 o) {
+            allocateTimestamps_result result = new allocateTimestamps_result();
+            result.success = o;
+            try {
+              fcall.sendResponse(fb, result, 
org.apache.thrift.protocol.TMessageType.REPLY,seqid);
+            } catch (org.apache.thrift.transport.TTransportException e) {
+              _LOGGER.error("TTransportException writing to internal frame 
buffer", e);
+              fb.close();
+            } catch (java.lang.Exception e) {
+              _LOGGER.error("Exception writing to internal frame buffer", e);
+              onError(e);
+            }
+          }
+          @Override
+          public void onError(java.lang.Exception e) {
+            byte msgType = org.apache.thrift.protocol.TMessageType.REPLY;
+            org.apache.thrift.TSerializable msg;
+            allocateTimestamps_result result = new allocateTimestamps_result();
+            if (e instanceof org.apache.thrift.transport.TTransportException) {
+              _LOGGER.error("TTransportException inside handler", e);
+              fb.close();
+              return;
+            } else if (e instanceof org.apache.thrift.TApplicationException) {
+              _LOGGER.error("TApplicationException inside handler", e);
+              msgType = org.apache.thrift.protocol.TMessageType.EXCEPTION;
+              msg = (org.apache.thrift.TApplicationException)e;
+            } else {
+              _LOGGER.error("Exception inside handler", e);
+              msgType = org.apache.thrift.protocol.TMessageType.EXCEPTION;
+              msg = new 
org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.INTERNAL_ERROR,
 e.getMessage());
+            }
+            try {
+              fcall.sendResponse(fb,msg,msgType,seqid);
+            } catch (java.lang.Exception ex) {
+              _LOGGER.error("Exception writing to internal frame buffer", ex);
+              fb.close();
+            }
+          }
+        };
+      }
+
+      @Override
+      protected boolean isOneway() {
+        return false;
+      }
+
+      @Override
+      public void start(I iface, allocateTimestamps_args args, 
org.apache.thrift.async.AsyncMethodCallback<java.util.Map<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent,java.lang.Long>>
 resultHandler) throws org.apache.thrift.TException {
+        iface.allocateTimestamps(args.tinfo, args.credentials, args.tablets, 
args.numStamps,resultHandler);
+      }
+    }
+
   }
 
   @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"})
@@ -16536,5 +16708,1202 @@ public class TabletServerClientService {
     }
   }
 
+  @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"})
+  public static class allocateTimestamps_args implements 
org.apache.thrift.TBase<allocateTimestamps_args, 
allocateTimestamps_args._Fields>, java.io.Serializable, Cloneable, 
Comparable<allocateTimestamps_args>   {
+    private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new 
org.apache.thrift.protocol.TStruct("allocateTimestamps_args");
+
+    private static final org.apache.thrift.protocol.TField TINFO_FIELD_DESC = 
new org.apache.thrift.protocol.TField("tinfo", 
org.apache.thrift.protocol.TType.STRUCT, (short)1);
+    private static final org.apache.thrift.protocol.TField 
CREDENTIALS_FIELD_DESC = new org.apache.thrift.protocol.TField("credentials", 
org.apache.thrift.protocol.TType.STRUCT, (short)2);
+    private static final org.apache.thrift.protocol.TField TABLETS_FIELD_DESC 
= new org.apache.thrift.protocol.TField("tablets", 
org.apache.thrift.protocol.TType.LIST, (short)3);
+    private static final org.apache.thrift.protocol.TField 
NUM_STAMPS_FIELD_DESC = new org.apache.thrift.protocol.TField("numStamps", 
org.apache.thrift.protocol.TType.I32, (short)4);
+
+    private static final org.apache.thrift.scheme.SchemeFactory 
STANDARD_SCHEME_FACTORY = new allocateTimestamps_argsStandardSchemeFactory();
+    private static final org.apache.thrift.scheme.SchemeFactory 
TUPLE_SCHEME_FACTORY = new allocateTimestamps_argsTupleSchemeFactory();
+
+    public @org.apache.thrift.annotation.Nullable 
org.apache.accumulo.core.clientImpl.thrift.TInfo tinfo; // required
+    public @org.apache.thrift.annotation.Nullable 
org.apache.accumulo.core.securityImpl.thrift.TCredentials credentials; // 
required
+    public @org.apache.thrift.annotation.Nullable 
java.util.List<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent> tablets; // 
required
+    public int numStamps; // required
+
+    /** The set of fields this struct contains, along with convenience methods 
for finding and manipulating them. */
+    public enum _Fields implements org.apache.thrift.TFieldIdEnum {
+      TINFO((short)1, "tinfo"),
+      CREDENTIALS((short)2, "credentials"),
+      TABLETS((short)3, "tablets"),
+      NUM_STAMPS((short)4, "numStamps");
+
+      private static final java.util.Map<java.lang.String, _Fields> byName = 
new java.util.HashMap<java.lang.String, _Fields>();
+
+      static {
+        for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) {
+          byName.put(field.getFieldName(), field);
+        }
+      }
+
+      /**
+       * Find the _Fields constant that matches fieldId, or null if its not 
found.
+       */
+      @org.apache.thrift.annotation.Nullable
+      public static _Fields findByThriftId(int fieldId) {
+        switch(fieldId) {
+          case 1: // TINFO
+            return TINFO;
+          case 2: // CREDENTIALS
+            return CREDENTIALS;
+          case 3: // TABLETS
+            return TABLETS;
+          case 4: // NUM_STAMPS
+            return NUM_STAMPS;
+          default:
+            return null;
+        }
+      }
+
+      /**
+       * Find the _Fields constant that matches fieldId, throwing an exception
+       * if it is not found.
+       */
+      public static _Fields findByThriftIdOrThrow(int fieldId) {
+        _Fields fields = findByThriftId(fieldId);
+        if (fields == null) throw new 
java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!");
+        return fields;
+      }
+
+      /**
+       * Find the _Fields constant that matches name, or null if its not found.
+       */
+      @org.apache.thrift.annotation.Nullable
+      public static _Fields findByName(java.lang.String name) {
+        return byName.get(name);
+      }
+
+      private final short _thriftId;
+      private final java.lang.String _fieldName;
+
+      _Fields(short thriftId, java.lang.String fieldName) {
+        _thriftId = thriftId;
+        _fieldName = fieldName;
+      }
+
+      @Override
+      public short getThriftFieldId() {
+        return _thriftId;
+      }
+
+      @Override
+      public java.lang.String getFieldName() {
+        return _fieldName;
+      }
+    }
+
+    // isset id assignments
+    private static final int __NUMSTAMPS_ISSET_ID = 0;
+    private byte __isset_bitfield = 0;
+    public static final java.util.Map<_Fields, 
org.apache.thrift.meta_data.FieldMetaData> metaDataMap;
+    static {
+      java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap 
= new java.util.EnumMap<_Fields, 
org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);
+      tmpMap.put(_Fields.TINFO, new 
org.apache.thrift.meta_data.FieldMetaData("tinfo", 
org.apache.thrift.TFieldRequirementType.DEFAULT, 
+          new 
org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT,
 org.apache.accumulo.core.clientImpl.thrift.TInfo.class)));
+      tmpMap.put(_Fields.CREDENTIALS, new 
org.apache.thrift.meta_data.FieldMetaData("credentials", 
org.apache.thrift.TFieldRequirementType.DEFAULT, 
+          new 
org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT,
 org.apache.accumulo.core.securityImpl.thrift.TCredentials.class)));
+      tmpMap.put(_Fields.TABLETS, new 
org.apache.thrift.meta_data.FieldMetaData("tablets", 
org.apache.thrift.TFieldRequirementType.DEFAULT, 
+          new 
org.apache.thrift.meta_data.ListMetaData(org.apache.thrift.protocol.TType.LIST, 
+              new 
org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT,
 org.apache.accumulo.core.dataImpl.thrift.TKeyExtent.class))));
+      tmpMap.put(_Fields.NUM_STAMPS, new 
org.apache.thrift.meta_data.FieldMetaData("numStamps", 
org.apache.thrift.TFieldRequirementType.DEFAULT, 
+          new 
org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I32)));
+      metaDataMap = java.util.Collections.unmodifiableMap(tmpMap);
+      
org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(allocateTimestamps_args.class,
 metaDataMap);
+    }
+
+    public allocateTimestamps_args() {
+    }
+
+    public allocateTimestamps_args(
+      org.apache.accumulo.core.clientImpl.thrift.TInfo tinfo,
+      org.apache.accumulo.core.securityImpl.thrift.TCredentials credentials,
+      java.util.List<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent> 
tablets,
+      int numStamps)
+    {
+      this();
+      this.tinfo = tinfo;
+      this.credentials = credentials;
+      this.tablets = tablets;
+      this.numStamps = numStamps;
+      setNumStampsIsSet(true);
+    }
+
+    /**
+     * Performs a deep copy on <i>other</i>.
+     */
+    public allocateTimestamps_args(allocateTimestamps_args other) {
+      __isset_bitfield = other.__isset_bitfield;
+      if (other.isSetTinfo()) {
+        this.tinfo = new 
org.apache.accumulo.core.clientImpl.thrift.TInfo(other.tinfo);
+      }
+      if (other.isSetCredentials()) {
+        this.credentials = new 
org.apache.accumulo.core.securityImpl.thrift.TCredentials(other.credentials);
+      }
+      if (other.isSetTablets()) {
+        java.util.List<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent> 
__this__tablets = new 
java.util.ArrayList<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent>(other.tablets.size());
+        for (org.apache.accumulo.core.dataImpl.thrift.TKeyExtent other_element 
: other.tablets) {
+          __this__tablets.add(new 
org.apache.accumulo.core.dataImpl.thrift.TKeyExtent(other_element));
+        }
+        this.tablets = __this__tablets;
+      }
+      this.numStamps = other.numStamps;
+    }
+
+    @Override
+    public allocateTimestamps_args deepCopy() {
+      return new allocateTimestamps_args(this);
+    }
+
+    @Override
+    public void clear() {
+      this.tinfo = null;
+      this.credentials = null;
+      this.tablets = null;
+      setNumStampsIsSet(false);
+      this.numStamps = 0;
+    }
+
+    @org.apache.thrift.annotation.Nullable
+    public org.apache.accumulo.core.clientImpl.thrift.TInfo getTinfo() {
+      return this.tinfo;
+    }
+
+    public allocateTimestamps_args 
setTinfo(@org.apache.thrift.annotation.Nullable 
org.apache.accumulo.core.clientImpl.thrift.TInfo tinfo) {
+      this.tinfo = tinfo;
+      return this;
+    }
+
+    public void unsetTinfo() {
+      this.tinfo = null;
+    }
+
+    /** Returns true if field tinfo is set (has been assigned a value) and 
false otherwise */
+    public boolean isSetTinfo() {
+      return this.tinfo != null;
+    }
+
+    public void setTinfoIsSet(boolean value) {
+      if (!value) {
+        this.tinfo = null;
+      }
+    }
+
+    @org.apache.thrift.annotation.Nullable
+    public org.apache.accumulo.core.securityImpl.thrift.TCredentials 
getCredentials() {
+      return this.credentials;
+    }
+
+    public allocateTimestamps_args 
setCredentials(@org.apache.thrift.annotation.Nullable 
org.apache.accumulo.core.securityImpl.thrift.TCredentials credentials) {
+      this.credentials = credentials;
+      return this;
+    }
+
+    public void unsetCredentials() {
+      this.credentials = null;
+    }
+
+    /** Returns true if field credentials is set (has been assigned a value) 
and false otherwise */
+    public boolean isSetCredentials() {
+      return this.credentials != null;
+    }
+
+    public void setCredentialsIsSet(boolean value) {
+      if (!value) {
+        this.credentials = null;
+      }
+    }
+
+    public int getTabletsSize() {
+      return (this.tablets == null) ? 0 : this.tablets.size();
+    }
+
+    @org.apache.thrift.annotation.Nullable
+    public 
java.util.Iterator<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent> 
getTabletsIterator() {
+      return (this.tablets == null) ? null : this.tablets.iterator();
+    }
+
+    public void 
addToTablets(org.apache.accumulo.core.dataImpl.thrift.TKeyExtent elem) {
+      if (this.tablets == null) {
+        this.tablets = new 
java.util.ArrayList<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent>();
+      }
+      this.tablets.add(elem);
+    }
+
+    @org.apache.thrift.annotation.Nullable
+    public java.util.List<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent> 
getTablets() {
+      return this.tablets;
+    }
+
+    public allocateTimestamps_args 
setTablets(@org.apache.thrift.annotation.Nullable 
java.util.List<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent> tablets) {
+      this.tablets = tablets;
+      return this;
+    }
+
+    public void unsetTablets() {
+      this.tablets = null;
+    }
+
+    /** Returns true if field tablets is set (has been assigned a value) and 
false otherwise */
+    public boolean isSetTablets() {
+      return this.tablets != null;
+    }
+
+    public void setTabletsIsSet(boolean value) {
+      if (!value) {
+        this.tablets = null;
+      }
+    }
+
+    public int getNumStamps() {
+      return this.numStamps;
+    }
+
+    public allocateTimestamps_args setNumStamps(int numStamps) {
+      this.numStamps = numStamps;
+      setNumStampsIsSet(true);
+      return this;
+    }
+
+    public void unsetNumStamps() {
+      __isset_bitfield = 
org.apache.thrift.EncodingUtils.clearBit(__isset_bitfield, 
__NUMSTAMPS_ISSET_ID);
+    }
+
+    /** Returns true if field numStamps is set (has been assigned a value) and 
false otherwise */
+    public boolean isSetNumStamps() {
+      return org.apache.thrift.EncodingUtils.testBit(__isset_bitfield, 
__NUMSTAMPS_ISSET_ID);
+    }
+
+    public void setNumStampsIsSet(boolean value) {
+      __isset_bitfield = 
org.apache.thrift.EncodingUtils.setBit(__isset_bitfield, __NUMSTAMPS_ISSET_ID, 
value);
+    }
+
+    @Override
+    public void setFieldValue(_Fields field, 
@org.apache.thrift.annotation.Nullable java.lang.Object value) {
+      switch (field) {
+      case TINFO:
+        if (value == null) {
+          unsetTinfo();
+        } else {
+          setTinfo((org.apache.accumulo.core.clientImpl.thrift.TInfo)value);
+        }
+        break;
+
+      case CREDENTIALS:
+        if (value == null) {
+          unsetCredentials();
+        } else {
+          
setCredentials((org.apache.accumulo.core.securityImpl.thrift.TCredentials)value);
+        }
+        break;
+
+      case TABLETS:
+        if (value == null) {
+          unsetTablets();
+        } else {
+          
setTablets((java.util.List<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent>)value);
+        }
+        break;
+
+      case NUM_STAMPS:
+        if (value == null) {
+          unsetNumStamps();
+        } else {
+          setNumStamps((java.lang.Integer)value);
+        }
+        break;
+
+      }
+    }
+
+    @org.apache.thrift.annotation.Nullable
+    @Override
+    public java.lang.Object getFieldValue(_Fields field) {
+      switch (field) {
+      case TINFO:
+        return getTinfo();
+
+      case CREDENTIALS:
+        return getCredentials();
+
+      case TABLETS:
+        return getTablets();
+
+      case NUM_STAMPS:
+        return getNumStamps();
+
+      }
+      throw new java.lang.IllegalStateException();
+    }
+
+    /** Returns true if field corresponding to fieldID is set (has been 
assigned a value) and false otherwise */
+    @Override
+    public boolean isSet(_Fields field) {
+      if (field == null) {
+        throw new java.lang.IllegalArgumentException();
+      }
+
+      switch (field) {
+      case TINFO:
+        return isSetTinfo();
+      case CREDENTIALS:
+        return isSetCredentials();
+      case TABLETS:
+        return isSetTablets();
+      case NUM_STAMPS:
+        return isSetNumStamps();
+      }
+      throw new java.lang.IllegalStateException();
+    }
+
+    @Override
+    public boolean equals(java.lang.Object that) {
+      if (that instanceof allocateTimestamps_args)
+        return this.equals((allocateTimestamps_args)that);
+      return false;
+    }
+
+    public boolean equals(allocateTimestamps_args that) {
+      if (that == null)
+        return false;
+      if (this == that)
+        return true;
+
+      boolean this_present_tinfo = true && this.isSetTinfo();
+      boolean that_present_tinfo = true && that.isSetTinfo();
+      if (this_present_tinfo || that_present_tinfo) {
+        if (!(this_present_tinfo && that_present_tinfo))
+          return false;
+        if (!this.tinfo.equals(that.tinfo))
+          return false;
+      }
+
+      boolean this_present_credentials = true && this.isSetCredentials();
+      boolean that_present_credentials = true && that.isSetCredentials();
+      if (this_present_credentials || that_present_credentials) {
+        if (!(this_present_credentials && that_present_credentials))
+          return false;
+        if (!this.credentials.equals(that.credentials))
+          return false;
+      }
+
+      boolean this_present_tablets = true && this.isSetTablets();
+      boolean that_present_tablets = true && that.isSetTablets();
+      if (this_present_tablets || that_present_tablets) {
+        if (!(this_present_tablets && that_present_tablets))
+          return false;
+        if (!this.tablets.equals(that.tablets))
+          return false;
+      }
+
+      boolean this_present_numStamps = true;
+      boolean that_present_numStamps = true;
+      if (this_present_numStamps || that_present_numStamps) {
+        if (!(this_present_numStamps && that_present_numStamps))
+          return false;
+        if (this.numStamps != that.numStamps)
+          return false;
+      }
+
+      return true;
+    }
+
+    @Override
+    public int hashCode() {
+      int hashCode = 1;
+
+      hashCode = hashCode * 8191 + ((isSetTinfo()) ? 131071 : 524287);
+      if (isSetTinfo())
+        hashCode = hashCode * 8191 + tinfo.hashCode();
+
+      hashCode = hashCode * 8191 + ((isSetCredentials()) ? 131071 : 524287);
+      if (isSetCredentials())
+        hashCode = hashCode * 8191 + credentials.hashCode();
+
+      hashCode = hashCode * 8191 + ((isSetTablets()) ? 131071 : 524287);
+      if (isSetTablets())
+        hashCode = hashCode * 8191 + tablets.hashCode();
+
+      hashCode = hashCode * 8191 + numStamps;
+
+      return hashCode;
+    }
+
+    @Override
+    public int compareTo(allocateTimestamps_args other) {
+      if (!getClass().equals(other.getClass())) {
+        return getClass().getName().compareTo(other.getClass().getName());
+      }
+
+      int lastComparison = 0;
+
+      lastComparison = java.lang.Boolean.compare(isSetTinfo(), 
other.isSetTinfo());
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+      if (isSetTinfo()) {
+        lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.tinfo, 
other.tinfo);
+        if (lastComparison != 0) {
+          return lastComparison;
+        }
+      }
+      lastComparison = java.lang.Boolean.compare(isSetCredentials(), 
other.isSetCredentials());
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+      if (isSetCredentials()) {
+        lastComparison = 
org.apache.thrift.TBaseHelper.compareTo(this.credentials, other.credentials);
+        if (lastComparison != 0) {
+          return lastComparison;
+        }
+      }
+      lastComparison = java.lang.Boolean.compare(isSetTablets(), 
other.isSetTablets());
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+      if (isSetTablets()) {
+        lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.tablets, 
other.tablets);
+        if (lastComparison != 0) {
+          return lastComparison;
+        }
+      }
+      lastComparison = java.lang.Boolean.compare(isSetNumStamps(), 
other.isSetNumStamps());
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+      if (isSetNumStamps()) {
+        lastComparison = 
org.apache.thrift.TBaseHelper.compareTo(this.numStamps, other.numStamps);
+        if (lastComparison != 0) {
+          return lastComparison;
+        }
+      }
+      return 0;
+    }
+
+    @org.apache.thrift.annotation.Nullable
+    @Override
+    public _Fields fieldForId(int fieldId) {
+      return _Fields.findByThriftId(fieldId);
+    }
+
+    @Override
+    public void read(org.apache.thrift.protocol.TProtocol iprot) throws 
org.apache.thrift.TException {
+      scheme(iprot).read(iprot, this);
+    }
+
+    @Override
+    public void write(org.apache.thrift.protocol.TProtocol oprot) throws 
org.apache.thrift.TException {
+      scheme(oprot).write(oprot, this);
+    }
+
+    @Override
+    public java.lang.String toString() {
+      java.lang.StringBuilder sb = new 
java.lang.StringBuilder("allocateTimestamps_args(");
+      boolean first = true;
+
+      sb.append("tinfo:");
+      if (this.tinfo == null) {
+        sb.append("null");
+      } else {
+        sb.append(this.tinfo);
+      }
+      first = false;
+      if (!first) sb.append(", ");
+      sb.append("credentials:");
+      if (this.credentials == null) {
+        sb.append("null");
+      } else {
+        sb.append(this.credentials);
+      }
+      first = false;
+      if (!first) sb.append(", ");
+      sb.append("tablets:");
+      if (this.tablets == null) {
+        sb.append("null");
+      } else {
+        sb.append(this.tablets);
+      }
+      first = false;
+      if (!first) sb.append(", ");
+      sb.append("numStamps:");
+      sb.append(this.numStamps);
+      first = false;
+      sb.append(")");
+      return sb.toString();
+    }
+
+    public void validate() throws org.apache.thrift.TException {
+      // check for required fields
+      // check for sub-struct validity
+      if (tinfo != null) {
+        tinfo.validate();
+      }
+      if (credentials != null) {
+        credentials.validate();
+      }
+    }
+
+    private void writeObject(java.io.ObjectOutputStream out) throws 
java.io.IOException {
+      try {
+        write(new org.apache.thrift.protocol.TCompactProtocol(new 
org.apache.thrift.transport.TIOStreamTransport(out)));
+      } catch (org.apache.thrift.TException te) {
+        throw new java.io.IOException(te);
+      }
+    }
+
+    private void readObject(java.io.ObjectInputStream in) throws 
java.io.IOException, java.lang.ClassNotFoundException {
+      try {
+        // it doesn't seem like you should have to do this, but java 
serialization is wacky, and doesn't call the default constructor.
+        __isset_bitfield = 0;
+        read(new org.apache.thrift.protocol.TCompactProtocol(new 
org.apache.thrift.transport.TIOStreamTransport(in)));
+      } catch (org.apache.thrift.TException te) {
+        throw new java.io.IOException(te);
+      }
+    }
+
+    private static class allocateTimestamps_argsStandardSchemeFactory 
implements org.apache.thrift.scheme.SchemeFactory {
+      @Override
+      public allocateTimestamps_argsStandardScheme getScheme() {
+        return new allocateTimestamps_argsStandardScheme();
+      }
+    }
+
+    private static class allocateTimestamps_argsStandardScheme extends 
org.apache.thrift.scheme.StandardScheme<allocateTimestamps_args> {
+
+      @Override
+      public void read(org.apache.thrift.protocol.TProtocol iprot, 
allocateTimestamps_args struct) throws org.apache.thrift.TException {
+        org.apache.thrift.protocol.TField schemeField;
+        iprot.readStructBegin();
+        while (true)
+        {
+          schemeField = iprot.readFieldBegin();
+          if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { 
+            break;
+          }
+          switch (schemeField.id) {
+            case 1: // TINFO
+              if (schemeField.type == org.apache.thrift.protocol.TType.STRUCT) 
{
+                struct.tinfo = new 
org.apache.accumulo.core.clientImpl.thrift.TInfo();
+                struct.tinfo.read(iprot);
+                struct.setTinfoIsSet(true);
+              } else { 
+                org.apache.thrift.protocol.TProtocolUtil.skip(iprot, 
schemeField.type);
+              }
+              break;
+            case 2: // CREDENTIALS
+              if (schemeField.type == org.apache.thrift.protocol.TType.STRUCT) 
{
+                struct.credentials = new 
org.apache.accumulo.core.securityImpl.thrift.TCredentials();
+                struct.credentials.read(iprot);
+                struct.setCredentialsIsSet(true);
+              } else { 
+                org.apache.thrift.protocol.TProtocolUtil.skip(iprot, 
schemeField.type);
+              }
+              break;
+            case 3: // TABLETS
+              if (schemeField.type == org.apache.thrift.protocol.TType.LIST) {
+                {
+                  org.apache.thrift.protocol.TList _list138 = 
iprot.readListBegin();
+                  struct.tablets = new 
java.util.ArrayList<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent>(_list138.size);
+                  @org.apache.thrift.annotation.Nullable 
org.apache.accumulo.core.dataImpl.thrift.TKeyExtent _elem139;
+                  for (int _i140 = 0; _i140 < _list138.size; ++_i140)
+                  {
+                    _elem139 = new 
org.apache.accumulo.core.dataImpl.thrift.TKeyExtent();
+                    _elem139.read(iprot);
+                    struct.tablets.add(_elem139);
+                  }
+                  iprot.readListEnd();
+                }
+                struct.setTabletsIsSet(true);
+              } else { 
+                org.apache.thrift.protocol.TProtocolUtil.skip(iprot, 
schemeField.type);
+              }
+              break;
+            case 4: // NUM_STAMPS
+              if (schemeField.type == org.apache.thrift.protocol.TType.I32) {
+                struct.numStamps = iprot.readI32();
+                struct.setNumStampsIsSet(true);
+              } else { 
+                org.apache.thrift.protocol.TProtocolUtil.skip(iprot, 
schemeField.type);
+              }
+              break;
+            default:
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, 
schemeField.type);
+          }
+          iprot.readFieldEnd();
+        }
+        iprot.readStructEnd();
+
+        // check for required fields of primitive type, which can't be checked 
in the validate method
+        struct.validate();
+      }
+
+      @Override
+      public void write(org.apache.thrift.protocol.TProtocol oprot, 
allocateTimestamps_args struct) throws org.apache.thrift.TException {
+        struct.validate();
+
+        oprot.writeStructBegin(STRUCT_DESC);
+        if (struct.tinfo != null) {
+          oprot.writeFieldBegin(TINFO_FIELD_DESC);
+          struct.tinfo.write(oprot);
+          oprot.writeFieldEnd();
+        }
+        if (struct.credentials != null) {
+          oprot.writeFieldBegin(CREDENTIALS_FIELD_DESC);
+          struct.credentials.write(oprot);
+          oprot.writeFieldEnd();
+        }
+        if (struct.tablets != null) {
+          oprot.writeFieldBegin(TABLETS_FIELD_DESC);
+          {
+            oprot.writeListBegin(new 
org.apache.thrift.protocol.TList(org.apache.thrift.protocol.TType.STRUCT, 
struct.tablets.size()));
+            for (org.apache.accumulo.core.dataImpl.thrift.TKeyExtent _iter141 
: struct.tablets)
+            {
+              _iter141.write(oprot);
+            }
+            oprot.writeListEnd();
+          }
+          oprot.writeFieldEnd();
+        }
+        oprot.writeFieldBegin(NUM_STAMPS_FIELD_DESC);
+        oprot.writeI32(struct.numStamps);
+        oprot.writeFieldEnd();
+        oprot.writeFieldStop();
+        oprot.writeStructEnd();
+      }
+
+    }
+
+    private static class allocateTimestamps_argsTupleSchemeFactory implements 
org.apache.thrift.scheme.SchemeFactory {
+      @Override
+      public allocateTimestamps_argsTupleScheme getScheme() {
+        return new allocateTimestamps_argsTupleScheme();
+      }
+    }
+
+    private static class allocateTimestamps_argsTupleScheme extends 
org.apache.thrift.scheme.TupleScheme<allocateTimestamps_args> {
+
+      @Override
+      public void write(org.apache.thrift.protocol.TProtocol prot, 
allocateTimestamps_args struct) throws org.apache.thrift.TException {
+        org.apache.thrift.protocol.TTupleProtocol oprot = 
(org.apache.thrift.protocol.TTupleProtocol) prot;
+        java.util.BitSet optionals = new java.util.BitSet();
+        if (struct.isSetTinfo()) {
+          optionals.set(0);
+        }
+        if (struct.isSetCredentials()) {
+          optionals.set(1);
+        }
+        if (struct.isSetTablets()) {
+          optionals.set(2);
+        }
+        if (struct.isSetNumStamps()) {
+          optionals.set(3);
+        }
+        oprot.writeBitSet(optionals, 4);
+        if (struct.isSetTinfo()) {
+          struct.tinfo.write(oprot);
+        }
+        if (struct.isSetCredentials()) {
+          struct.credentials.write(oprot);
+        }
+        if (struct.isSetTablets()) {
+          {
+            oprot.writeI32(struct.tablets.size());
+            for (org.apache.accumulo.core.dataImpl.thrift.TKeyExtent _iter142 
: struct.tablets)
+            {
+              _iter142.write(oprot);
+            }
+          }
+        }
+        if (struct.isSetNumStamps()) {
+          oprot.writeI32(struct.numStamps);
+        }
+      }
+
+      @Override
+      public void read(org.apache.thrift.protocol.TProtocol prot, 
allocateTimestamps_args struct) throws org.apache.thrift.TException {
+        org.apache.thrift.protocol.TTupleProtocol iprot = 
(org.apache.thrift.protocol.TTupleProtocol) prot;
+        java.util.BitSet incoming = iprot.readBitSet(4);
+        if (incoming.get(0)) {
+          struct.tinfo = new 
org.apache.accumulo.core.clientImpl.thrift.TInfo();
+          struct.tinfo.read(iprot);
+          struct.setTinfoIsSet(true);
+        }
+        if (incoming.get(1)) {
+          struct.credentials = new 
org.apache.accumulo.core.securityImpl.thrift.TCredentials();
+          struct.credentials.read(iprot);
+          struct.setCredentialsIsSet(true);
+        }
+        if (incoming.get(2)) {
+          {
+            org.apache.thrift.protocol.TList _list143 = 
iprot.readListBegin(org.apache.thrift.protocol.TType.STRUCT);
+            struct.tablets = new 
java.util.ArrayList<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent>(_list143.size);
+            @org.apache.thrift.annotation.Nullable 
org.apache.accumulo.core.dataImpl.thrift.TKeyExtent _elem144;
+            for (int _i145 = 0; _i145 < _list143.size; ++_i145)
+            {
+              _elem144 = new 
org.apache.accumulo.core.dataImpl.thrift.TKeyExtent();
+              _elem144.read(iprot);
+              struct.tablets.add(_elem144);
+            }
+          }
+          struct.setTabletsIsSet(true);
+        }
+        if (incoming.get(3)) {
+          struct.numStamps = iprot.readI32();
+          struct.setNumStampsIsSet(true);
+        }
+      }
+    }
+
+    private static <S extends org.apache.thrift.scheme.IScheme> S 
scheme(org.apache.thrift.protocol.TProtocol proto) {
+      return 
(org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? 
STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme();
+    }
+  }
+
+  @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"})
+  public static class allocateTimestamps_result implements 
org.apache.thrift.TBase<allocateTimestamps_result, 
allocateTimestamps_result._Fields>, java.io.Serializable, Cloneable, 
Comparable<allocateTimestamps_result>   {
+    private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new 
org.apache.thrift.protocol.TStruct("allocateTimestamps_result");
+
+    private static final org.apache.thrift.protocol.TField SUCCESS_FIELD_DESC 
= new org.apache.thrift.protocol.TField("success", 
org.apache.thrift.protocol.TType.MAP, (short)0);
+
+    private static final org.apache.thrift.scheme.SchemeFactory 
STANDARD_SCHEME_FACTORY = new allocateTimestamps_resultStandardSchemeFactory();
+    private static final org.apache.thrift.scheme.SchemeFactory 
TUPLE_SCHEME_FACTORY = new allocateTimestamps_resultTupleSchemeFactory();
+
+    public @org.apache.thrift.annotation.Nullable 
java.util.Map<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent,java.lang.Long>
 success; // required
+
+    /** The set of fields this struct contains, along with convenience methods 
for finding and manipulating them. */
+    public enum _Fields implements org.apache.thrift.TFieldIdEnum {
+      SUCCESS((short)0, "success");
+
+      private static final java.util.Map<java.lang.String, _Fields> byName = 
new java.util.HashMap<java.lang.String, _Fields>();
+
+      static {
+        for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) {
+          byName.put(field.getFieldName(), field);
+        }
+      }
+
+      /**
+       * Find the _Fields constant that matches fieldId, or null if its not 
found.
+       */
+      @org.apache.thrift.annotation.Nullable
+      public static _Fields findByThriftId(int fieldId) {
+        switch(fieldId) {
+          case 0: // SUCCESS
+            return SUCCESS;
+          default:
+            return null;
+        }
+      }
+
+      /**
+       * Find the _Fields constant that matches fieldId, throwing an exception
+       * if it is not found.
+       */
+      public static _Fields findByThriftIdOrThrow(int fieldId) {
+        _Fields fields = findByThriftId(fieldId);
+        if (fields == null) throw new 
java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!");
+        return fields;
+      }
+
+      /**
+       * Find the _Fields constant that matches name, or null if its not found.
+       */
+      @org.apache.thrift.annotation.Nullable
+      public static _Fields findByName(java.lang.String name) {
+        return byName.get(name);
+      }
+
+      private final short _thriftId;
+      private final java.lang.String _fieldName;
+
+      _Fields(short thriftId, java.lang.String fieldName) {
+        _thriftId = thriftId;
+        _fieldName = fieldName;
+      }
+
+      @Override
+      public short getThriftFieldId() {
+        return _thriftId;
+      }
+
+      @Override
+      public java.lang.String getFieldName() {
+        return _fieldName;
+      }
+    }
+
+    // isset id assignments
+    public static final java.util.Map<_Fields, 
org.apache.thrift.meta_data.FieldMetaData> metaDataMap;
+    static {
+      java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap 
= new java.util.EnumMap<_Fields, 
org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);
+      tmpMap.put(_Fields.SUCCESS, new 
org.apache.thrift.meta_data.FieldMetaData("success", 
org.apache.thrift.TFieldRequirementType.DEFAULT, 
+          new 
org.apache.thrift.meta_data.MapMetaData(org.apache.thrift.protocol.TType.MAP, 
+              new 
org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT,
 org.apache.accumulo.core.dataImpl.thrift.TKeyExtent.class), 
+              new 
org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I64))));
+      metaDataMap = java.util.Collections.unmodifiableMap(tmpMap);
+      
org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(allocateTimestamps_result.class,
 metaDataMap);
+    }
+
+    public allocateTimestamps_result() {
+    }
+
+    public allocateTimestamps_result(
+      
java.util.Map<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent,java.lang.Long>
 success)
+    {
+      this();
+      this.success = success;
+    }
+
+    /**
+     * Performs a deep copy on <i>other</i>.
+     */
+    public allocateTimestamps_result(allocateTimestamps_result other) {
+      if (other.isSetSuccess()) {
+        
java.util.Map<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent,java.lang.Long>
 __this__success = new 
java.util.HashMap<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent,java.lang.Long>(other.success.size());
+        for 
(java.util.Map.Entry<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent, 
java.lang.Long> other_element : other.success.entrySet()) {
+
+          org.apache.accumulo.core.dataImpl.thrift.TKeyExtent 
other_element_key = other_element.getKey();
+          java.lang.Long other_element_value = other_element.getValue();
+
+          org.apache.accumulo.core.dataImpl.thrift.TKeyExtent 
__this__success_copy_key = new 
org.apache.accumulo.core.dataImpl.thrift.TKeyExtent(other_element_key);
+
+          java.lang.Long __this__success_copy_value = other_element_value;
+
+          __this__success.put(__this__success_copy_key, 
__this__success_copy_value);
+        }
+        this.success = __this__success;
+      }
+    }
+
+    @Override
+    public allocateTimestamps_result deepCopy() {
+      return new allocateTimestamps_result(this);
+    }
+
+    @Override
+    public void clear() {
+      this.success = null;
+    }
+
+    public int getSuccessSize() {
+      return (this.success == null) ? 0 : this.success.size();
+    }
+
+    public void 
putToSuccess(org.apache.accumulo.core.dataImpl.thrift.TKeyExtent key, long val) 
{
+      if (this.success == null) {
+        this.success = new 
java.util.HashMap<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent,java.lang.Long>();
+      }
+      this.success.put(key, val);
+    }
+
+    @org.apache.thrift.annotation.Nullable
+    public 
java.util.Map<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent,java.lang.Long>
 getSuccess() {
+      return this.success;
+    }
+
+    public allocateTimestamps_result 
setSuccess(@org.apache.thrift.annotation.Nullable 
java.util.Map<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent,java.lang.Long>
 success) {
+      this.success = success;
+      return this;
+    }
+
+    public void unsetSuccess() {
+      this.success = null;
+    }
+
+    /** Returns true if field success is set (has been assigned a value) and 
false otherwise */
+    public boolean isSetSuccess() {
+      return this.success != null;
+    }
+
+    public void setSuccessIsSet(boolean value) {
+      if (!value) {
+        this.success = null;
+      }
+    }
+
+    @Override
+    public void setFieldValue(_Fields field, 
@org.apache.thrift.annotation.Nullable java.lang.Object value) {
+      switch (field) {
+      case SUCCESS:
+        if (value == null) {
+          unsetSuccess();
+        } else {
+          
setSuccess((java.util.Map<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent,java.lang.Long>)value);
+        }
+        break;
+
+      }
+    }
+
+    @org.apache.thrift.annotation.Nullable
+    @Override
+    public java.lang.Object getFieldValue(_Fields field) {
+      switch (field) {
+      case SUCCESS:
+        return getSuccess();
+
+      }
+      throw new java.lang.IllegalStateException();
+    }
+
+    /** Returns true if field corresponding to fieldID is set (has been 
assigned a value) and false otherwise */
+    @Override
+    public boolean isSet(_Fields field) {
+      if (field == null) {
+        throw new java.lang.IllegalArgumentException();
+      }
+
+      switch (field) {
+      case SUCCESS:
+        return isSetSuccess();
+      }
+      throw new java.lang.IllegalStateException();
+    }
+
+    @Override
+    public boolean equals(java.lang.Object that) {
+      if (that instanceof allocateTimestamps_result)
+        return this.equals((allocateTimestamps_result)that);
+      return false;
+    }
+
+    public boolean equals(allocateTimestamps_result that) {
+      if (that == null)
+        return false;
+      if (this == that)
+        return true;
+
+      boolean this_present_success = true && this.isSetSuccess();
+      boolean that_present_success = true && that.isSetSuccess();
+      if (this_present_success || that_present_success) {
+        if (!(this_present_success && that_present_success))
+          return false;
+        if (!this.success.equals(that.success))
+          return false;
+      }
+
+      return true;
+    }
+
+    @Override
+    public int hashCode() {
+      int hashCode = 1;
+
+      hashCode = hashCode * 8191 + ((isSetSuccess()) ? 131071 : 524287);
+      if (isSetSuccess())
+        hashCode = hashCode * 8191 + success.hashCode();
+
+      return hashCode;
+    }
+
+    @Override
+    public int compareTo(allocateTimestamps_result other) {
+      if (!getClass().equals(other.getClass())) {
+        return getClass().getName().compareTo(other.getClass().getName());
+      }
+
+      int lastComparison = 0;
+
+      lastComparison = java.lang.Boolean.compare(isSetSuccess(), 
other.isSetSuccess());
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+      if (isSetSuccess()) {
+        lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.success, 
other.success);
+        if (lastComparison != 0) {
+          return lastComparison;
+        }
+      }
+      return 0;
+    }
+
+    @org.apache.thrift.annotation.Nullable
+    @Override
+    public _Fields fieldForId(int fieldId) {
+      return _Fields.findByThriftId(fieldId);
+    }
+
+    @Override
+    public void read(org.apache.thrift.protocol.TProtocol iprot) throws 
org.apache.thrift.TException {
+      scheme(iprot).read(iprot, this);
+    }
+
+    public void write(org.apache.thrift.protocol.TProtocol oprot) throws 
org.apache.thrift.TException {
+      scheme(oprot).write(oprot, this);
+      }
+
+    @Override
+    public java.lang.String toString() {
+      java.lang.StringBuilder sb = new 
java.lang.StringBuilder("allocateTimestamps_result(");
+      boolean first = true;
+
+      sb.append("success:");
+      if (this.success == null) {
+        sb.append("null");
+      } else {
+        sb.append(this.success);
+      }
+      first = false;
+      sb.append(")");
+      return sb.toString();
+    }
+
+    public void validate() throws org.apache.thrift.TException {
+      // check for required fields
+      // check for sub-struct validity
+    }
+
+    private void writeObject(java.io.ObjectOutputStream out) throws 
java.io.IOException {
+      try {
+        write(new org.apache.thrift.protocol.TCompactProtocol(new 
org.apache.thrift.transport.TIOStreamTransport(out)));
+      } catch (org.apache.thrift.TException te) {
+        throw new java.io.IOException(te);
+      }
+    }
+
+    private void readObject(java.io.ObjectInputStream in) throws 
java.io.IOException, java.lang.ClassNotFoundException {
+      try {
+        read(new org.apache.thrift.protocol.TCompactProtocol(new 
org.apache.thrift.transport.TIOStreamTransport(in)));
+      } catch (org.apache.thrift.TException te) {
+        throw new java.io.IOException(te);
+      }
+    }
+
+    private static class allocateTimestamps_resultStandardSchemeFactory 
implements org.apache.thrift.scheme.SchemeFactory {
+      @Override
+      public allocateTimestamps_resultStandardScheme getScheme() {
+        return new allocateTimestamps_resultStandardScheme();
+      }
+    }
+
+    private static class allocateTimestamps_resultStandardScheme extends 
org.apache.thrift.scheme.StandardScheme<allocateTimestamps_result> {
+
+      @Override
+      public void read(org.apache.thrift.protocol.TProtocol iprot, 
allocateTimestamps_result struct) throws org.apache.thrift.TException {
+        org.apache.thrift.protocol.TField schemeField;
+        iprot.readStructBegin();
+        while (true)
+        {
+          schemeField = iprot.readFieldBegin();
+          if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { 
+            break;
+          }
+          switch (schemeField.id) {
+            case 0: // SUCCESS
+              if (schemeField.type == org.apache.thrift.protocol.TType.MAP) {
+                {
+                  org.apache.thrift.protocol.TMap _map146 = 
iprot.readMapBegin();
+                  struct.success = new 
java.util.HashMap<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent,java.lang.Long>(2*_map146.size);
+                  @org.apache.thrift.annotation.Nullable 
org.apache.accumulo.core.dataImpl.thrift.TKeyExtent _key147;
+                  long _val148;
+                  for (int _i149 = 0; _i149 < _map146.size; ++_i149)
+                  {
+                    _key147 = new 
org.apache.accumulo.core.dataImpl.thrift.TKeyExtent();
+                    _key147.read(iprot);
+                    _val148 = iprot.readI64();
+                    struct.success.put(_key147, _val148);
+                  }
+                  iprot.readMapEnd();
+                }
+                struct.setSuccessIsSet(true);
+              } else { 
+                org.apache.thrift.protocol.TProtocolUtil.skip(iprot, 
schemeField.type);
+              }
+              break;
+            default:
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, 
schemeField.type);
+          }
+          iprot.readFieldEnd();
+        }
+        iprot.readStructEnd();
+
+        // check for required fields of primitive type, which can't be checked 
in the validate method
+        struct.validate();
+      }
+
+      @Override
+      public void write(org.apache.thrift.protocol.TProtocol oprot, 
allocateTimestamps_result struct) throws org.apache.thrift.TException {
+        struct.validate();
+
+        oprot.writeStructBegin(STRUCT_DESC);
+        if (struct.success != null) {
+          oprot.writeFieldBegin(SUCCESS_FIELD_DESC);
+          {
+            oprot.writeMapBegin(new 
org.apache.thrift.protocol.TMap(org.apache.thrift.protocol.TType.STRUCT, 
org.apache.thrift.protocol.TType.I64, struct.success.size()));
+            for 
(java.util.Map.Entry<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent, 
java.lang.Long> _iter150 : struct.success.entrySet())
+            {
+              _iter150.getKey().write(oprot);
+              oprot.writeI64(_iter150.getValue());
+            }
+            oprot.writeMapEnd();
+          }
+          oprot.writeFieldEnd();
+        }
+        oprot.writeFieldStop();
+        oprot.writeStructEnd();
+      }
+
+    }
+
+    private static class allocateTimestamps_resultTupleSchemeFactory 
implements org.apache.thrift.scheme.SchemeFactory {
+      @Override
+      public allocateTimestamps_resultTupleScheme getScheme() {
+        return new allocateTimestamps_resultTupleScheme();
+      }
+    }
+
+    private static class allocateTimestamps_resultTupleScheme extends 
org.apache.thrift.scheme.TupleScheme<allocateTimestamps_result> {
+
+      @Override
+      public void write(org.apache.thrift.protocol.TProtocol prot, 
allocateTimestamps_result struct) throws org.apache.thrift.TException {
+        org.apache.thrift.protocol.TTupleProtocol oprot = 
(org.apache.thrift.protocol.TTupleProtocol) prot;
+        java.util.BitSet optionals = new java.util.BitSet();
+        if (struct.isSetSuccess()) {
+          optionals.set(0);
+        }
+        oprot.writeBitSet(optionals, 1);
+        if (struct.isSetSuccess()) {
+          {
+            oprot.writeI32(struct.success.size());
+            for 
(java.util.Map.Entry<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent, 
java.lang.Long> _iter151 : struct.success.entrySet())
+            {
+              _iter151.getKey().write(oprot);
+              oprot.writeI64(_iter151.getValue());
+            }
+          }
+        }
+      }
+
+      @Override
+      public void read(org.apache.thrift.protocol.TProtocol prot, 
allocateTimestamps_result struct) throws org.apache.thrift.TException {
+        org.apache.thrift.protocol.TTupleProtocol iprot = 
(org.apache.thrift.protocol.TTupleProtocol) prot;
+        java.util.BitSet incoming = iprot.readBitSet(1);
+        if (incoming.get(0)) {
+          {
+            org.apache.thrift.protocol.TMap _map152 = 
iprot.readMapBegin(org.apache.thrift.protocol.TType.STRUCT, 
org.apache.thrift.protocol.TType.I64); 
+            struct.success = new 
java.util.HashMap<org.apache.accumulo.core.dataImpl.thrift.TKeyExtent,java.lang.Long>(2*_map152.size);
+            @org.apache.thrift.annotation.Nullable 
org.apache.accumulo.core.dataImpl.thrift.TKeyExtent _key153;
+            long _val154;
+            for (int _i155 = 0; _i155 < _map152.size; ++_i155)
+            {
+              _key153 = new 
org.apache.accumulo.core.dataImpl.thrift.TKeyExtent();
+              _key153.read(iprot);
+              _val154 = iprot.readI64();
+              struct.success.put(_key153, _val154);
+            }
+          }
+          struct.setSuccessIsSet(true);
+        }
+      }
+    }
+
+    private static <S extends org.apache.thrift.scheme.IScheme> S 
scheme(org.apache.thrift.protocol.TProtocol proto) {
+      return 
(org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? 
STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme();
+    }
+  }
+
   private static void unusedMethod() {}
 }
diff --git a/core/src/main/thrift/tabletserver.thrift 
b/core/src/main/thrift/tabletserver.thrift
index eb394c95a6..e473b4ad81 100644
--- a/core/src/main/thrift/tabletserver.thrift
+++ b/core/src/main/thrift/tabletserver.thrift
@@ -237,6 +237,13 @@ service TabletServerClientService {
     2:security.TCredentials credentials
     3:list<data.TKeyExtent> tabletsToRefresh
   )
+
+  map<data.TKeyExtent, i64> allocateTimestamps(
+    1:client.TInfo tinfo
+    2:security.TCredentials credentials
+    3:list<data.TKeyExtent> tablets
+    4:i32 numStamps
+  )
 }
 
 typedef i32 TabletID
diff --git 
a/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/bulkVer2/CleanUpBulkImport.java
 
b/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/bulkVer2/CleanUpBulkImport.java
index 0d28058822..ab78cb3ffb 100644
--- 
a/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/bulkVer2/CleanUpBulkImport.java
+++ 
b/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/bulkVer2/CleanUpBulkImport.java
@@ -25,8 +25,10 @@ import static java.util.concurrent.TimeUnit.SECONDS;
 import java.io.IOException;
 import java.util.Collections;
 import java.util.Map;
+import java.util.Optional;
 
 import org.apache.accumulo.core.Constants;
+import org.apache.accumulo.core.data.AbstractId;
 import org.apache.accumulo.core.data.TableId;
 import org.apache.accumulo.core.fate.FateTxId;
 import org.apache.accumulo.core.fate.Repo;
@@ -34,6 +36,7 @@ import org.apache.accumulo.core.gc.ReferenceFile;
 import org.apache.accumulo.core.manager.thrift.BulkImportState;
 import org.apache.accumulo.core.metadata.schema.Ample;
 import org.apache.accumulo.core.metadata.schema.Ample.ConditionalResult.Status;
+import org.apache.accumulo.core.metadata.schema.TabletMetadata;
 import org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType;
 import org.apache.accumulo.core.util.Retry;
 import org.apache.accumulo.manager.Manager;
@@ -122,9 +125,10 @@ public class CleanUpBulkImport extends ManagerRepo {
 
           results.forEach((extent, condResult) -> {
             if (condResult.getStatus() != Status.ACCEPTED) {
-              var metadata = condResult.readMetadata();
+              var metadata = Optional.ofNullable(condResult.readMetadata());
               log.debug("Tablet update failed {} {} {} {} ", 
FateTxId.formatTid(tid), extent,
-                  condResult.getStatus(), metadata.getOperationId());
+                  condResult.getStatus(), 
metadata.map(TabletMetadata::getOperationId)
+                      .map(AbstractId::toString).orElse("tablet is gone"));
             }
           });
 
diff --git 
a/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/bulkVer2/LoadFiles.java
 
b/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/bulkVer2/LoadFiles.java
index 15109b9a44..1d6fe1c6ee 100644
--- 
a/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/bulkVer2/LoadFiles.java
+++ 
b/server/manager/src/main/java/org/apache/accumulo/manager/tableOps/bulkVer2/LoadFiles.java
@@ -22,6 +22,7 @@ import static 
org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType
 import static 
org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.LOCATION;
 import static 
org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.PREV_ROW;
 import static 
org.apache.accumulo.core.metadata.schema.TabletMetadata.ColumnType.TIME;
+import static 
org.apache.accumulo.core.metadata.schema.TabletMetadata.LocationType.CURRENT;
 
 import java.util.ArrayList;
 import java.util.Comparator;
@@ -30,22 +31,31 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 import org.apache.accumulo.core.clientImpl.bulk.Bulk;
 import org.apache.accumulo.core.clientImpl.bulk.Bulk.Files;
 import org.apache.accumulo.core.clientImpl.bulk.BulkSerialize;
 import org.apache.accumulo.core.clientImpl.bulk.LoadMappingIterator;
+import org.apache.accumulo.core.conf.Property;
 import org.apache.accumulo.core.data.TableId;
 import org.apache.accumulo.core.dataImpl.KeyExtent;
+import org.apache.accumulo.core.dataImpl.thrift.TKeyExtent;
 import org.apache.accumulo.core.fate.FateTxId;
 import org.apache.accumulo.core.fate.Repo;
 import org.apache.accumulo.core.manager.thrift.BulkImportState;
 import org.apache.accumulo.core.metadata.ReferencedTabletFile;
+import org.apache.accumulo.core.metadata.StoredTabletFile;
 import org.apache.accumulo.core.metadata.schema.Ample;
 import org.apache.accumulo.core.metadata.schema.Ample.ConditionalResult.Status;
 import org.apache.accumulo.core.metadata.schema.DataFileValue;
 import org.apache.accumulo.core.metadata.schema.TabletMetadata;
 import org.apache.accumulo.core.metadata.schema.TabletsMetadata;
+import org.apache.accumulo.core.rpc.ThriftUtil;
+import org.apache.accumulo.core.rpc.clients.ThriftClientTypes;
+import org.apache.accumulo.core.tabletserver.thrift.TabletServerClientService;
+import org.apache.accumulo.core.trace.TraceUtil;
 import org.apache.accumulo.core.util.PeekingIterator;
 import org.apache.accumulo.manager.Manager;
 import org.apache.accumulo.manager.tableOps.ManagerRepo;
@@ -53,9 +63,12 @@ import org.apache.accumulo.server.fs.VolumeManager;
 import org.apache.accumulo.server.tablets.TabletTime;
 import org.apache.hadoop.fs.Path;
 import org.apache.hadoop.io.Text;
+import org.apache.thrift.TException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.net.HostAndPort;
+
 /**
  * Make asynchronous load calls to each overlapping Tablet. This RepO does its 
work on the isReady
  * and will return a linear sleep value based on the largest number of Tablets 
on a TabletServer.
@@ -97,40 +110,83 @@ class LoadFiles extends ManagerRepo {
     protected Path bulkDir;
     protected Manager manager;
     protected long tid;
+    private String logId;
     protected boolean setTime;
     Ample.ConditionalTabletsMutator conditionalMutator;
 
+    private long skipped = 0;
+
     void start(Path bulkDir, Manager manager, long tid, boolean setTime) 
throws Exception {
       this.bulkDir = bulkDir;
       this.manager = manager;
       this.tid = tid;
+      this.logId = FateTxId.formatTid(tid);
       this.setTime = setTime;
       conditionalMutator = 
manager.getContext().getAmple().conditionallyMutateTablets();
+      this.skipped = 0;
     }
 
     void load(List<TabletMetadata> tablets, Files files) {
 
-      for (TabletMetadata tablet : tablets) {
-        Map<ReferencedTabletFile,DataFileValue> filesToLoad = new HashMap<>();
+      Map<ReferencedTabletFile,Bulk.FileInfo> toLoad = new HashMap<>();
+      for (var fileInfo : files) {
+        toLoad.put(new ReferencedTabletFile(new Path(bulkDir, 
fileInfo.getFileName())), fileInfo);
+      }
 
-        if (setTime && tablet.getLocation() != null) {
-          throw new IllegalStateException("Setting time on hosted tablet is 
not implemented");
+      // remove any tablets that already have loaded flags
+      tablets = tablets.stream().filter(tabletMeta -> {
+        Set<ReferencedTabletFile> loaded = 
tabletMeta.getLoaded().keySet().stream()
+            .map(StoredTabletFile::getTabletFile).collect(Collectors.toSet());
+        return !loaded.containsAll(toLoad.keySet());
+      }).collect(Collectors.toList());
+
+      // timestamps from tablets that are hosted on a tablet server
+      Map<KeyExtent,Long> hostedTimestamps;
+      if (setTime) {
+        hostedTimestamps = allocateTimestamps(tablets, toLoad.size());
+        hostedTimestamps.forEach((e, t) -> {
+          log.trace("{} allocated timestamp {} {}", logId, e, t);
+        });
+      } else {
+        hostedTimestamps = Map.of();
+      }
+
+      for (TabletMetadata tablet : tablets) {
+        if (setTime && tablet.getLocation() != null
+            && !hostedTimestamps.containsKey(tablet.getExtent())) {
+          skipped++;
+          log.debug("{} tablet {} did not have a timestamp allocated, will 
retry later", logId,
+              tablet.getExtent());
+          continue;
         }
 
+        Map<ReferencedTabletFile,DataFileValue> filesToLoad = new HashMap<>();
+
         var tabletTime = TabletTime.getInstance(tablet.getTime());
 
-        for (final Bulk.FileInfo fileInfo : files) {
+        int timeOffset = 0;
+
+        for (var entry : toLoad.entrySet()) {
+          ReferencedTabletFile refTabFile = entry.getKey();
+          Bulk.FileInfo fileInfo = entry.getValue();
 
           DataFileValue dfv;
 
           if (setTime) {
-            dfv = new DataFileValue(fileInfo.getEstFileSize(), 
fileInfo.getEstNumEntries(),
-                tabletTime.getAndUpdateTime());
+            if (tablet.getLocation() == null) {
+              dfv = new DataFileValue(fileInfo.getEstFileSize(), 
fileInfo.getEstNumEntries(),
+                  tabletTime.getAndUpdateTime());
+            } else {
+              dfv = new DataFileValue(fileInfo.getEstFileSize(), 
fileInfo.getEstNumEntries(),
+                  hostedTimestamps.get(tablet.getExtent()) + timeOffset);
+              timeOffset++;
+            }
           } else {
             dfv = new DataFileValue(fileInfo.getEstFileSize(), 
fileInfo.getEstNumEntries());
           }
 
-          filesToLoad.put(new ReferencedTabletFile(new Path(bulkDir, 
fileInfo.getFileName())), dfv);
+          filesToLoad.put(refTabFile, dfv);
+
         }
 
         // remove any files that were already loaded
@@ -139,37 +195,87 @@ class LoadFiles extends ManagerRepo {
         });
 
         if (!filesToLoad.isEmpty()) {
-          // ELASTICITY_TODO lets automatically call require prev end row
-          var tabletMutator =
-              
conditionalMutator.mutateTablet(tablet.getExtent()).requireAbsentOperation();
-
-          if (setTime) {
-            tabletMutator.requireSame(tablet, LOADED, TIME, LOCATION);
-          } else {
-            tabletMutator.requireSame(tablet, LOADED);
-          }
+          var tabletMutator = 
conditionalMutator.mutateTablet(tablet.getExtent())
+              .requireAbsentOperation().requireSame(tablet, LOADED, TIME, 
LOCATION);
 
           filesToLoad.forEach((f, v) -> {
             tabletMutator.putBulkFile(f, tid);
             tabletMutator.putFile(f, v);
-
-            if (setTime) {
-              // ELASTICITY_TODO this is not the correct thing to do when the 
tablet is hosted and
-              // could be harmful
-              tabletMutator.putTime(tabletTime.getMetadataTime());
-            }
           });
 
+          if (setTime && tablet.getLocation() == null) {
+            tabletMutator.putTime(tabletTime.getMetadataTime());
+          }
+
           tabletMutator.submit(tm -> false);
         }
       }
     }
 
+    private Map<KeyExtent,Long> allocateTimestamps(List<TabletMetadata> 
tablets, int numStamps) {
+
+      Map<HostAndPort,List<TKeyExtent>> serversToAsk = new HashMap<>();
+
+      Map<KeyExtent,Long> allTimestamps = new HashMap<>();
+
+      for (var tablet : tablets) {
+        if (tablet.getLocation() != null && tablet.getLocation().getType() == 
CURRENT) {
+          var location = tablet.getLocation().getHostAndPort();
+          serversToAsk.computeIfAbsent(location, l -> new ArrayList<>())
+              .add(tablet.getExtent().toThrift());
+        }
+      }
+
+      for (var entry : serversToAsk.entrySet()) {
+        HostAndPort server = entry.getKey();
+        List<TKeyExtent> extents = entry.getValue();
+
+        Map<KeyExtent,Long> serversTimestamps = allocateTimestamps(server, 
extents, numStamps);
+        allTimestamps.putAll(serversTimestamps);
+
+      }
+
+      return allTimestamps;
+    }
+
+    private Map<KeyExtent,Long> allocateTimestamps(HostAndPort server, 
List<TKeyExtent> extents,
+        int numStamps) {
+      TabletServerClientService.Client client = null;
+      var context = manager.getContext();
+      try {
+
+        log.trace("{} sending allocate timestamps request to {} for {} 
extents", logId, server,
+            extents.size());
+        var timeInMillis =
+            
context.getConfiguration().getTimeInMillis(Property.MANAGER_BULK_TIMEOUT);
+        client =
+            ThriftUtil.getClient(ThriftClientTypes.TABLET_SERVER, server, 
context, timeInMillis);
+
+        var timestamps = client.allocateTimestamps(TraceUtil.traceInfo(), 
context.rpcCreds(),
+            extents, numStamps);
+
+        log.trace("{} allocate timestamps request to {} returned {} 
timestamps", logId, server,
+            timestamps.size());
+
+        var converted = new HashMap<KeyExtent,Long>();
+        timestamps.forEach((k, v) -> converted.put(KeyExtent.fromThrift(k), 
v));
+        return converted;
+      } catch (TException ex) {
+        log.debug("rpc failed server: " + server + ", " + logId + " " + 
ex.getMessage(), ex);
+        // return an empty map, should retry later
+        return Map.of();
+      } finally {
+        ThriftUtil.returnClient(client, context);
+      }
+
+    }
+
     long finish() {
       var results = conditionalMutator.process();
 
       boolean allDone =
-          results.values().stream().allMatch(result -> result.getStatus() == 
Status.ACCEPTED);
+          results.values().stream().allMatch(result -> result.getStatus() == 
Status.ACCEPTED)
+              && skipped == 0;
 
       long sleepTime = 0;
       if (!allDone) {
@@ -178,9 +284,14 @@ class LoadFiles extends ManagerRepo {
         results.forEach((extent, condResult) -> {
           if (condResult.getStatus() != Status.ACCEPTED) {
             var metadata = condResult.readMetadata();
-            log.debug("Tablet update failed {} {} {} {} {} {}", 
FateTxId.formatTid(tid), extent,
-                condResult.getStatus(), metadata.getOperationId(), 
metadata.getLocation(),
-                metadata.getLoaded());
+            if (metadata == null) {
+              log.debug("Tablet update failed, tablet is gone {} {} {}", 
logId, extent,
+                  condResult.getStatus());
+            } else {
+              log.debug("Tablet update failed {} {} {} {} {} {}", logId, 
extent,
+                  condResult.getStatus(), metadata.getOperationId(), 
metadata.getLocation(),
+                  metadata.getLoaded());
+            }
           }
         });
       }
diff --git 
a/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletClientHandler.java
 
b/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletClientHandler.java
index 7f34d65b4f..a1619d1697 100644
--- 
a/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletClientHandler.java
+++ 
b/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletClientHandler.java
@@ -1171,6 +1171,30 @@ public class TabletClientHandler implements 
TabletServerClientService.Iface,
     return List.of();
   }
 
+  @Override
+  public Map<TKeyExtent,Long> allocateTimestamps(TInfo tinfo, TCredentials 
credentials,
+      List<TKeyExtent> extents, int numStamps) throws TException {
+    if (!security.canPerformSystemActions(credentials)) {
+      throw new AccumuloSecurityException(credentials.getPrincipal(),
+          SecurityErrorCode.PERMISSION_DENIED).asThriftException();
+    }
+
+    var tabletsSnapshot = server.getOnlineTablets();
+
+    Map<TKeyExtent,Long> timestamps = new HashMap<>();
+
+    for (var textent : extents) {
+      var extent = KeyExtent.fromThrift(textent);
+      Tablet tablet = tabletsSnapshot.get(extent);
+      if (tablet != null) {
+        tablet.allocateTimestamp(numStamps)
+            .ifPresent(timestamp -> timestamps.put(textent, timestamp));
+      }
+    }
+
+    return timestamps;
+  }
+
   @Override
   public List<String> getActiveLogs(TInfo tinfo, TCredentials credentials) {
     String log = server.logger.getLogFile();
diff --git 
a/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/Tablet.java 
b/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/Tablet.java
index 4a9358ca26..842d881ecd 100644
--- 
a/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/Tablet.java
+++ 
b/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/Tablet.java
@@ -32,6 +32,7 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
+import java.util.OptionalLong;
 import java.util.Set;
 import java.util.concurrent.ConcurrentSkipListSet;
 import java.util.concurrent.TimeUnit;
@@ -1598,4 +1599,20 @@ public class Tablet extends TabletBase {
     return !activeScans.isEmpty() || writesInProgress > 0;
   }
 
+  public synchronized OptionalLong allocateTimestamp(int numStamps) {
+    if (isClosing() || isClosed()) {
+      return OptionalLong.empty();
+    }
+
+    Preconditions.checkArgument(numStamps > 0);
+    long timestamp = Long.MIN_VALUE;
+    for (int i = 0; i < numStamps; i++) {
+      timestamp = tabletTime.getAndUpdateTime();
+    }
+
+    getTabletMemory().getCommitSession().updateMaxCommittedTime(timestamp);
+
+    // ELASTICITY_TODO this needs to be persisted in the metadata table or 
walog
+    return OptionalLong.of(timestamp);
+  }
 }
diff --git a/test/src/main/java/org/apache/accumulo/test/ScanConsistencyIT.java 
b/test/src/main/java/org/apache/accumulo/test/ScanConsistencyIT.java
index 5e52066cb1..ba5873bed7 100644
--- a/test/src/main/java/org/apache/accumulo/test/ScanConsistencyIT.java
+++ b/test/src/main/java/org/apache/accumulo/test/ScanConsistencyIT.java
@@ -62,7 +62,6 @@ import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.FileSystem;
 import org.apache.hadoop.fs.Path;
 import org.apache.hadoop.io.Text;
-import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -77,7 +76,6 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
  * This test verifies that scans will always see data written before the scan 
started even when
  * there are concurrent scans, writes, and table operations running.
  */
-@Disabled // ELASTICITY_TODO
 public class ScanConsistencyIT extends AccumuloClusterHarness {
 
   private static final Logger log = 
LoggerFactory.getLogger(ScanConsistencyIT.class);
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 bbdb091fd3..4e3713e10e 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
@@ -45,6 +45,7 @@ import java.util.Map.Entry;
 import java.util.Set;
 import java.util.SortedSet;
 import java.util.TreeSet;
+import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
 import java.util.stream.Collectors;
 
@@ -157,6 +158,13 @@ public class BulkNewIT extends SharedMiniClusterBase {
 
   private void testSingleTabletSingleFile(AccumuloClient c, boolean offline, 
boolean setTime)
       throws Exception {
+    testSingleTabletSingleFile(c, offline, setTime, () -> {
+      return null;
+    });
+  }
+
+  private void testSingleTabletSingleFile(AccumuloClient c, boolean offline, 
boolean setTime,
+      Callable<Void> preLoadAction) throws Exception {
     addSplits(c, tableName, "0333");
 
     if (offline) {
@@ -167,6 +175,7 @@ public class BulkNewIT extends SharedMiniClusterBase {
 
     String h1 = writeData(dir + "/f1.", aconf, 0, 332);
 
+    preLoadAction.call();
     
c.tableOperations().importDirectory(dir).to(tableName).tableTime(setTime).load();
     // running again with ignoreEmptyDir set to true will not throw an 
exception
     
c.tableOperations().importDirectory(dir).to(tableName).tableTime(setTime).ignoreEmptyDir(true)
@@ -209,12 +218,73 @@ public class BulkNewIT extends SharedMiniClusterBase {
       // set logical time type so we can set time on bulk import
       newTableConf.setTimeType(TimeType.LOGICAL);
       client.tableOperations().create(tableName, newTableConf);
-      testSingleTabletSingleFile(client, false, true);
 
       var ctx = (ClientContext) client;
-      var tabletTime = ctx.getAmple()
-          .readTablet(new KeyExtent(ctx.getTableId(tableName), new 
Text("0333"), null)).getTime();
-      assertEquals(new MetadataTime(1, TimeType.LOGICAL), tabletTime);
+
+      var tablet = ctx.getAmple().readTablet(new 
KeyExtent(ctx.getTableId(tableName), null, null));
+      assertEquals(new MetadataTime(0, TimeType.LOGICAL), tablet.getTime());
+
+      var extent = new KeyExtent(ctx.getTableId(tableName), new Text("0333"), 
null);
+
+      testSingleTabletSingleFile(client, false, true, () -> {
+        // Want to test with and without a location, assuming the tablet does 
not have a location
+        // now. Need to validate that assumption.
+        assertNull(ctx.getAmple().readTablet(extent).getLocation());
+        return null;
+      });
+
+      assertEquals(new MetadataTime(1, TimeType.LOGICAL),
+          ctx.getAmple().readTablet(extent).getTime());
+
+      int added = 0;
+      try (var writer = client.createBatchWriter(tableName);
+          var scanner = client.createScanner(tableName)) {
+        for (var entry : scanner) {
+          Mutation m = new Mutation(entry.getKey().getRow());
+          m.at().family(entry.getKey().getColumnFamily())
+              .qualifier(entry.getKey().getColumnFamily())
+              .visibility(entry.getKey().getColumnVisibility())
+              .put(Integer.parseInt(entry.getValue().toString()) * 10 + "");
+          writer.addMutation(m);
+          added++;
+        }
+      }
+
+      // verify data written by batch writer overwrote bulk imported data
+      try (var scanner = client.createScanner(tableName)) {
+        assertEquals(2,
+            scanner.stream().mapToLong(e -> 
e.getKey().getTimestamp()).min().orElse(-1));
+        assertEquals(2 + added - 1,
+            scanner.stream().mapToLong(e -> 
e.getKey().getTimestamp()).max().orElse(-1));
+        scanner.forEach((k, v) -> {
+          assertEquals(Integer.parseInt(k.getRow().toString()) * 10,
+              Integer.parseInt(v.toString()));
+        });
+      }
+
+      String dir = getDir("/testSetTime-");
+      writeData(dir + "/f1.", aconf, 0, 332);
+
+      // For this import tablet should be hosted so the bulk import operation 
will have to
+      // coordinate getting time with the hosted tablet. The time should 
refect the batch writes
+      // just done.
+      
client.tableOperations().importDirectory(dir).to(tableName).tableTime(true).load();
+
+      // verify bulk imported data overwrote batch written data
+      try (var scanner = client.createScanner(tableName)) {
+        assertEquals(2 + added,
+            scanner.stream().mapToLong(e -> 
e.getKey().getTimestamp()).min().orElse(-1));
+        assertEquals(2 + added,
+            scanner.stream().mapToLong(e -> 
e.getKey().getTimestamp()).max().orElse(-1));
+        scanner.forEach((k, v) -> {
+          assertEquals(Integer.parseInt(k.getRow().toString()), 
Integer.parseInt(v.toString()));
+        });
+      }
+
+      client.tableOperations().flush(tableName, null, null, true);
+      assertEquals(new MetadataTime(2 + added, TimeType.LOGICAL),
+          ctx.getAmple().readTablet(extent).getTime());
+
     }
   }
 
diff --git 
a/test/src/main/java/org/apache/accumulo/test/performance/NullTserver.java 
b/test/src/main/java/org/apache/accumulo/test/performance/NullTserver.java
index 792d186054..dfa2c7e3ee 100644
--- a/test/src/main/java/org/apache/accumulo/test/performance/NullTserver.java
+++ b/test/src/main/java/org/apache/accumulo/test/performance/NullTserver.java
@@ -252,6 +252,12 @@ public class NullTserver {
         List<TKeyExtent> refreshes) throws TException {
       return List.of();
     }
+
+    @Override
+    public Map<TKeyExtent,Long> allocateTimestamps(TInfo tinfo, TCredentials 
credentials,
+        List<TKeyExtent> tablets, int numStamps) throws TException {
+      return Map.of();
+    }
   }
 
   static class Opts extends Help {

Reply via email to