All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.postgresql.hostchooser.MultiHostChooser Maven / Gradle / Ivy

There is a newer version: 42.7.3
Show newest version
/*-------------------------------------------------------------------------
 *
 * Copyright (c) 2014, PostgreSQL Global Development Group
 *
 *
 *-------------------------------------------------------------------------
 */
package org.postgresql.hostchooser;

import static java.lang.Boolean.parseBoolean;
import static java.lang.Integer.parseInt;
import static java.util.Arrays.asList;
import static java.util.Collections.shuffle;
import static java.util.Collections.sort;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;

import org.postgresql.hostchooser.GlobalHostStatusTracker.HostSpecStatus;
import org.postgresql.util.HostSpec;

/**
 * HostChooser that keeps track of known host statuses.
 */
public class MultiHostChooser implements HostChooser {
    private HostSpec[] hostSpecs;
    private final HostRequirement targetServerType;
    private int hostRecheckTime;
    private boolean loadBalance;

    protected MultiHostChooser(HostSpec[] hostSpecs, HostRequirement targetServerType, Properties info) {
        this.hostSpecs = hostSpecs;
        this.targetServerType = targetServerType;
        hostRecheckTime = parseInt(info.getProperty("hostRecheckSeconds", "10")) * 1000;
        loadBalance = parseBoolean(info.getProperty("loadBalanceHosts", "false"));
    }

    public Iterator iterator() {
        List candidates = GlobalHostStatusTracker.getCandidateHosts(hostSpecs, targetServerType, hostRecheckTime);
        // if no candidates are suitable (all wrong type or unavailable) then we try original list in order
        if (candidates.isEmpty()) {
            return asList(hostSpecs).iterator();
        }
        if (candidates.size() == 1) {
            return asList(candidates.get(0).host).iterator();
        }
        sortCandidates(candidates);
        shuffleGoodHosts(candidates);
        return extractHostSpecs(candidates).iterator();
    }

    private void sortCandidates(List candidates) {
        if (targetServerType == HostRequirement.any) {
            return;
        }
        sort(candidates, new HostSpecByTargetServerTypeComparator());
    }

    private void shuffleGoodHosts(List candidates) {
        if (!loadBalance) {
            return;
        }
        int count;
        for (count = 1; count < candidates.size(); count++) {
            HostSpecStatus hostSpecStatus = candidates.get(count);
            if (hostSpecStatus.status != null && !targetServerType.allowConnectingTo(hostSpecStatus.status)) {
                break;
            }
        }
        if (count == 1) {
            return;
        }
        List goodHosts = candidates.subList(0, count);
        shuffle(goodHosts);
    }

    private List extractHostSpecs(List hostSpecStatuses) {
        List hostSpecs = new ArrayList(hostSpecStatuses.size());
        for (HostSpecStatus hostSpecStatus : hostSpecStatuses) {
            hostSpecs.add(hostSpecStatus.host);
        }
        return hostSpecs;
    }

    class HostSpecByTargetServerTypeComparator implements Comparator {
        @Override
        public int compare(HostSpecStatus o1, HostSpecStatus o2) {
            int r1 = rank(o1.status, targetServerType);
            int r2 = rank(o2.status, targetServerType);
            return r1 == r2 ? 0 : r1 > r2 ? -1 : 1;
        }

        private int rank(HostStatus status, HostRequirement targetServerType) {
            if (status == HostStatus.ConnectFail) {
                return -1;
            }
            switch (targetServerType) {
            case master:
                return status == HostStatus.Master || status == null ? 1 : 0;
            case slave:
                return status == HostStatus.Slave || status == null ? 1 : 0;
            case preferSlave:
                return status == HostStatus.Slave || status == null ? 2 : status == HostStatus.Master ? 1 : 0;
            default:
                return 0;
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy