001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2010 Sun Microsystems, Inc. 025 * Portions copyright 2013 ForgeRock AS. 026 */ 027 028package org.forgerock.opendj.ldap; 029 030import java.util.Collection; 031import java.util.concurrent.ScheduledExecutorService; 032import java.util.concurrent.TimeUnit; 033import java.util.concurrent.atomic.AtomicInteger; 034 035/** 036 * A round robin load balancing algorithm distributes connection requests across 037 * a list of connection factories one at a time. When the end of the list is 038 * reached, the algorithm starts again from the beginning. 039 * <p> 040 * This algorithm is typically used for load-balancing <i>within</i> data 041 * centers, where load must be distributed equally across multiple data sources. 042 * This algorithm contrasts with the {@link FailoverLoadBalancingAlgorithm} 043 * which is used for load-balancing <i>between</i> data centers. 044 * <p> 045 * If a problem occurs that temporarily prevents connections from being obtained 046 * for one of the connection factories, then this algorithm automatically 047 * "fails over" to the next operational connection factory in the list. If none 048 * of the connection factories are operational then a 049 * {@code ConnectionException} is returned to the client. 050 * <p> 051 * The implementation periodically attempts to connect to failed connection 052 * factories in order to determine if they have become available again. 053 * 054 * @see FailoverLoadBalancingAlgorithm 055 * @see Connections#newLoadBalancer(LoadBalancingAlgorithm) 056 */ 057public final class RoundRobinLoadBalancingAlgorithm extends AbstractLoadBalancingAlgorithm { 058 private final int maxIndex; 059 private final AtomicInteger nextIndex = new AtomicInteger(-1); 060 061 /** 062 * Creates a new round robin load balancing algorithm which will monitor 063 * offline connection factories every 1 second using the default scheduler. 064 * 065 * @param factories 066 * The ordered collection of connection factories. 067 */ 068 public RoundRobinLoadBalancingAlgorithm(final Collection<? extends ConnectionFactory> factories) { 069 this(factories, null, 1, TimeUnit.SECONDS, null); 070 } 071 072 /** 073 * Creates a new round robin load balancing algorithm which will monitor 074 * offline connection factories every 1 second using the default scheduler. 075 * 076 * @param factories 077 * The ordered collection of connection factories. 078 * @param listener 079 * The event listener which should be notified whenever a 080 * connection factory changes state from online to offline or 081 * vice-versa. 082 */ 083 public RoundRobinLoadBalancingAlgorithm( 084 final Collection<? extends ConnectionFactory> factories, 085 final LoadBalancerEventListener listener) { 086 this(factories, listener, 1, TimeUnit.SECONDS, null); 087 } 088 089 /** 090 * Creates a new round robin load balancing algorithm which will monitor 091 * offline connection factories using the specified frequency using the 092 * default scheduler. 093 * 094 * @param factories 095 * The connection factories. 096 * @param listener 097 * The event listener which should be notified whenever a 098 * connection factory changes state from online to offline or 099 * vice-versa. 100 * @param interval 101 * The interval between attempts to poll offline factories. 102 * @param unit 103 * The time unit for the interval between attempts to poll 104 * offline factories. 105 */ 106 public RoundRobinLoadBalancingAlgorithm( 107 final Collection<? extends ConnectionFactory> factories, 108 final LoadBalancerEventListener listener, final long interval, final TimeUnit unit) { 109 this(factories, null, interval, unit, null); 110 } 111 112 /** 113 * Creates a new round robin load balancing algorithm which will monitor 114 * offline connection factories using the specified frequency and scheduler. 115 * 116 * @param factories 117 * The connection factories. 118 * @param listener 119 * The event listener which should be notified whenever a 120 * connection factory changes state from online to offline or 121 * vice-versa. 122 * @param interval 123 * The interval between attempts to poll offline factories. 124 * @param unit 125 * The time unit for the interval between attempts to poll 126 * offline factories. 127 * @param scheduler 128 * The scheduler which should for periodically monitoring dead 129 * connection factories to see if they are usable again. 130 */ 131 public RoundRobinLoadBalancingAlgorithm( 132 final Collection<? extends ConnectionFactory> factories, 133 final LoadBalancerEventListener listener, final long interval, final TimeUnit unit, 134 final ScheduledExecutorService scheduler) { 135 super(factories, listener, interval, unit, scheduler); 136 this.maxIndex = factories.size(); 137 } 138 139 /** 140 * Creates a new round robin load balancing algorithm which will monitor 141 * offline connection factories using the specified frequency using the 142 * default scheduler. 143 * 144 * @param factories 145 * The connection factories. 146 * @param interval 147 * The interval between attempts to poll offline factories. 148 * @param unit 149 * The time unit for the interval between attempts to poll 150 * offline factories. 151 */ 152 public RoundRobinLoadBalancingAlgorithm( 153 final Collection<? extends ConnectionFactory> factories, final long interval, 154 final TimeUnit unit) { 155 this(factories, null, interval, unit, null); 156 } 157 158 /** 159 * Creates a new round robin load balancing algorithm which will monitor 160 * offline connection factories using the specified frequency and scheduler. 161 * 162 * @param factories 163 * The connection factories. 164 * @param interval 165 * The interval between attempts to poll offline factories. 166 * @param unit 167 * The time unit for the interval between attempts to poll 168 * offline factories. 169 * @param scheduler 170 * The scheduler which should for periodically monitoring dead 171 * connection factories to see if they are usable again. 172 */ 173 public RoundRobinLoadBalancingAlgorithm( 174 final Collection<? extends ConnectionFactory> factories, final long interval, 175 final TimeUnit unit, final ScheduledExecutorService scheduler) { 176 this(factories, null, interval, unit, scheduler); 177 } 178 179 /** {@inheritDoc} */ 180 @Override 181 String getAlgorithmName() { 182 return "RoundRobin"; 183 } 184 185 /** {@inheritDoc} */ 186 @Override 187 int getInitialConnectionFactoryIndex() { 188 // A round robin pool of one connection factories is unlikely in 189 // practice and requires special treatment. 190 if (maxIndex == 1) { 191 return 0; 192 } 193 194 // Determine the next factory to use: avoid blocking algorithm. 195 int oldNextIndex; 196 int newNextIndex; 197 do { 198 oldNextIndex = nextIndex.get(); 199 newNextIndex = oldNextIndex + 1; 200 if (newNextIndex == maxIndex) { 201 newNextIndex = 0; 202 } 203 } while (!nextIndex.compareAndSet(oldNextIndex, newNextIndex)); 204 205 // There's a potential, but benign, race condition here: other threads 206 // could jump in and rotate through the list before we return the 207 // connection factory. 208 return newNextIndex; 209 } 210 211}