@Override
  public void mutateMany(Map<String, Map<ByteBuffer, Mutation>> batch, StoreTransaction txh)
      throws StorageException {
    MutationBatch m =
        keyspaceContext
            .getEntity()
            .prepareMutationBatch()
            .setConsistencyLevel(getTx(txh).getWriteConsistencyLevel().getAstyanaxConsistency())
            .withRetryPolicy(retryPolicy.duplicate());

    final long delTS = TimeUtility.getApproxNSSinceEpoch(false);
    final long addTS = TimeUtility.getApproxNSSinceEpoch(true);

    for (Map.Entry<String, Map<ByteBuffer, Mutation>> batchentry : batch.entrySet()) {
      String storeName = batchentry.getKey();
      Preconditions.checkArgument(
          openStores.containsKey(storeName), "Store cannot be found: " + storeName);
      ColumnFamily<ByteBuffer, ByteBuffer> columnFamily =
          openStores.get(storeName).getColumnFamily();

      Map<ByteBuffer, Mutation> mutations = batchentry.getValue();
      for (Map.Entry<ByteBuffer, Mutation> ent : mutations.entrySet()) {
        // The CLMs for additions and deletions are separated because
        // Astyanax's operation timestamp cannot be set on a per-delete
        // or per-addition basis.
        ColumnListMutation<ByteBuffer> dels = m.withRow(columnFamily, ent.getKey());
        dels.setTimestamp(delTS);
        ColumnListMutation<ByteBuffer> adds = m.withRow(columnFamily, ent.getKey());
        adds.setTimestamp(addTS);

        Mutation titanMutation = ent.getValue();

        if (titanMutation.hasDeletions()) {
          for (ByteBuffer b : titanMutation.getDeletions()) {
            dels.deleteColumn(b);
          }
        }

        if (titanMutation.hasAdditions()) {
          for (Entry e : titanMutation.getAdditions()) {
            adds.putColumn(e.getColumn(), e.getValue(), null);
          }
        }
      }
    }

    try {
      m.execute();
    } catch (ConnectionException e) {
      throw new TemporaryStorageException(e);
    }
  }
  /**
   * Convert Titan internal Mutation representation into HBase native commands.
   *
   * @param mutations Mutations to convert into HBase commands.
   * @param putTimestamp The timestamp to use for Put commands.
   * @param delTimestamp The timestamp to use for Delete commands.
   * @return Commands sorted by key converted from Titan internal representation.
   */
  private static Map<ByteBuffer, Pair<Put, Delete>> convertToCommands(
      Map<String, Map<ByteBuffer, KCVMutation>> mutations,
      final long putTimestamp,
      final long delTimestamp) {
    Map<ByteBuffer, Pair<Put, Delete>> commandsPerKey =
        new HashMap<ByteBuffer, Pair<Put, Delete>>();

    for (Map.Entry<String, Map<ByteBuffer, KCVMutation>> entry : mutations.entrySet()) {
      byte[] cfName = entry.getKey().getBytes();

      for (Map.Entry<ByteBuffer, KCVMutation> m : entry.getValue().entrySet()) {
        ByteBuffer key = m.getKey();
        KCVMutation mutation = m.getValue();

        Pair<Put, Delete> commands = commandsPerKey.get(key);

        if (commands == null) {
          commands = new Pair<Put, Delete>();
          commandsPerKey.put(key, commands);
        }

        if (mutation.hasDeletions()) {
          if (commands.getSecond() == null)
            commands.setSecond(new Delete(ByteBufferUtil.getArray(key), delTimestamp, null));

          for (ByteBuffer b : mutation.getDeletions()) {
            commands.getSecond().deleteColumns(cfName, ByteBufferUtil.getArray(b), delTimestamp);
          }
        }

        if (mutation.hasAdditions()) {
          if (commands.getFirst() == null)
            commands.setFirst(new Put(ByteBufferUtil.getArray(key), putTimestamp));

          for (Entry e : mutation.getAdditions()) {
            commands
                .getFirst()
                .add(
                    cfName,
                    ByteBufferUtil.getArray(e.getColumn()),
                    putTimestamp,
                    ByteBufferUtil.getArray(e.getValue()));
          }
        }
      }
    }

    return commandsPerKey;
  }