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

cn.bridgeli.masterslavedbselector.MasterSlaveSelectorByPoll Maven / Gradle / Ivy

package cn.bridgeli.masterslavedbselector;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 数据库选择器
 */
public class MasterSlaveSelectorByPoll implements MasterSlaveSelector {

    private static final Logger logger = LoggerFactory.getLogger(MasterSlaveSelectorByPoll.class);

    public static final ThreadLocal holder = new ThreadLocal();

    private List masters;

    private List slaves;

    private AtomicInteger selectedMasterIndex = new AtomicInteger(0);
    private AtomicInteger selectedSlavesIndex = new AtomicInteger(0);

    private List badMasters = Collections.synchronizedList(new ArrayList());
    private List badSlaves = Collections.synchronizedList(new ArrayList());

    private DataSource defaultDataSource;

    @Override
    public DataSource get() {
        DataSource ds = holder.get();
        return ds == null ? defaultDataSource : ds;
    }

    @Override
    public void master() {
        logger.debug("change master!");
        if (!masters.contains(holder.get())) {
            holder.set(getNext(selectedMasterIndex, masters));
        }
    }

    /**
     * 获取下个目标
     */
    private DataSource getNext(AtomicInteger selectedIndex, List sources) {
        if (sources.isEmpty()) {
            throw new RuntimeException("No datasource available.");
        }
        selectedIndex.weakCompareAndSet(sources.size(), 0);
        return sources.get(selectedIndex.getAndIncrement() % sources.size());
    }

    @Override
    public void slave() {
        logger.debug("change slave!");
        if (holder.get() == null) {
            holder.set(getNext(selectedSlavesIndex, slaves));
        }
    }

    @Override
    public void monitor() {
        checkRestore(badMasters, masters);
        checkRestore(badSlaves, slaves);
        checkBadDataSource(masters, badMasters);
        checkBadDataSource(slaves, badSlaves);
    }

    /**
     * 检查异常的数据源是否恢复了
     */
    private void checkBadDataSource(List normalDataSources,
                                    List badDataSources) {
        for (DataSource ds : normalDataSources) {
            try {
                ds.getConnection();
                ds.getConnection().close();
            } catch (Exception e) {
                badDataSources.add(ds);
                logger.error("Check new database error! database:" + ds, e.toString());
            }
        }
    }

    /**
     * 检查恢复的数据库
     */
    private void checkRestore(List badDataSources, List normalDataSources) {
        for (DataSource ds : badDataSources) {
            try {
                ds.getConnection();
                ds.getConnection().close();
                normalDataSources.add(ds);
            } catch (SQLException e) {
                logger.error("Continue database error! database:" + ds, e.toString());
            }
        }
    }

    /**
     * Setter method for property masters.
     *
     * @param masters value to be assigned to property masters
     */
    public void setMasters(List masters) {
        this.masters = Collections.synchronizedList(masters);
    }

    /**
     * Setter method for property slaves.
     *
     * @param slaves value to be assigned to property slaves
     */
    public void setSlaves(List slaves) {
        this.slaves = Collections.synchronizedList(slaves);
    }

    /**
     * Setter method for property defaultDataSource.
     *
     * @param defaultDataSource value to be assigned to property defaultDataSource
     */
    public void setDefaultDataSource(DataSource defaultDataSource) {
        this.defaultDataSource = defaultDataSource;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy