private OperationFuture<Long> asyncMutate(Mutator m, String key, long by,
      long def, int exp) {
    if (!(opFact instanceof BinaryOperationFactory) && (def != 0 || exp != -1)) {
      throw new UnsupportedOperationException("Default value or expiration "
        + "time are not supported on the async mutate methods. Use either the "
        + "binary protocol or the sync variant.");
    }

    final CountDownLatch latch = new CountDownLatch(1);
    final OperationFuture<Long> rv =
        new OperationFuture<Long>(key, latch, operationTimeout, executorService);
    Operation op = opFact.mutate(m, key, by, def, exp,
        new OperationCallback() {
          @Override
          public void receivedStatus(OperationStatus s) {
            rv.set(new Long(s.isSuccess() ? s.getMessage() : "-1"), s);
          }

          @Override
          public void complete() {
            latch.countDown();
            rv.signalComplete();
          }
        });
    mconn.enqueueOperation(key, op);
    rv.setOperation(op);
    return rv;
  }
Decrement the given counter, returning the new value.

Due to the way the memcached server operates on items, incremented and
decremented items will be returned as Strings with any operations that
return a value.

@param key the key
@param by the amount to decrement
@param def the default value (if the counter does not exist)
@param exp the expiration of this object
@return the new value, or -1 if we were unable to decrement or add
@throws OperationTimeoutException if the global operation timeout is
          exceeded
@throws IllegalStateException in the rare circumstance where queue is too
          full to accept any more requests
src/main/java/net/spy/memcached/MemcachedClient.java