protected void removeAllKeysInternal(Set<? extends K> keys) {
   final long start = System.nanoTime();
   final Set<Data> keysData;
   keysData = new HashSet<Data>();
   for (K key : keys) {
     keysData.add(toData(key));
   }
   final int partitionCount = clientContext.getPartitionService().getPartitionCount();
   final int completionId = nextCompletionId();
   registerCompletionLatch(completionId, partitionCount);
   ClientMessage request =
       CacheRemoveAllKeysCodec.encodeRequest(nameWithPrefix, keysData, completionId);
   try {
     invoke(request);
     waitCompletionLatch(completionId, null);
     if (statisticsEnabled) {
       // Actually we don't know how many of them are really removed or not.
       // We just assume that if there is no exception, all of them are removed.
       // Otherwise (if there is an exception), we don't update any cache stats about remove.
       statistics.increaseCacheRemovals(keysData.size());
       statistics.addRemoveTimeNanos(System.nanoTime() - start);
     }
   } catch (Throwable t) {
     deregisterCompletionLatch(completionId);
     throw ExceptionUtil.rethrowAllowedTypeFirst(t, CacheException.class);
   }
 }
 protected void handleStatisticsOnRemove(boolean isGet, long start, Object response) {
   if (isGet) {
     statistics.addGetTimeNanos(System.nanoTime() - start);
     if (response != null) {
       statistics.increaseCacheHits();
       statistics.increaseCacheRemovals();
       statistics.addRemoveTimeNanos(System.nanoTime() - start);
     } else {
       statistics.increaseCacheMisses();
     }
   } else {
     if (Boolean.TRUE.equals(response)) {
       statistics.increaseCacheRemovals();
       statistics.addRemoveTimeNanos(System.nanoTime() - start);
     }
   }
 }