private MutationSet sendMutationsToTabletServer(
        String location, Map<KeyExtent, List<Mutation>> tabMuts, TimeoutTracker timeoutTracker)
        throws IOException, AccumuloSecurityException, AccumuloServerException {
      if (tabMuts.size() == 0) {
        return new MutationSet();
      }
      TInfo tinfo = Tracer.traceInfo();

      // TODO remove this
      TTransport transport = null;

      timeoutTracker.startingWrite();

      try {
        TabletClientService.Iface client;

        if (timeoutTracker.getTimeOut()
            < instance.getConfiguration().getTimeInMillis(Property.GENERAL_RPC_TIMEOUT))
          client = ThriftUtil.getTServerClient(location, timeoutTracker.getTimeOut());
        else client = ThriftUtil.getTServerClient(location, instance.getConfiguration());

        try {
          MutationSet allFailures = new MutationSet();

          if (tabMuts.size() == 1 && tabMuts.values().iterator().next().size() == 1) {
            Entry<KeyExtent, List<Mutation>> entry = tabMuts.entrySet().iterator().next();

            try {
              client.update(
                  tinfo,
                  credentials.toThrift(instance),
                  entry.getKey().toThrift(),
                  entry.getValue().get(0).toThrift());
            } catch (NotServingTabletException e) {
              allFailures.addAll(entry.getKey().getTableId().toString(), entry.getValue());
              TabletLocator.getLocator(instance, new Text(entry.getKey().getTableId()))
                  .invalidateCache(entry.getKey());
            } catch (ConstraintViolationException e) {
              updatedConstraintViolations(
                  Translator.translate(e.violationSummaries, Translator.TCVST));
            }
            timeoutTracker.madeProgress();
          } else {

            long usid = client.startUpdate(tinfo, credentials.toThrift(instance));

            List<TMutation> updates = new ArrayList<TMutation>();
            for (Entry<KeyExtent, List<Mutation>> entry : tabMuts.entrySet()) {
              long size = 0;
              Iterator<Mutation> iter = entry.getValue().iterator();
              while (iter.hasNext()) {
                while (size < MUTATION_BATCH_SIZE && iter.hasNext()) {
                  Mutation mutation = iter.next();
                  updates.add(mutation.toThrift());
                  size += mutation.numBytes();
                }

                client.applyUpdates(tinfo, usid, entry.getKey().toThrift(), updates);
                updates.clear();
                size = 0;
              }
            }

            UpdateErrors updateErrors = client.closeUpdate(tinfo, usid);

            Map<KeyExtent, Long> failures =
                Translator.translate(updateErrors.failedExtents, Translator.TKET);
            updatedConstraintViolations(
                Translator.translate(updateErrors.violationSummaries, Translator.TCVST));
            updateAuthorizationFailures(
                Translator.translate(updateErrors.authorizationFailures, Translator.TKET));

            long totalCommitted = 0;

            for (Entry<KeyExtent, Long> entry : failures.entrySet()) {
              KeyExtent failedExtent = entry.getKey();
              int numCommitted = (int) (long) entry.getValue();
              totalCommitted += numCommitted;

              String table = failedExtent.getTableId().toString();

              TabletLocator.getLocator(instance, new Text(table)).invalidateCache(failedExtent);

              ArrayList<Mutation> mutations = (ArrayList<Mutation>) tabMuts.get(failedExtent);
              allFailures.addAll(table, mutations.subList(numCommitted, mutations.size()));
            }

            if (failures.keySet().containsAll(tabMuts.keySet()) && totalCommitted == 0) {
              // nothing was successfully written
              timeoutTracker.wroteNothing();
            } else {
              // successfully wrote something to tablet server
              timeoutTracker.madeProgress();
            }
          }
          return allFailures;
        } finally {
          ThriftUtil.returnClient((TServiceClient) client);
        }
      } catch (TTransportException e) {
        timeoutTracker.errorOccured(e);
        throw new IOException(e);
      } catch (TApplicationException tae) {
        updateServerErrors(location, tae);
        throw new AccumuloServerException(location, tae);
      } catch (ThriftSecurityException e) {
        updateAuthorizationFailures(tabMuts.keySet(), e.code);
        throw new AccumuloSecurityException(e.user, e.code, e);
      } catch (NoSuchScanIDException e) {
        throw new IOException(e);
      } catch (TException e) {
        throw new IOException(e);
      } finally {
        ThriftTransportPool.getInstance().returnTransport(transport);
      }
    }