com.cisco.oss.foundation.loadbalancer.StickyRoundRobinStrategy.java Source code

Java tutorial

Introduction

Here is the source code for com.cisco.oss.foundation.loadbalancer.StickyRoundRobinStrategy.java

Source

/*
 * Copyright 2015 Cisco Systems, Inc.
 *
 *  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.
 */

package com.cisco.oss.foundation.loadbalancer;

import com.cisco.oss.foundation.flowcontext.FlowContext;
import com.cisco.oss.foundation.flowcontext.FlowContextFactory;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * this is the sticky round robin strategy implementation. this strategy delegates the
 * requests to different servers each time. this way the load is balanced
 * between more than 1 server.
 * if multiple requstes are initialized from the same client using the same flowcontext it will be directed to the same server node.
 *
 * @author Yair Ogen
 */
public class StickyRoundRobinStrategy<S extends ClientRequest> extends RoundRobinStrategy<S> {

    private static final String FLOW_CONTEXT = "FLOW_CONTEXT";
    private static final long serialVersionUID = -4176790456291346233L;
    private static final Logger LOGGER = LoggerFactory.getLogger(StickyRoundRobinStrategy.class);
    private String hashField = FLOW_CONTEXT;

    public StickyRoundRobinStrategy(String serviceName, boolean serviceDirectoryEnabled, long waitingTime,
            String clientName, long retryDelay, int numberOfAttempts) {
        super(serviceName, serviceDirectoryEnabled, waitingTime, clientName, retryDelay, numberOfAttempts);
    }

    @Override
    protected int nextNode(int serverProxisListSize, S request) {
        int hash = getHash(request);
        if (hash == -1) {
            return super.nextNode(serverProxisListSize, request);
        } else {
            int serverIndex = determineNextNode(hash, serverProxisListSize);
            if (serverIndex == -1) {
                return super.nextNode(serverProxisListSize, request);
            } else {
                return serverIndex;
            }
        }

    }

    private int getHash(S request) {

        String hashField = request.getLbKey();

        if (StringUtils.isNotBlank(hashField)) {
            if (FLOW_CONTEXT.equals(hashField)) {
                FlowContext flowContext = FlowContextFactory.getFlowContext();
                if (flowContext != null) {
                    return flowContext.hashCode();
                }
            } else {
                return hashField.hashCode();
            }
        }
        return -1;
    }

    private int determineNextNode(int hash, int serverProxisListSize) {

        int serverIndex = -1;

        //run from the end to the begining
        for (int i = serverProxisListSize; i > 0; i--) {
            if (hash % i == 0) {
                LOGGER.trace("node {} chosen for hash {}", i, hash);
                serverIndex = i - 1;
                break;
            }
        }

        final InternalServerProxy serverProxy = getServerProxies().get(serverIndex);
        if (!serverProxy.activate()) {
            serverIndex = -1;
        }

        LOGGER.debug("defaulting to regular round robin mode");
        return serverIndex;
    }

    public String getHashField() {
        return hashField;
    }

    public void setHashField(String hashField) {
        this.hashField = hashField;
    }

}