/*
 *
 *  *  Copyright 2010-2016 OrientDB LTD (http://orientdb.com)
 *  *
 *  *  Licensed under the Apache License, Version 2.0 (the "License");
 *  *  you may not use this file except in compliance with the License.
 *  *  You may obtain a copy of the License at
 *  *
 *  *       http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  *  Unless required by applicable law or agreed to in writing, software
 *  *  distributed under the License is distributed on an "AS IS" BASIS,
 *  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  *  See the License for the specific language governing permissions and
 *  *  limitations under the License.
 *  *
 *  * For more information: http://orientdb.com
 *
 */
package com.orientechnologies.orient.server.distributed;

import com.orientechnologies.orient.client.remote.OBinaryRequest;
import com.orientechnologies.orient.core.config.OGlobalConfiguration;
import java.io.IOException;

/**
 * Remote server controller. It handles the communication with remote servers in HA configuration.
 *
 * @author Luca Garulli (l.garulli--(at)--orientdb.com)
 */
public class ORemoteServerController {
  private final ORemoteServerChannel[] requestChannels;
  private volatile int requestChannelIndex = 0;

  private final ORemoteServerChannel[] responseChannels;
  private volatile int responseChannelIndex = 0;

  private int protocolVersion = -1;
  public static final int CURRENT_PROTOCOL_VERSION = 2;
  public static final int MIN_SUPPORTED_PROTOCOL_VERSION = 2;

  public ORemoteServerController(
      final ORemoteServerAvailabilityCheck check,
      String localNodeName,
      final String iServer,
      final String iURL,
      final String user,
      final String passwd)
      throws IOException {
    if (user == null) throw new IllegalArgumentException("User is null");
    if (passwd == null) throw new IllegalArgumentException("Password is null");

    ODistributedServerLog.debug(
        this,
        localNodeName,
        iServer,
        ODistributedServerLog.DIRECTION.OUT,
        "Creating remote channel(s) to distributed server...");

    requestChannels =
        new ORemoteServerChannel
            [OGlobalConfiguration.DISTRIBUTED_REQUEST_CHANNELS.getValueAsInteger()];
    for (int i = 0; i < requestChannels.length; ++i)
      requestChannels[i] =
          new ORemoteServerChannel(
              check, localNodeName, iServer, iURL, user, passwd, CURRENT_PROTOCOL_VERSION);

    protocolVersion = requestChannels[0].getDistributedProtocolVersion();

    responseChannels =
        new ORemoteServerChannel
            [OGlobalConfiguration.DISTRIBUTED_RESPONSE_CHANNELS.getValueAsInteger()];
    for (int i = 0; i < responseChannels.length; ++i)
      responseChannels[i] =
          new ORemoteServerChannel(
              check, localNodeName, iServer, iURL, user, passwd, CURRENT_PROTOCOL_VERSION);
  }

  public void sendRequest(final ODistributedRequest req) {
    int idx = requestChannelIndex++;
    if (idx < 0) idx = 0;
    requestChannels[idx % requestChannels.length].sendRequest(req);
  }

  public void sendResponse(final ODistributedResponse response) {
    int idx = responseChannelIndex++;
    if (idx < 0) idx = 0;
    responseChannels[idx % responseChannels.length].sendResponse(response);
  }

  public void close() {
    for (int i = 0; i < requestChannels.length; ++i) requestChannels[i].close();

    for (int i = 0; i < responseChannels.length; ++i) responseChannels[i].close();
  }

  public int getProtocolVersion() {
    return protocolVersion;
  }

  public void sendBinaryRequest(OBinaryRequest request) {
    int idx = requestChannelIndex++;
    if (idx < 0) idx = 0;
    requestChannels[idx % requestChannels.length].sendBinaryRequest(request);
  }
}

@@ -1216,33 +1216,24 @@
 ;%0A  private 
-volatile 
 int requestC
@@ -1321,17 +1321,8 @@
 ate 
-volatile 
 int 
@@ -2942,34 +2942,76 @@
 q) %7B%0A    int idx
+;%0A    synchronized (requestChannels) %7B%0A    
  
-=
  requestChannelI
@@ -3018,39 +3018,73 @@
 ndex++;%0A    
+  
 if (
-idx %3C 0) id
+requestChannelIndex %3C 0) requestChannelInde
 x = 0;%0A    r
@@ -3073,32 +3073,40 @@
 elIndex = 0;%0A   
+   idx =
  requestChannels
@@ -3096,36 +3096,36 @@
 = requestChannel
-s%5Bid
+Inde
 x %25 requestChann
@@ -3126,32 +3126,63 @@
 tChannels.length
+;%0A    %7D%0A    requestChannels%5Bidx
 %5D.sendRequest(re
@@ -3267,18 +3267,61 @@
  int idx
+;%0A    synchronized (responseChannels) %7B%0A    
  
-=
  respons
@@ -3337,39 +3337,75 @@
 ndex++;%0A    
+  
 if (
-idx %3C 0) id
+responseChannelIndex %3C 0) responseChannelInde
 x = 0;%0A    r
@@ -3398,24 +3398,32 @@
 dex = 0;%0A   
+   idx =
  responseCha
@@ -3422,28 +3422,28 @@
 ponseChannel
-s%5Bid
+Inde
 x %25 response
@@ -3453,24 +3453,56 @@
 nnels.length
+;%0A    %7D%0A    responseChannels%5Bidx
 %5D.sendRespon
@@ -3825,24 +3825,27 @@
 inaryRequest
+%3C?%3E
  request) %7B%0A
@@ -3851,26 +3851,68 @@
 %0A    int idx
+;%0A    synchronized (requestChannels) %7B%0A    
  
-=
  requestChan
@@ -3931,23 +3931,57 @@
     
+  
 if (
-idx %3C 0) id
+requestChannelIndex %3C 0) requestChannelInde
 x = 
@@ -3982,24 +3982,32 @@
 dex = 0;%0A   
+   idx =
  requestChan
@@ -4009,20 +4009,20 @@
 tChannel
-s%5Bid
+Inde
 x %25 requ
@@ -4039,16 +4039,47 @@
 s.length
+;%0A    %7D%0A    requestChannels%5Bidx
 %5D.sendBi

Fix bad math on channel indexes