KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > cache > buddyreplication > NextMemberBuddyLocator


1 /*
2  * JBoss, Home of Professional Open Source
3  *
4  * Distributable under LGPL license.
5  * See terms of license at gnu.org.
6  */

7 package org.jboss.cache.buddyreplication;
8
9 import org.apache.commons.logging.Log;
10 import org.apache.commons.logging.LogFactory;
11 import org.jboss.cache.config.BuddyReplicationConfig.BuddyLocatorConfig;
12 import org.jgroups.Address;
13 import org.jgroups.stack.IpAddress;
14
15 import java.net.InetAddress JavaDoc;
16 import java.net.NetworkInterface JavaDoc;
17 import java.net.SocketException JavaDoc;
18 import java.util.ArrayList JavaDoc;
19 import java.util.Enumeration JavaDoc;
20 import java.util.List JavaDoc;
21 import java.util.Map JavaDoc;
22
23 /**
24  * This buddy locator uses a next-in-line algorithm to select buddies for a buddy group.
25  * This algorithm allows for the following properties, all of which are optional.
26  * <p/>
27  * <ul>
28  * <li>More than one buddy per group - the <b>numBuddies</b> property, defaulting to 1 if ommitted.</li>
29  * <li>Ability to skip buddies on the same host when selecting buddies - the <b>ignoreColocatedBuddies</b>
30  * property, defaulting to true if ommitted. Note that this is just a hint though, and if all nstances in
31  * a cluster are colocated, the algorithm will be forced to pick a colocated instance even if this is property
32  * set to true.</li>
33  * </ul>
34  *
35  * @author <a HREF="mailto:manik@jboss.org">Manik Surtani (manik@jboss.org)</a>
36  */

37 public class NextMemberBuddyLocator implements BuddyLocator
38 {
39    private Log log = LogFactory.getLog(NextMemberBuddyLocator.class);
40
41    private NextMemberBuddyLocatorConfig config = new NextMemberBuddyLocatorConfig();
42
43    public BuddyLocatorConfig getConfig()
44    {
45       return config;
46    }
47
48    public void init(BuddyLocatorConfig buddyLocatorConfig)
49    {
50       if (buddyLocatorConfig instanceof NextMemberBuddyLocatorConfig)
51       {
52          this.config = (NextMemberBuddyLocatorConfig) buddyLocatorConfig;
53       }
54       else if (buddyLocatorConfig != null)
55       {
56          this.config = new NextMemberBuddyLocatorConfig(buddyLocatorConfig);
57       }
58       else
59       {
60          // We were passed null; just use a default config
61
this.config = new NextMemberBuddyLocatorConfig();
62       }
63    }
64
65    public List JavaDoc<Address> locateBuddies(Map JavaDoc<Address, String JavaDoc> buddyPoolMap, List JavaDoc<Address> currentMembership, Address dataOwner)
66    {
67       int numBuddiesToFind = Math.min(config.getNumBuddies(), currentMembership.size());
68       List JavaDoc<Address> buddies = new ArrayList JavaDoc<Address>(numBuddiesToFind);
69
70       // find where we are in the list.
71
int dataOwnerSubscript = currentMembership.indexOf(dataOwner);
72       int i = 0;
73       boolean ignoreColocatedBuddiesForSession = config.isIgnoreColocatedBuddies();
74
75
76       while (buddies.size() < numBuddiesToFind)
77       {
78          int subscript = i + dataOwnerSubscript + 1;
79          // make sure we loop around the list
80
if (subscript >= currentMembership.size()) subscript = subscript - currentMembership.size();
81
82          // now if subscript is STILL greater than or equal to the current membership size, we've looped around
83
// completely and still havent found any more suitable candidates. Try with colocation hint disabled.
84
if (subscript >= currentMembership.size() && ignoreColocatedBuddiesForSession)
85          {
86             ignoreColocatedBuddiesForSession = false;
87             i = 0;
88             if (log.isInfoEnabled())
89                log.info("Expected to look for " + numBuddiesToFind + " buddies but could only find " + buddies.size() + " suitable candidates - trying with colocated buddies as well.");
90
91             continue;
92          }
93
94          // now try disabling the buddy pool
95
if (subscript >= currentMembership.size() && buddyPoolMap != null)
96          {
97             buddyPoolMap = null;
98             ignoreColocatedBuddiesForSession = config.isIgnoreColocatedBuddies(); // reset this flag
99
i = 0;
100             if (log.isInfoEnabled())
101                log.info("Expected to look for " + numBuddiesToFind + " buddies but could only find " + buddies.size() + " suitable candidates - trying again, ignoring buddy pool hints.");
102             continue;
103          }
104
105          // now if subscript is STILL greater than or equal to the current membership size, we've looped around
106
// completely and still havent found any more suitable candidates. Give up with however many we have.
107
if (subscript >= currentMembership.size())
108          {
109             if (log.isInfoEnabled())
110                log.info("Expected to look for " + numBuddiesToFind + " buddies but could only find " + buddies.size() + " suitable candidates!");
111             break;
112          }
113
114          Address candidate = currentMembership.get(subscript);
115          if (
116                  !candidate.equals(dataOwner) && // ignore self from selection as buddy
117
!buddies.contains(candidate) && // havent already considered this candidate
118
(!ignoreColocatedBuddiesForSession || !isColocated(candidate, dataOwner)) && // ignore colocated buddies
119
(isInSameBuddyPool(buddyPoolMap, candidate, dataOwner)) // try and find buddies in the same buddy pool first
120
)
121          {
122             buddies.add(candidate);
123          }
124          i++;
125       }
126
127       if (log.isTraceEnabled()) log.trace("Selected buddy group as " + buddies);
128       return buddies;
129    }
130
131    private boolean isInSameBuddyPool(Map JavaDoc<Address, String JavaDoc> buddyPoolMap, Address candidate, Address dataOwner)
132    {
133       if (buddyPoolMap == null) return true;
134       Object JavaDoc ownerPoolName = buddyPoolMap.get(dataOwner);
135       Object JavaDoc candidatePoolName = buddyPoolMap.get(candidate);
136       return !(ownerPoolName == null || candidatePoolName == null) && ownerPoolName.equals(candidatePoolName);
137    }
138
139    private boolean isColocated(Address candidate, Address dataOwner)
140    {
141       // assume they're both IpAddresses??
142
InetAddress JavaDoc inetC = ((IpAddress) candidate).getIpAddress();
143       InetAddress JavaDoc inetD = ((IpAddress) dataOwner).getIpAddress();
144
145       if (inetC.equals(inetD)) return true;
146
147       // now check other interfaces.
148
try
149       {
150          for (Enumeration JavaDoc<NetworkInterface JavaDoc> nics = NetworkInterface.getNetworkInterfaces(); nics.hasMoreElements();)
151          {
152             NetworkInterface JavaDoc i = nics.nextElement();
153             for (Enumeration JavaDoc<InetAddress JavaDoc> addrs = i.getInetAddresses(); addrs.hasMoreElements();)
154             {
155                InetAddress JavaDoc addr = addrs.nextElement();
156                if (addr.equals(inetC)) return true;
157             }
158          }
159       }
160       catch (SocketException JavaDoc e)
161       {
162          if (log.isDebugEnabled()) log.debug("Unable to read NICs on host", e);
163          if (log.isWarnEnabled())
164          {
165             log.warn("UNable to read all network interfaces on host " + inetD + " to determine colocation of " + inetC + ". Assuming " + inetC + " is NOT colocated with " + inetD);
166          }
167       }
168
169       return false;
170    }
171 }
Popular Tags