@Override
  public void mutateMany(Map<ByteBuffer, Mutation> mutations, TransactionHandle txh)
      throws StorageException {
    // null txh means a Transaction is calling this method
    if (null != txh) {
      // non-null txh -> make sure locks are valid
      AstyanaxTransaction atxh = (AstyanaxTransaction) txh;
      if (!atxh.isMutationStarted()) {
        // This is the first mutate call in the transaction
        atxh.mutationStarted();
        // Verify all blind lock claims now
        atxh.verifyAllLockClaims(); // throws GSE and unlocks everything on any lock failure
      }
    }

    MutationBatch m =
        keyspace
            .prepareMutationBatch()
            .setConsistencyLevel(writeLevel)
            .withRetryPolicy(retryPolicy.duplicate());

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

    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(cf, ent.getKey());
      dels.setTimestamp(delTS);
      ColumnListMutation<ByteBuffer> adds = m.withRow(cf, 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);
    }
  }
  @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);
    }
  }
 @Override
 public ByteBuffer get(ByteBuffer key, ByteBuffer column, TransactionHandle txh)
     throws StorageException {
   try {
     OperationResult<Column<ByteBuffer>> result =
         keyspace
             .prepareQuery(cf)
             .setConsistencyLevel(readLevel)
             .withRetryPolicy(retryPolicy.duplicate())
             .getKey(key)
             .getColumn(column)
             .execute();
     return result.getResult().getByteBufferValue();
   } catch (NotFoundException e) {
     return null;
   } catch (ConnectionException e) {
     throw new TemporaryStorageException(e);
   }
 }
 @Override
 public boolean containsKey(ByteBuffer key, TransactionHandle txh) throws StorageException {
   try {
     // See getSlice() below for a warning suppression justification
     @SuppressWarnings("rawtypes")
     RowQuery rq =
         (RowQuery)
             keyspace
                 .prepareQuery(cf)
                 .withRetryPolicy(retryPolicy.duplicate())
                 .setConsistencyLevel(readLevel)
                 .getKey(key);
     @SuppressWarnings("unchecked")
     OperationResult<ColumnList<ByteBuffer>> r =
         rq.withColumnRange(EMPTY, EMPTY, false, 1).execute();
     return 0 < r.getResult().size();
   } catch (ConnectionException e) {
     throw new TemporaryStorageException(e);
   }
 }
  @Override
  public String getConfigurationProperty(final String key) throws StorageException {
    try {
      ensureColumnFamilyExists(SYSTEM_PROPERTIES_CF, "org.apache.cassandra.db.marshal.UTF8Type");

      OperationResult<Column<String>> result =
          keyspaceContext
              .getEntity()
              .prepareQuery(PROPERTIES_CF)
              .setConsistencyLevel(ConsistencyLevel.CL_QUORUM)
              .withRetryPolicy(retryPolicy.duplicate())
              .getKey(SYSTEM_PROPERTIES_KEY)
              .getColumn(key)
              .execute();

      return result.getResult().getStringValue();
    } catch (NotFoundException e) {
      return null;
    } catch (ConnectionException e) {
      throw new PermanentStorageException(e);
    }
  }
  @Override
  public List<Entry> getSlice(
      ByteBuffer key,
      ByteBuffer columnStart,
      ByteBuffer columnEnd,
      int limit,
      TransactionHandle txh)
      throws StorageException {

    /*
     * The following hideous cast dance avoids a type-erasure error in the
     * RowQuery<K, V> type that emerges when K=V=ByteBuffer. Specifically,
     * these two methods erase to the same signature after generic reduction
     * during compilation:
     *
     * RowQuery<K, C> withColumnRange(C startColumn, C endColumn, boolean
     * reversed, int count) RowQuery<K, C> withColumnRange(ByteBuffer
     * startColumn, ByteBuffer endColumn, boolean reversed, int count)
     *
     *
     * The compiler substitutes ByteBuffer=C for both startColumn and
     * endColumn, compares it to its identical twin with that type
     * hard-coded, and dies.
     *
     * Here's the compiler error I received when attempting to compile this
     * code without the following casts. I used Oracle JDK 6 Linux x86_64.
     *
     * AstyanaxOrderedKeyColumnValueStore.java:[108,4] reference to
     * withColumnRange is ambiguous, both method
     * withColumnRange(C,C,boolean,int) in
     * com.netflix.astyanax.query.RowQuery<java.nio.ByteBuffer,java.nio.ByteBuffer>
     * and method
     * withColumnRange(java.nio.ByteBuffer,java.nio.ByteBuffer,boolean,int)
     * in
     * com.netflix.astyanax.query.RowQuery<java.nio.ByteBuffer,java.nio.ByteBuffer>
     * match
     *
     */
    @SuppressWarnings("rawtypes")
    RowQuery rq =
        (RowQuery)
            keyspace
                .prepareQuery(cf)
                .setConsistencyLevel(readLevel)
                .withRetryPolicy(retryPolicy.duplicate())
                .getKey(key);
    //		RowQuery<ByteBuffer, ByteBuffer> rq = keyspace.prepareQuery(cf).getKey(key);
    rq.withColumnRange(columnStart, columnEnd, false, limit + 1);

    OperationResult<ColumnList<ByteBuffer>> r;
    try {
      @SuppressWarnings("unchecked")
      OperationResult<ColumnList<ByteBuffer>> tmp =
          (OperationResult<ColumnList<ByteBuffer>>) rq.execute();
      r = tmp;
    } catch (ConnectionException e) {
      throw new TemporaryStorageException(e);
    }

    List<Entry> result = new ArrayList<Entry>(r.getResult().size());

    int i = 0;

    for (Column<ByteBuffer> c : r.getResult()) {
      ByteBuffer colName = c.getName();

      if (colName.equals(columnEnd)) {
        break;
      }

      result.add(new Entry(colName, c.getByteBufferValue()));

      if (++i == limit) {
        break;
      }
    }

    return result;
  }