protected byte[] returnPossiblePrevValue(Transport transport) {
   if (hasForceReturn(flags)) {
     byte[] bytes = transport.readArray();
     if (log.isTraceEnabled())
       log.tracef("Previous value bytes is: %s", Util.printArray(bytes, false));
     // 0-length response means null
     return bytes.length == 0 ? null : bytes;
   } else {
     return null;
   }
 }
    @Override
    public SocketAddress getServer(Object key) {
      int keyHashCode = getNormalizedHash(key);
      if (keyHashCode == Integer.MIN_VALUE) keyHashCode += 1;
      int hash = Math.abs(keyHashCode);

      SortedMap<Integer, SocketAddress> candidates = positions.tailMap(hash % hashSpace);
      if (log.isTraceEnabled()) {
        log.tracef("Found possible candidates: %s", candidates);
      }
      return (candidates.size() > 0 ? candidates : positions)
          .entrySet()
          .iterator()
          .next()
          .getValue();
    }
    @Override
    public void init(
        Map<SocketAddress, Set<Integer>> servers2Hash, int numKeyOwners, int hashSpace) {

      log.infof(
          "Parameters received by CH are: server2Hash: %s, numKeyOwners: %s, hashSpace: %s",
          servers2Hash, numKeyOwners, hashSpace);

      for (Map.Entry<SocketAddress, Set<Integer>> entry : servers2Hash.entrySet()) {
        SocketAddress addr = entry.getKey();
        for (Integer hash : entry.getValue()) {
          SocketAddress prev = positions.put(hash, addr);
          if (prev != null)
            log.debugf(
                "Adding hash (%d) again, this time for %s. Previously it was associated with: %s",
                hash, addr, prev);
        }
      }

      log.tracef("Positions (%d entries) are: %s", positions.size(), positions);
      this.hashSpace = hashSpace;
      this.numKeyOwners = numKeyOwners;
    }