001/*
002 * HA-JDBC: High-Availability JDBC
003 * Copyright (C) 2012  Paul Ferraro
004 *
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU Lesser General Public License as published by
007 * the Free Software Foundation, either version 3 of the License, or
008 * (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 * GNU Lesser General Public License for more details.
014 *
015 * You should have received a copy of the GNU Lesser General Public License
016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017 */
018package net.sf.hajdbc.balancer.roundrobin;
019
020import java.util.LinkedList;
021import java.util.Queue;
022import java.util.Set;
023
024import net.sf.hajdbc.Database;
025import net.sf.hajdbc.balancer.AbstractSetBalancer;
026
027/**
028 * Balancer implementation whose {@link #next()} implementation uses a circular FIFO queue.
029 * 
030 * @author  Paul Ferraro
031 * @param <D> either java.sql.Driver or javax.sql.DataSource
032 */
033public class RoundRobinBalancer<P, D extends Database<P>> extends AbstractSetBalancer<P, D>
034{
035        private Queue<D> databaseQueue = new LinkedList<D>();
036
037        /**
038         * Constructs a new RoundRobinBalancer
039         * @param databases
040         */
041        public RoundRobinBalancer(Set<D> databases)
042        {
043                super(databases);
044                
045                for (D database: databases)
046                {
047                        this.added(database);
048                }
049        }
050        
051        /**
052         * {@inheritDoc}
053         * @see net.sf.hajdbc.balancer.AbstractSetBalancer#added(net.sf.hajdbc.Database)
054         */
055        @Override
056        protected void added(D database)
057        {
058                int weight = database.getWeight();
059                
060                for (int i = 0; i < weight; ++i)
061                {
062                        this.databaseQueue.add(database);
063                }
064        }
065
066        /**
067         * {@inheritDoc}
068         * @see net.sf.hajdbc.balancer.AbstractSetBalancer#removed(net.sf.hajdbc.Database)
069         */
070        @Override
071        protected void removed(D database)
072        {
073                int weight = database.getWeight();
074                
075                for (int i = 0; i < weight; ++i)
076                {
077                        this.databaseQueue.remove(database);
078                }
079        }
080        
081        /**
082         * {@inheritDoc}
083         * @see net.sf.hajdbc.balancer.Balancer#next()
084         */
085        @Override
086        public D next()
087        {
088                this.getLock().lock();
089                
090                try
091                {
092                        if (this.databaseQueue.isEmpty())
093                        {
094                                return this.primary();
095                        }
096                        
097                        if (this.databaseQueue.size() == 1)
098                        {
099                                return this.databaseQueue.element();
100                        }
101                        
102                        D database = this.databaseQueue.remove();
103                        
104                        this.databaseQueue.add(database);
105                        
106                        return database;
107                }
108                finally
109                {
110                        this.getLock().unlock();
111                }
112        }
113
114        /**
115         * {@inheritDoc}
116         * @see net.sf.hajdbc.balancer.AbstractSetBalancer#cleared()
117         */
118        @Override
119        protected void cleared()
120        {
121                this.databaseQueue.clear();
122        }
123}