Package org.infinispan.client.hotrod.impl.protocol

Source Code of org.infinispan.client.hotrod.impl.protocol.Codec11

/*
* Copyright 2011 Red Hat, Inc. and/or its affiliates.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*/

package org.infinispan.client.hotrod.impl.protocol;

import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;

import org.infinispan.client.hotrod.impl.consistenthash.ConsistentHash;
import org.infinispan.client.hotrod.impl.transport.Transport;
import org.infinispan.client.hotrod.logging.Log;
import org.infinispan.client.hotrod.logging.LogFactory;

/**
* A Hot Rod encoder/decoder for version 1.1 of the protocol.
*
* @author Galder Zamarreño
* @since 5.1
*/
public class Codec11 extends Codec10 {

   private static final Log log = LogFactory.getLog(Codec11.class, Log.class);

   @Override
   public HeaderParams writeHeader(Transport transport, HeaderParams params) {
      return writeHeader(transport, params, HotRodConstants.VERSION_11);
   }

   @Override
   protected void readNewTopologyAndHash(Transport transport, AtomicInteger topologyId) {
      final Log localLog = getLog();
      int newTopologyId = transport.readVInt();
      topologyId.set(newTopologyId);
      int numKeyOwners = transport.readUnsignedShort();
      short hashFctVersion = transport.readByte();
      ConsistentHash ch = null;
      if (hashFctVersion != 0)
         ch = transport.getTransportFactory().getConsistentHashFactory()
               .newConsistentHash(hashFctVersion);
      else
         localLog.trace("Not using a consistent hash function (hash function version == 0)");

      int hashSpace = transport.readVInt();
      int clusterSize = transport.readVInt();
      // New in 1.1
      int numVirtualNodes = transport.readVInt();

      localLog.tracef("Topology change request: newTopologyId=%d, numKeyOwners=%d, " +
            "hashFunctionVersion=%d, hashSpaceSize=%d, clusterSize=%d, numVirtualNodes=%d",
            newTopologyId, numKeyOwners, hashFctVersion, hashSpace, clusterSize,
            numVirtualNodes);

      Map<SocketAddress, Set<Integer>> servers2Hash =
            new LinkedHashMap<SocketAddress, Set<Integer>>();

      for (int i = 0; i < clusterSize; i++) {
         String host = transport.readString();
         int port = transport.readUnsignedShort();
         // TODO: Performance improvement, since hash positions are fixed, we could maybe only calculate for those nodes that the client is not aware of?
         int baseHashCode = transport.read4ByteInt();
         int normalizedHashCode = getNormalizedHash(baseHashCode, ch);
         localLog.tracef("Server(%s:%d) read with base hash code %d, and normalized hash code %d",
                    host, port, baseHashCode, normalizedHashCode);
         cacheHashCode(servers2Hash, host, port, normalizedHashCode);
         if (numVirtualNodes > 1)
            calcVirtualHashCodes(baseHashCode, numVirtualNodes, servers2Hash, host, port, ch);
      }

      if (localLog.isInfoEnabled()) {
         localLog.newTopology(servers2Hash.keySet());
      }
      transport.getTransportFactory().updateServers(servers2Hash.keySet());
      if (hashFctVersion == 0) {
         localLog.trace("Not using a consistent hash function (hash function version == 0)");
      } else {
         transport.getTransportFactory().updateHashFunction(
               servers2Hash, numKeyOwners, hashFctVersion, hashSpace);
      }
   }

   @Override
   public Log getLog() {
      return log;
   }

   private int getNormalizedHash(int baseHashCode, ConsistentHash ch) {
      if (ch != null)
         return ch.getNormalizedHash(baseHashCode);
      else
         return baseHashCode;
   }

   private void calcVirtualHashCodes(int addrHashCode, int numVirtualNodes,
            Map<SocketAddress, Set<Integer>> servers2Hash, String host, int port,
            ConsistentHash ch) {
      for (int j = 1; j < numVirtualNodes; j++) {
         int hashCode = calcVNodeHashCode(addrHashCode, j);
         cacheHashCode(servers2Hash, host, port, getNormalizedHash(hashCode, ch));
      }
   }

   private void cacheHashCode(Map<SocketAddress, Set<Integer>> servers2Hash,
            String host, int port, int hashCode) {
      InetSocketAddress address = new InetSocketAddress(host, port);
      Set<Integer> hashes = servers2Hash.get(address);
      if (hashes == null) {
         hashes = new HashSet<Integer>();
         servers2Hash.put(address, hashes);
      }
      hashes.add(hashCode);
      getLog().tracef("Hash code is: %d", hashCode);
   }

   // IMPORTANT NOTE: Hot Rod protocol agrees to this calculation for a virtual
   // node address hash code calculation, so any changes to the implementation
   // require modification of the protocol.
   private int calcVNodeHashCode(int addrHashCode, int id) {
      int result = id;
      result = 31 * result + addrHashCode;
      return result;
   }

}
TOP

Related Classes of org.infinispan.client.hotrod.impl.protocol.Codec11

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.