Published site at d5aaeee88b331e064830a2774f4fed238631457c.
[hbase-site.git] / devapidocs / src-html / org / apache / hadoop / hbase / rsgroup / RSGroupBasedLoadBalancer.html
1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
2 <html lang="en">
3 <head>
4 <title>Source code</title>
5 <link rel="stylesheet" type="text/css" href="../../../../../../stylesheet.css" title="Style">
6 </head>
7 <body>
8 <div class="sourceContainer">
9 <pre><span class="sourceLineNo">001</span>/**<a name="line.1"></a>
10 <span class="sourceLineNo">002</span> * Licensed to the Apache Software Foundation (ASF) under one<a name="line.2"></a>
11 <span class="sourceLineNo">003</span> * or more contributor license agreements. See the NOTICE file<a name="line.3"></a>
12 <span class="sourceLineNo">004</span> * distributed with this work for additional information<a name="line.4"></a>
13 <span class="sourceLineNo">005</span> * regarding copyright ownership. The ASF licenses this file<a name="line.5"></a>
14 <span class="sourceLineNo">006</span> * to you under the Apache License, Version 2.0 (the<a name="line.6"></a>
15 <span class="sourceLineNo">007</span> * "License"); you may not use this file except in compliance<a name="line.7"></a>
16 <span class="sourceLineNo">008</span> * with the License. You may obtain a copy of the License at<a name="line.8"></a>
17 <span class="sourceLineNo">009</span> *<a name="line.9"></a>
18 <span class="sourceLineNo">010</span> * http://www.apache.org/licenses/LICENSE-2.0<a name="line.10"></a>
19 <span class="sourceLineNo">011</span> *<a name="line.11"></a>
20 <span class="sourceLineNo">012</span> * Unless required by applicable law or agreed to in writing, software<a name="line.12"></a>
21 <span class="sourceLineNo">013</span> * distributed under the License is distributed on an "AS IS" BASIS,<a name="line.13"></a>
22 <span class="sourceLineNo">014</span> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.<a name="line.14"></a>
23 <span class="sourceLineNo">015</span> * See the License for the specific language governing permissions and<a name="line.15"></a>
24 <span class="sourceLineNo">016</span> * limitations under the License.<a name="line.16"></a>
25 <span class="sourceLineNo">017</span> */<a name="line.17"></a>
26 <span class="sourceLineNo">018</span><a name="line.18"></a>
27 <span class="sourceLineNo">019</span>package org.apache.hadoop.hbase.rsgroup;<a name="line.19"></a>
28 <span class="sourceLineNo">020</span><a name="line.20"></a>
29 <span class="sourceLineNo">021</span>import java.io.IOException;<a name="line.21"></a>
30 <span class="sourceLineNo">022</span>import java.util.ArrayList;<a name="line.22"></a>
31 <span class="sourceLineNo">023</span>import java.util.Collections;<a name="line.23"></a>
32 <span class="sourceLineNo">024</span>import java.util.HashMap;<a name="line.24"></a>
33 <span class="sourceLineNo">025</span>import java.util.HashSet;<a name="line.25"></a>
34 <span class="sourceLineNo">026</span>import java.util.LinkedList;<a name="line.26"></a>
35 <span class="sourceLineNo">027</span>import java.util.List;<a name="line.27"></a>
36 <span class="sourceLineNo">028</span>import java.util.Map;<a name="line.28"></a>
37 <span class="sourceLineNo">029</span>import java.util.Set;<a name="line.29"></a>
38 <span class="sourceLineNo">030</span>import java.util.TreeMap;<a name="line.30"></a>
39 <span class="sourceLineNo">031</span><a name="line.31"></a>
40 <span class="sourceLineNo">032</span>import org.apache.hadoop.conf.Configuration;<a name="line.32"></a>
41 <span class="sourceLineNo">033</span>import org.apache.hadoop.hbase.ClusterMetrics;<a name="line.33"></a>
42 <span class="sourceLineNo">034</span>import org.apache.hadoop.hbase.HBaseIOException;<a name="line.34"></a>
43 <span class="sourceLineNo">035</span>import org.apache.hadoop.hbase.HConstants;<a name="line.35"></a>
44 <span class="sourceLineNo">036</span>import org.apache.hadoop.hbase.ServerName;<a name="line.36"></a>
45 <span class="sourceLineNo">037</span>import org.apache.hadoop.hbase.TableName;<a name="line.37"></a>
46 <span class="sourceLineNo">038</span>import org.apache.hadoop.hbase.client.RegionInfo;<a name="line.38"></a>
47 <span class="sourceLineNo">039</span>import org.apache.hadoop.hbase.constraint.ConstraintException;<a name="line.39"></a>
48 <span class="sourceLineNo">040</span>import org.apache.hadoop.hbase.master.LoadBalancer;<a name="line.40"></a>
49 <span class="sourceLineNo">041</span>import org.apache.hadoop.hbase.master.MasterServices;<a name="line.41"></a>
50 <span class="sourceLineNo">042</span>import org.apache.hadoop.hbase.master.RegionPlan;<a name="line.42"></a>
51 <span class="sourceLineNo">043</span>import org.apache.hadoop.hbase.master.balancer.StochasticLoadBalancer;<a name="line.43"></a>
52 <span class="sourceLineNo">044</span>import org.apache.hadoop.hbase.net.Address;<a name="line.44"></a>
53 <span class="sourceLineNo">045</span>import org.apache.hadoop.hbase.util.Pair;<a name="line.45"></a>
54 <span class="sourceLineNo">046</span>import org.apache.hadoop.util.ReflectionUtils;<a name="line.46"></a>
55 <span class="sourceLineNo">047</span>import org.apache.yetus.audience.InterfaceAudience;<a name="line.47"></a>
56 <span class="sourceLineNo">048</span>import org.slf4j.Logger;<a name="line.48"></a>
57 <span class="sourceLineNo">049</span>import org.slf4j.LoggerFactory;<a name="line.49"></a>
58 <span class="sourceLineNo">050</span><a name="line.50"></a>
59 <span class="sourceLineNo">051</span>import org.apache.hbase.thirdparty.com.google.common.annotations.VisibleForTesting;<a name="line.51"></a>
60 <span class="sourceLineNo">052</span>import org.apache.hbase.thirdparty.com.google.common.collect.ArrayListMultimap;<a name="line.52"></a>
61 <span class="sourceLineNo">053</span>import org.apache.hbase.thirdparty.com.google.common.collect.LinkedListMultimap;<a name="line.53"></a>
62 <span class="sourceLineNo">054</span>import org.apache.hbase.thirdparty.com.google.common.collect.ListMultimap;<a name="line.54"></a>
63 <span class="sourceLineNo">055</span>import org.apache.hbase.thirdparty.com.google.common.collect.Lists;<a name="line.55"></a>
64 <span class="sourceLineNo">056</span>import org.apache.hbase.thirdparty.com.google.common.collect.Maps;<a name="line.56"></a>
65 <span class="sourceLineNo">057</span><a name="line.57"></a>
66 <span class="sourceLineNo">058</span>/**<a name="line.58"></a>
67 <span class="sourceLineNo">059</span> * GroupBasedLoadBalancer, used when Region Server Grouping is configured (HBase-6721)<a name="line.59"></a>
68 <span class="sourceLineNo">060</span> * It does region balance based on a table's group membership.<a name="line.60"></a>
69 <span class="sourceLineNo">061</span> *<a name="line.61"></a>
70 <span class="sourceLineNo">062</span> * Most assignment methods contain two exclusive code paths: Online - when the group<a name="line.62"></a>
71 <span class="sourceLineNo">063</span> * table is online and Offline - when it is unavailable.<a name="line.63"></a>
72 <span class="sourceLineNo">064</span> *<a name="line.64"></a>
73 <span class="sourceLineNo">065</span> * During Offline, assignments are assigned based on cached information in zookeeper.<a name="line.65"></a>
74 <span class="sourceLineNo">066</span> * If unavailable (ie bootstrap) then regions are assigned randomly.<a name="line.66"></a>
75 <span class="sourceLineNo">067</span> *<a name="line.67"></a>
76 <span class="sourceLineNo">068</span> * Once the GROUP table has been assigned, the balancer switches to Online and will then<a name="line.68"></a>
77 <span class="sourceLineNo">069</span> * start providing appropriate assignments for user tables.<a name="line.69"></a>
78 <span class="sourceLineNo">070</span> *<a name="line.70"></a>
79 <span class="sourceLineNo">071</span> */<a name="line.71"></a>
80 <span class="sourceLineNo">072</span>@InterfaceAudience.Private<a name="line.72"></a>
81 <span class="sourceLineNo">073</span>public class RSGroupBasedLoadBalancer implements RSGroupableBalancer {<a name="line.73"></a>
82 <span class="sourceLineNo">074</span> private static final Logger LOG = LoggerFactory.getLogger(RSGroupBasedLoadBalancer.class);<a name="line.74"></a>
83 <span class="sourceLineNo">075</span><a name="line.75"></a>
84 <span class="sourceLineNo">076</span> private Configuration config;<a name="line.76"></a>
85 <span class="sourceLineNo">077</span> private ClusterMetrics clusterStatus;<a name="line.77"></a>
86 <span class="sourceLineNo">078</span> private MasterServices masterServices;<a name="line.78"></a>
87 <span class="sourceLineNo">079</span> private volatile RSGroupInfoManager rsGroupInfoManager;<a name="line.79"></a>
88 <span class="sourceLineNo">080</span> private LoadBalancer internalBalancer;<a name="line.80"></a>
89 <span class="sourceLineNo">081</span><a name="line.81"></a>
90 <span class="sourceLineNo">082</span> /**<a name="line.82"></a>
91 <span class="sourceLineNo">083</span> * Used by reflection in {@link org.apache.hadoop.hbase.master.balancer.LoadBalancerFactory}.<a name="line.83"></a>
92 <span class="sourceLineNo">084</span> */<a name="line.84"></a>
93 <span class="sourceLineNo">085</span> @InterfaceAudience.Private<a name="line.85"></a>
94 <span class="sourceLineNo">086</span> public RSGroupBasedLoadBalancer() {}<a name="line.86"></a>
95 <span class="sourceLineNo">087</span><a name="line.87"></a>
96 <span class="sourceLineNo">088</span> @Override<a name="line.88"></a>
97 <span class="sourceLineNo">089</span> public Configuration getConf() {<a name="line.89"></a>
98 <span class="sourceLineNo">090</span> return config;<a name="line.90"></a>
99 <span class="sourceLineNo">091</span> }<a name="line.91"></a>
100 <span class="sourceLineNo">092</span><a name="line.92"></a>
101 <span class="sourceLineNo">093</span> @Override<a name="line.93"></a>
102 <span class="sourceLineNo">094</span> public void setConf(Configuration conf) {<a name="line.94"></a>
103 <span class="sourceLineNo">095</span> this.config = conf;<a name="line.95"></a>
104 <span class="sourceLineNo">096</span> }<a name="line.96"></a>
105 <span class="sourceLineNo">097</span><a name="line.97"></a>
106 <span class="sourceLineNo">098</span> @Override<a name="line.98"></a>
107 <span class="sourceLineNo">099</span> public void setClusterMetrics(ClusterMetrics sm) {<a name="line.99"></a>
108 <span class="sourceLineNo">100</span> this.clusterStatus = sm;<a name="line.100"></a>
109 <span class="sourceLineNo">101</span> }<a name="line.101"></a>
110 <span class="sourceLineNo">102</span><a name="line.102"></a>
111 <span class="sourceLineNo">103</span> @Override<a name="line.103"></a>
112 <span class="sourceLineNo">104</span> public void setMasterServices(MasterServices masterServices) {<a name="line.104"></a>
113 <span class="sourceLineNo">105</span> this.masterServices = masterServices;<a name="line.105"></a>
114 <span class="sourceLineNo">106</span> }<a name="line.106"></a>
115 <span class="sourceLineNo">107</span><a name="line.107"></a>
116 <span class="sourceLineNo">108</span> @Override<a name="line.108"></a>
117 <span class="sourceLineNo">109</span> public List&lt;RegionPlan&gt; balanceCluster(TableName tableName, Map&lt;ServerName, List&lt;RegionInfo&gt;&gt;<a name="line.109"></a>
118 <span class="sourceLineNo">110</span> clusterState) throws HBaseIOException {<a name="line.110"></a>
119 <span class="sourceLineNo">111</span> return balanceCluster(clusterState);<a name="line.111"></a>
120 <span class="sourceLineNo">112</span> }<a name="line.112"></a>
121 <span class="sourceLineNo">113</span><a name="line.113"></a>
122 <span class="sourceLineNo">114</span> @Override<a name="line.114"></a>
123 <span class="sourceLineNo">115</span> public List&lt;RegionPlan&gt; balanceCluster(Map&lt;ServerName, List&lt;RegionInfo&gt;&gt; clusterState)<a name="line.115"></a>
124 <span class="sourceLineNo">116</span> throws HBaseIOException {<a name="line.116"></a>
125 <span class="sourceLineNo">117</span> if (!isOnline()) {<a name="line.117"></a>
126 <span class="sourceLineNo">118</span> throw new ConstraintException(RSGroupInfoManager.RSGROUP_TABLE_NAME +<a name="line.118"></a>
127 <span class="sourceLineNo">119</span> " is not online, unable to perform balance");<a name="line.119"></a>
128 <span class="sourceLineNo">120</span> }<a name="line.120"></a>
129 <span class="sourceLineNo">121</span><a name="line.121"></a>
130 <span class="sourceLineNo">122</span> // Calculate correct assignments and a list of RegionPlan for mis-placed regions<a name="line.122"></a>
131 <span class="sourceLineNo">123</span> Pair&lt;Map&lt;ServerName,List&lt;RegionInfo&gt;&gt;, List&lt;RegionPlan&gt;&gt; correctedStateAndRegionPlans =<a name="line.123"></a>
132 <span class="sourceLineNo">124</span> correctAssignments(clusterState);<a name="line.124"></a>
133 <span class="sourceLineNo">125</span> Map&lt;ServerName,List&lt;RegionInfo&gt;&gt; correctedState = correctedStateAndRegionPlans.getFirst();<a name="line.125"></a>
134 <span class="sourceLineNo">126</span> List&lt;RegionPlan&gt; regionPlans = correctedStateAndRegionPlans.getSecond();<a name="line.126"></a>
135 <span class="sourceLineNo">127</span><a name="line.127"></a>
136 <span class="sourceLineNo">128</span> // Add RegionPlan<a name="line.128"></a>
137 <span class="sourceLineNo">129</span> // for the regions which have been placed according to the region server group assignment<a name="line.129"></a>
138 <span class="sourceLineNo">130</span> // into the movement list<a name="line.130"></a>
139 <span class="sourceLineNo">131</span> try {<a name="line.131"></a>
140 <span class="sourceLineNo">132</span> List&lt;RSGroupInfo&gt; rsgi = rsGroupInfoManager.listRSGroups();<a name="line.132"></a>
141 <span class="sourceLineNo">133</span> for (RSGroupInfo info: rsgi) {<a name="line.133"></a>
142 <span class="sourceLineNo">134</span> Map&lt;ServerName, List&lt;RegionInfo&gt;&gt; groupClusterState = new HashMap&lt;&gt;();<a name="line.134"></a>
143 <span class="sourceLineNo">135</span> Map&lt;TableName, Map&lt;ServerName, List&lt;RegionInfo&gt;&gt;&gt; groupClusterLoad = new HashMap&lt;&gt;();<a name="line.135"></a>
144 <span class="sourceLineNo">136</span> for (Address sName : info.getServers()) {<a name="line.136"></a>
145 <span class="sourceLineNo">137</span> for(ServerName curr: clusterState.keySet()) {<a name="line.137"></a>
146 <span class="sourceLineNo">138</span> if(curr.getAddress().equals(sName)) {<a name="line.138"></a>
147 <span class="sourceLineNo">139</span> groupClusterState.put(curr, correctedState.get(curr));<a name="line.139"></a>
148 <span class="sourceLineNo">140</span> }<a name="line.140"></a>
149 <span class="sourceLineNo">141</span> }<a name="line.141"></a>
150 <span class="sourceLineNo">142</span> }<a name="line.142"></a>
151 <span class="sourceLineNo">143</span> groupClusterLoad.put(HConstants.ENSEMBLE_TABLE_NAME, groupClusterState);<a name="line.143"></a>
152 <span class="sourceLineNo">144</span> this.internalBalancer.setClusterLoad(groupClusterLoad);<a name="line.144"></a>
153 <span class="sourceLineNo">145</span> List&lt;RegionPlan&gt; groupPlans = this.internalBalancer<a name="line.145"></a>
154 <span class="sourceLineNo">146</span> .balanceCluster(groupClusterState);<a name="line.146"></a>
155 <span class="sourceLineNo">147</span> if (groupPlans != null) {<a name="line.147"></a>
156 <span class="sourceLineNo">148</span> regionPlans.addAll(groupPlans);<a name="line.148"></a>
157 <span class="sourceLineNo">149</span> }<a name="line.149"></a>
158 <span class="sourceLineNo">150</span> }<a name="line.150"></a>
159 <span class="sourceLineNo">151</span> } catch (IOException exp) {<a name="line.151"></a>
160 <span class="sourceLineNo">152</span> LOG.warn("Exception while balancing cluster.", exp);<a name="line.152"></a>
161 <span class="sourceLineNo">153</span> regionPlans.clear();<a name="line.153"></a>
162 <span class="sourceLineNo">154</span> }<a name="line.154"></a>
163 <span class="sourceLineNo">155</span><a name="line.155"></a>
164 <span class="sourceLineNo">156</span> // Return the whole movement list<a name="line.156"></a>
165 <span class="sourceLineNo">157</span> return regionPlans;<a name="line.157"></a>
166 <span class="sourceLineNo">158</span> }<a name="line.158"></a>
167 <span class="sourceLineNo">159</span><a name="line.159"></a>
168 <span class="sourceLineNo">160</span> @Override<a name="line.160"></a>
169 <span class="sourceLineNo">161</span> public Map&lt;ServerName, List&lt;RegionInfo&gt;&gt; roundRobinAssignment(<a name="line.161"></a>
170 <span class="sourceLineNo">162</span> List&lt;RegionInfo&gt; regions, List&lt;ServerName&gt; servers) throws HBaseIOException {<a name="line.162"></a>
171 <span class="sourceLineNo">163</span> Map&lt;ServerName, List&lt;RegionInfo&gt;&gt; assignments = Maps.newHashMap();<a name="line.163"></a>
172 <span class="sourceLineNo">164</span> ListMultimap&lt;String,RegionInfo&gt; regionMap = ArrayListMultimap.create();<a name="line.164"></a>
173 <span class="sourceLineNo">165</span> ListMultimap&lt;String,ServerName&gt; serverMap = ArrayListMultimap.create();<a name="line.165"></a>
174 <span class="sourceLineNo">166</span> generateGroupMaps(regions, servers, regionMap, serverMap);<a name="line.166"></a>
175 <span class="sourceLineNo">167</span> for(String groupKey : regionMap.keySet()) {<a name="line.167"></a>
176 <span class="sourceLineNo">168</span> if (regionMap.get(groupKey).size() &gt; 0) {<a name="line.168"></a>
177 <span class="sourceLineNo">169</span> Map&lt;ServerName, List&lt;RegionInfo&gt;&gt; result =<a name="line.169"></a>
178 <span class="sourceLineNo">170</span> this.internalBalancer.roundRobinAssignment(<a name="line.170"></a>
179 <span class="sourceLineNo">171</span> regionMap.get(groupKey),<a name="line.171"></a>
180 <span class="sourceLineNo">172</span> serverMap.get(groupKey));<a name="line.172"></a>
181 <span class="sourceLineNo">173</span> if(result != null) {<a name="line.173"></a>
182 <span class="sourceLineNo">174</span> if(result.containsKey(LoadBalancer.BOGUS_SERVER_NAME) &amp;&amp;<a name="line.174"></a>
183 <span class="sourceLineNo">175</span> assignments.containsKey(LoadBalancer.BOGUS_SERVER_NAME)){<a name="line.175"></a>
184 <span class="sourceLineNo">176</span> assignments.get(LoadBalancer.BOGUS_SERVER_NAME).addAll(<a name="line.176"></a>
185 <span class="sourceLineNo">177</span> result.get(LoadBalancer.BOGUS_SERVER_NAME));<a name="line.177"></a>
186 <span class="sourceLineNo">178</span> } else {<a name="line.178"></a>
187 <span class="sourceLineNo">179</span> assignments.putAll(result);<a name="line.179"></a>
188 <span class="sourceLineNo">180</span> }<a name="line.180"></a>
189 <span class="sourceLineNo">181</span> }<a name="line.181"></a>
190 <span class="sourceLineNo">182</span> }<a name="line.182"></a>
191 <span class="sourceLineNo">183</span> }<a name="line.183"></a>
192 <span class="sourceLineNo">184</span> return assignments;<a name="line.184"></a>
193 <span class="sourceLineNo">185</span> }<a name="line.185"></a>
194 <span class="sourceLineNo">186</span><a name="line.186"></a>
195 <span class="sourceLineNo">187</span> @Override<a name="line.187"></a>
196 <span class="sourceLineNo">188</span> public Map&lt;ServerName, List&lt;RegionInfo&gt;&gt; retainAssignment(<a name="line.188"></a>
197 <span class="sourceLineNo">189</span> Map&lt;RegionInfo, ServerName&gt; regions, List&lt;ServerName&gt; servers) throws HBaseIOException {<a name="line.189"></a>
198 <span class="sourceLineNo">190</span> try {<a name="line.190"></a>
199 <span class="sourceLineNo">191</span> Map&lt;ServerName, List&lt;RegionInfo&gt;&gt; assignments = new TreeMap&lt;&gt;();<a name="line.191"></a>
200 <span class="sourceLineNo">192</span> ListMultimap&lt;String, RegionInfo&gt; groupToRegion = ArrayListMultimap.create();<a name="line.192"></a>
201 <span class="sourceLineNo">193</span> Set&lt;RegionInfo&gt; misplacedRegions = getMisplacedRegions(regions);<a name="line.193"></a>
202 <span class="sourceLineNo">194</span> for (RegionInfo region : regions.keySet()) {<a name="line.194"></a>
203 <span class="sourceLineNo">195</span> if (!misplacedRegions.contains(region)) {<a name="line.195"></a>
204 <span class="sourceLineNo">196</span> String groupName = rsGroupInfoManager.getRSGroupOfTable(region.getTable());<a name="line.196"></a>
205 <span class="sourceLineNo">197</span> groupToRegion.put(groupName, region);<a name="line.197"></a>
206 <span class="sourceLineNo">198</span> }<a name="line.198"></a>
207 <span class="sourceLineNo">199</span> }<a name="line.199"></a>
208 <span class="sourceLineNo">200</span> // Now the "groupToRegion" map has only the regions which have correct<a name="line.200"></a>
209 <span class="sourceLineNo">201</span> // assignments.<a name="line.201"></a>
210 <span class="sourceLineNo">202</span> for (String key : groupToRegion.keySet()) {<a name="line.202"></a>
211 <span class="sourceLineNo">203</span> Map&lt;RegionInfo, ServerName&gt; currentAssignmentMap = new TreeMap&lt;RegionInfo, ServerName&gt;();<a name="line.203"></a>
212 <span class="sourceLineNo">204</span> List&lt;RegionInfo&gt; regionList = groupToRegion.get(key);<a name="line.204"></a>
213 <span class="sourceLineNo">205</span> RSGroupInfo info = rsGroupInfoManager.getRSGroup(key);<a name="line.205"></a>
214 <span class="sourceLineNo">206</span> List&lt;ServerName&gt; candidateList = filterOfflineServers(info, servers);<a name="line.206"></a>
215 <span class="sourceLineNo">207</span> for (RegionInfo region : regionList) {<a name="line.207"></a>
216 <span class="sourceLineNo">208</span> currentAssignmentMap.put(region, regions.get(region));<a name="line.208"></a>
217 <span class="sourceLineNo">209</span> }<a name="line.209"></a>
218 <span class="sourceLineNo">210</span> if(candidateList.size() &gt; 0) {<a name="line.210"></a>
219 <span class="sourceLineNo">211</span> assignments.putAll(this.internalBalancer.retainAssignment(<a name="line.211"></a>
220 <span class="sourceLineNo">212</span> currentAssignmentMap, candidateList));<a name="line.212"></a>
221 <span class="sourceLineNo">213</span> }<a name="line.213"></a>
222 <span class="sourceLineNo">214</span> }<a name="line.214"></a>
223 <span class="sourceLineNo">215</span><a name="line.215"></a>
224 <span class="sourceLineNo">216</span> for (RegionInfo region : misplacedRegions) {<a name="line.216"></a>
225 <span class="sourceLineNo">217</span> String groupName = rsGroupInfoManager.getRSGroupOfTable(region.getTable());<a name="line.217"></a>
226 <span class="sourceLineNo">218</span> RSGroupInfo info = rsGroupInfoManager.getRSGroup(groupName);<a name="line.218"></a>
227 <span class="sourceLineNo">219</span> List&lt;ServerName&gt; candidateList = filterOfflineServers(info, servers);<a name="line.219"></a>
228 <span class="sourceLineNo">220</span> ServerName server = this.internalBalancer.randomAssignment(region,<a name="line.220"></a>
229 <span class="sourceLineNo">221</span> candidateList);<a name="line.221"></a>
230 <span class="sourceLineNo">222</span> if (server != null) {<a name="line.222"></a>
231 <span class="sourceLineNo">223</span> if (!assignments.containsKey(server)) {<a name="line.223"></a>
232 <span class="sourceLineNo">224</span> assignments.put(server, new ArrayList&lt;&gt;());<a name="line.224"></a>
233 <span class="sourceLineNo">225</span> }<a name="line.225"></a>
234 <span class="sourceLineNo">226</span> assignments.get(server).add(region);<a name="line.226"></a>
235 <span class="sourceLineNo">227</span> } else {<a name="line.227"></a>
236 <span class="sourceLineNo">228</span> //if not server is available assign to bogus so it ends up in RIT<a name="line.228"></a>
237 <span class="sourceLineNo">229</span> if(!assignments.containsKey(LoadBalancer.BOGUS_SERVER_NAME)) {<a name="line.229"></a>
238 <span class="sourceLineNo">230</span> assignments.put(LoadBalancer.BOGUS_SERVER_NAME, new ArrayList&lt;&gt;());<a name="line.230"></a>
239 <span class="sourceLineNo">231</span> }<a name="line.231"></a>
240 <span class="sourceLineNo">232</span> assignments.get(LoadBalancer.BOGUS_SERVER_NAME).add(region);<a name="line.232"></a>
241 <span class="sourceLineNo">233</span> }<a name="line.233"></a>
242 <span class="sourceLineNo">234</span> }<a name="line.234"></a>
243 <span class="sourceLineNo">235</span> return assignments;<a name="line.235"></a>
244 <span class="sourceLineNo">236</span> } catch (IOException e) {<a name="line.236"></a>
245 <span class="sourceLineNo">237</span> throw new HBaseIOException("Failed to do online retain assignment", e);<a name="line.237"></a>
246 <span class="sourceLineNo">238</span> }<a name="line.238"></a>
247 <span class="sourceLineNo">239</span> }<a name="line.239"></a>
248 <span class="sourceLineNo">240</span><a name="line.240"></a>
249 <span class="sourceLineNo">241</span> @Override<a name="line.241"></a>
250 <span class="sourceLineNo">242</span> public ServerName randomAssignment(RegionInfo region,<a name="line.242"></a>
251 <span class="sourceLineNo">243</span> List&lt;ServerName&gt; servers) throws HBaseIOException {<a name="line.243"></a>
252 <span class="sourceLineNo">244</span> ListMultimap&lt;String,RegionInfo&gt; regionMap = LinkedListMultimap.create();<a name="line.244"></a>
253 <span class="sourceLineNo">245</span> ListMultimap&lt;String,ServerName&gt; serverMap = LinkedListMultimap.create();<a name="line.245"></a>
254 <span class="sourceLineNo">246</span> generateGroupMaps(Lists.newArrayList(region), servers, regionMap, serverMap);<a name="line.246"></a>
255 <span class="sourceLineNo">247</span> List&lt;ServerName&gt; filteredServers = serverMap.get(regionMap.keySet().iterator().next());<a name="line.247"></a>
256 <span class="sourceLineNo">248</span> return this.internalBalancer.randomAssignment(region, filteredServers);<a name="line.248"></a>
257 <span class="sourceLineNo">249</span> }<a name="line.249"></a>
258 <span class="sourceLineNo">250</span><a name="line.250"></a>
259 <span class="sourceLineNo">251</span> private void generateGroupMaps(<a name="line.251"></a>
260 <span class="sourceLineNo">252</span> List&lt;RegionInfo&gt; regions,<a name="line.252"></a>
261 <span class="sourceLineNo">253</span> List&lt;ServerName&gt; servers,<a name="line.253"></a>
262 <span class="sourceLineNo">254</span> ListMultimap&lt;String, RegionInfo&gt; regionMap,<a name="line.254"></a>
263 <span class="sourceLineNo">255</span> ListMultimap&lt;String, ServerName&gt; serverMap) throws HBaseIOException {<a name="line.255"></a>
264 <span class="sourceLineNo">256</span> try {<a name="line.256"></a>
265 <span class="sourceLineNo">257</span> for (RegionInfo region : regions) {<a name="line.257"></a>
266 <span class="sourceLineNo">258</span> String groupName = rsGroupInfoManager.getRSGroupOfTable(region.getTable());<a name="line.258"></a>
267 <span class="sourceLineNo">259</span> if (groupName == null) {<a name="line.259"></a>
268 <span class="sourceLineNo">260</span> LOG.warn("Group for table "+region.getTable()+" is null");<a name="line.260"></a>
269 <span class="sourceLineNo">261</span> }<a name="line.261"></a>
270 <span class="sourceLineNo">262</span> regionMap.put(groupName, region);<a name="line.262"></a>
271 <span class="sourceLineNo">263</span> }<a name="line.263"></a>
272 <span class="sourceLineNo">264</span> for (String groupKey : regionMap.keySet()) {<a name="line.264"></a>
273 <span class="sourceLineNo">265</span> RSGroupInfo info = rsGroupInfoManager.getRSGroup(groupKey);<a name="line.265"></a>
274 <span class="sourceLineNo">266</span> serverMap.putAll(groupKey, filterOfflineServers(info, servers));<a name="line.266"></a>
275 <span class="sourceLineNo">267</span> if(serverMap.get(groupKey).size() &lt; 1) {<a name="line.267"></a>
276 <span class="sourceLineNo">268</span> serverMap.put(groupKey, LoadBalancer.BOGUS_SERVER_NAME);<a name="line.268"></a>
277 <span class="sourceLineNo">269</span> }<a name="line.269"></a>
278 <span class="sourceLineNo">270</span> }<a name="line.270"></a>
279 <span class="sourceLineNo">271</span> } catch(IOException e) {<a name="line.271"></a>
280 <span class="sourceLineNo">272</span> throw new HBaseIOException("Failed to generate group maps", e);<a name="line.272"></a>
281 <span class="sourceLineNo">273</span> }<a name="line.273"></a>
282 <span class="sourceLineNo">274</span> }<a name="line.274"></a>
283 <span class="sourceLineNo">275</span><a name="line.275"></a>
284 <span class="sourceLineNo">276</span> private List&lt;ServerName&gt; filterOfflineServers(RSGroupInfo RSGroupInfo,<a name="line.276"></a>
285 <span class="sourceLineNo">277</span> List&lt;ServerName&gt; onlineServers) {<a name="line.277"></a>
286 <span class="sourceLineNo">278</span> if (RSGroupInfo != null) {<a name="line.278"></a>
287 <span class="sourceLineNo">279</span> return filterServers(RSGroupInfo.getServers(), onlineServers);<a name="line.279"></a>
288 <span class="sourceLineNo">280</span> } else {<a name="line.280"></a>
289 <span class="sourceLineNo">281</span> LOG.warn("RSGroup Information found to be null. Some regions might be unassigned.");<a name="line.281"></a>
290 <span class="sourceLineNo">282</span> return Collections.EMPTY_LIST;<a name="line.282"></a>
291 <span class="sourceLineNo">283</span> }<a name="line.283"></a>
292 <span class="sourceLineNo">284</span> }<a name="line.284"></a>
293 <span class="sourceLineNo">285</span><a name="line.285"></a>
294 <span class="sourceLineNo">286</span> /**<a name="line.286"></a>
295 <span class="sourceLineNo">287</span> * Filter servers based on the online servers.<a name="line.287"></a>
296 <span class="sourceLineNo">288</span> *<a name="line.288"></a>
297 <span class="sourceLineNo">289</span> * @param servers<a name="line.289"></a>
298 <span class="sourceLineNo">290</span> * the servers<a name="line.290"></a>
299 <span class="sourceLineNo">291</span> * @param onlineServers<a name="line.291"></a>
300 <span class="sourceLineNo">292</span> * List of servers which are online.<a name="line.292"></a>
301 <span class="sourceLineNo">293</span> * @return the list<a name="line.293"></a>
302 <span class="sourceLineNo">294</span> */<a name="line.294"></a>
303 <span class="sourceLineNo">295</span> private List&lt;ServerName&gt; filterServers(Set&lt;Address&gt; servers,<a name="line.295"></a>
304 <span class="sourceLineNo">296</span> List&lt;ServerName&gt; onlineServers) {<a name="line.296"></a>
305 <span class="sourceLineNo">297</span> /**<a name="line.297"></a>
306 <span class="sourceLineNo">298</span> * servers is actually a TreeSet (see {@link org.apache.hadoop.hbase.rsgroup.RSGroupInfo}),<a name="line.298"></a>
307 <span class="sourceLineNo">299</span> * having its contains()'s time complexity as O(logn), which is good enough.<a name="line.299"></a>
308 <span class="sourceLineNo">300</span> * TODO: consider using HashSet to pursue O(1) for contains() throughout the calling chain<a name="line.300"></a>
309 <span class="sourceLineNo">301</span> * if needed. */<a name="line.301"></a>
310 <span class="sourceLineNo">302</span> ArrayList&lt;ServerName&gt; finalList = new ArrayList&lt;&gt;();<a name="line.302"></a>
311 <span class="sourceLineNo">303</span> for (ServerName onlineServer : onlineServers) {<a name="line.303"></a>
312 <span class="sourceLineNo">304</span> if (servers.contains(onlineServer.getAddress())) {<a name="line.304"></a>
313 <span class="sourceLineNo">305</span> finalList.add(onlineServer);<a name="line.305"></a>
314 <span class="sourceLineNo">306</span> }<a name="line.306"></a>
315 <span class="sourceLineNo">307</span> }<a name="line.307"></a>
316 <span class="sourceLineNo">308</span><a name="line.308"></a>
317 <span class="sourceLineNo">309</span> return finalList;<a name="line.309"></a>
318 <span class="sourceLineNo">310</span> }<a name="line.310"></a>
319 <span class="sourceLineNo">311</span><a name="line.311"></a>
320 <span class="sourceLineNo">312</span> @VisibleForTesting<a name="line.312"></a>
321 <span class="sourceLineNo">313</span> public Set&lt;RegionInfo&gt; getMisplacedRegions(<a name="line.313"></a>
322 <span class="sourceLineNo">314</span> Map&lt;RegionInfo, ServerName&gt; regions) throws IOException {<a name="line.314"></a>
323 <span class="sourceLineNo">315</span> Set&lt;RegionInfo&gt; misplacedRegions = new HashSet&lt;&gt;();<a name="line.315"></a>
324 <span class="sourceLineNo">316</span> for(Map.Entry&lt;RegionInfo, ServerName&gt; region : regions.entrySet()) {<a name="line.316"></a>
325 <span class="sourceLineNo">317</span> RegionInfo regionInfo = region.getKey();<a name="line.317"></a>
326 <span class="sourceLineNo">318</span> ServerName assignedServer = region.getValue();<a name="line.318"></a>
327 <span class="sourceLineNo">319</span> RSGroupInfo info = rsGroupInfoManager.getRSGroup(rsGroupInfoManager.<a name="line.319"></a>
328 <span class="sourceLineNo">320</span> getRSGroupOfTable(regionInfo.getTable()));<a name="line.320"></a>
329 <span class="sourceLineNo">321</span> if (assignedServer == null) {<a name="line.321"></a>
330 <span class="sourceLineNo">322</span> LOG.debug("There is no assigned server for {}", region);<a name="line.322"></a>
331 <span class="sourceLineNo">323</span> continue;<a name="line.323"></a>
332 <span class="sourceLineNo">324</span> }<a name="line.324"></a>
333 <span class="sourceLineNo">325</span> RSGroupInfo otherInfo = rsGroupInfoManager.getRSGroupOfServer(assignedServer.getAddress());<a name="line.325"></a>
334 <span class="sourceLineNo">326</span> if (info == null &amp;&amp; otherInfo == null) {<a name="line.326"></a>
335 <span class="sourceLineNo">327</span> LOG.warn("Couldn't obtain rs group information for {} on {}", region, assignedServer);<a name="line.327"></a>
336 <span class="sourceLineNo">328</span> continue;<a name="line.328"></a>
337 <span class="sourceLineNo">329</span> }<a name="line.329"></a>
338 <span class="sourceLineNo">330</span> if ((info == null || !info.containsServer(assignedServer.getAddress()))) {<a name="line.330"></a>
339 <span class="sourceLineNo">331</span> LOG.debug("Found misplaced region: " + regionInfo.getRegionNameAsString() +<a name="line.331"></a>
340 <span class="sourceLineNo">332</span> " on server: " + assignedServer +<a name="line.332"></a>
341 <span class="sourceLineNo">333</span> " found in group: " + otherInfo +<a name="line.333"></a>
342 <span class="sourceLineNo">334</span> " outside of group: " + (info == null ? "UNKNOWN" : info.getName()));<a name="line.334"></a>
343 <span class="sourceLineNo">335</span> misplacedRegions.add(regionInfo);<a name="line.335"></a>
344 <span class="sourceLineNo">336</span> }<a name="line.336"></a>
345 <span class="sourceLineNo">337</span> }<a name="line.337"></a>
346 <span class="sourceLineNo">338</span> return misplacedRegions;<a name="line.338"></a>
347 <span class="sourceLineNo">339</span> }<a name="line.339"></a>
348 <span class="sourceLineNo">340</span><a name="line.340"></a>
349 <span class="sourceLineNo">341</span> private Pair&lt;Map&lt;ServerName, List&lt;RegionInfo&gt;&gt;, List&lt;RegionPlan&gt;&gt; correctAssignments(<a name="line.341"></a>
350 <span class="sourceLineNo">342</span> Map&lt;ServerName, List&lt;RegionInfo&gt;&gt; existingAssignments)<a name="line.342"></a>
351 <span class="sourceLineNo">343</span> throws HBaseIOException{<a name="line.343"></a>
352 <span class="sourceLineNo">344</span> // To return<a name="line.344"></a>
353 <span class="sourceLineNo">345</span> Map&lt;ServerName, List&lt;RegionInfo&gt;&gt; correctAssignments = new TreeMap&lt;&gt;();<a name="line.345"></a>
354 <span class="sourceLineNo">346</span> List&lt;RegionPlan&gt; regionPlansForMisplacedRegions = new ArrayList&lt;&gt;();<a name="line.346"></a>
355 <span class="sourceLineNo">347</span><a name="line.347"></a>
356 <span class="sourceLineNo">348</span> for (Map.Entry&lt;ServerName, List&lt;RegionInfo&gt;&gt; assignments : existingAssignments.entrySet()){<a name="line.348"></a>
357 <span class="sourceLineNo">349</span> ServerName currentHostServer = assignments.getKey();<a name="line.349"></a>
358 <span class="sourceLineNo">350</span> correctAssignments.put(currentHostServer, new LinkedList&lt;&gt;());<a name="line.350"></a>
359 <span class="sourceLineNo">351</span> List&lt;RegionInfo&gt; regions = assignments.getValue();<a name="line.351"></a>
360 <span class="sourceLineNo">352</span> for (RegionInfo region : regions) {<a name="line.352"></a>
361 <span class="sourceLineNo">353</span> RSGroupInfo targetRSGInfo = null;<a name="line.353"></a>
362 <span class="sourceLineNo">354</span> try {<a name="line.354"></a>
363 <span class="sourceLineNo">355</span> targetRSGInfo = rsGroupInfoManager.getRSGroup(<a name="line.355"></a>
364 <span class="sourceLineNo">356</span> rsGroupInfoManager.getRSGroupOfTable(region.getTable()));<a name="line.356"></a>
365 <span class="sourceLineNo">357</span> } catch (IOException exp) {<a name="line.357"></a>
366 <span class="sourceLineNo">358</span> LOG.debug("RSGroup information null for region of table " + region.getTable(),<a name="line.358"></a>
367 <span class="sourceLineNo">359</span> exp);<a name="line.359"></a>
368 <span class="sourceLineNo">360</span> }<a name="line.360"></a>
369 <span class="sourceLineNo">361</span> if (targetRSGInfo == null ||<a name="line.361"></a>
370 <span class="sourceLineNo">362</span> !targetRSGInfo.containsServer(currentHostServer.getAddress())) { // region is mis-placed<a name="line.362"></a>
371 <span class="sourceLineNo">363</span> regionPlansForMisplacedRegions.add(new RegionPlan(region, currentHostServer, null));<a name="line.363"></a>
372 <span class="sourceLineNo">364</span> } else { // region is placed as expected<a name="line.364"></a>
373 <span class="sourceLineNo">365</span> correctAssignments.get(currentHostServer).add(region);<a name="line.365"></a>
374 <span class="sourceLineNo">366</span> }<a name="line.366"></a>
375 <span class="sourceLineNo">367</span> }<a name="line.367"></a>
376 <span class="sourceLineNo">368</span> }<a name="line.368"></a>
377 <span class="sourceLineNo">369</span><a name="line.369"></a>
378 <span class="sourceLineNo">370</span> // Return correct assignments and region movement plan for mis-placed regions together<a name="line.370"></a>
379 <span class="sourceLineNo">371</span> return new Pair&lt;Map&lt;ServerName, List&lt;RegionInfo&gt;&gt;, List&lt;RegionPlan&gt;&gt;(<a name="line.371"></a>
380 <span class="sourceLineNo">372</span> correctAssignments, regionPlansForMisplacedRegions);<a name="line.372"></a>
381 <span class="sourceLineNo">373</span> }<a name="line.373"></a>
382 <span class="sourceLineNo">374</span><a name="line.374"></a>
383 <span class="sourceLineNo">375</span> @Override<a name="line.375"></a>
384 <span class="sourceLineNo">376</span> public void initialize() throws HBaseIOException {<a name="line.376"></a>
385 <span class="sourceLineNo">377</span> try {<a name="line.377"></a>
386 <span class="sourceLineNo">378</span> if (rsGroupInfoManager == null) {<a name="line.378"></a>
387 <span class="sourceLineNo">379</span> List&lt;RSGroupAdminEndpoint&gt; cps =<a name="line.379"></a>
388 <span class="sourceLineNo">380</span> masterServices.getMasterCoprocessorHost().findCoprocessors(RSGroupAdminEndpoint.class);<a name="line.380"></a>
389 <span class="sourceLineNo">381</span> if (cps.size() != 1) {<a name="line.381"></a>
390 <span class="sourceLineNo">382</span> String msg = "Expected one implementation of GroupAdminEndpoint but found " + cps.size();<a name="line.382"></a>
391 <span class="sourceLineNo">383</span> LOG.error(msg);<a name="line.383"></a>
392 <span class="sourceLineNo">384</span> throw new HBaseIOException(msg);<a name="line.384"></a>
393 <span class="sourceLineNo">385</span> }<a name="line.385"></a>
394 <span class="sourceLineNo">386</span> rsGroupInfoManager = cps.get(0).getGroupInfoManager();<a name="line.386"></a>
395 <span class="sourceLineNo">387</span> if(rsGroupInfoManager == null){<a name="line.387"></a>
396 <span class="sourceLineNo">388</span> String msg = "RSGroupInfoManager hasn't been initialized";<a name="line.388"></a>
397 <span class="sourceLineNo">389</span> LOG.error(msg);<a name="line.389"></a>
398 <span class="sourceLineNo">390</span> throw new HBaseIOException(msg);<a name="line.390"></a>
399 <span class="sourceLineNo">391</span> }<a name="line.391"></a>
400 <span class="sourceLineNo">392</span> rsGroupInfoManager.start();<a name="line.392"></a>
401 <span class="sourceLineNo">393</span> }<a name="line.393"></a>
402 <span class="sourceLineNo">394</span> } catch (IOException e) {<a name="line.394"></a>
403 <span class="sourceLineNo">395</span> throw new HBaseIOException("Failed to initialize GroupInfoManagerImpl", e);<a name="line.395"></a>
404 <span class="sourceLineNo">396</span> }<a name="line.396"></a>
405 <span class="sourceLineNo">397</span><a name="line.397"></a>
406 <span class="sourceLineNo">398</span> // Create the balancer<a name="line.398"></a>
407 <span class="sourceLineNo">399</span> Class&lt;? extends LoadBalancer&gt; balancerKlass = config.getClass(HBASE_RSGROUP_LOADBALANCER_CLASS,<a name="line.399"></a>
408 <span class="sourceLineNo">400</span> StochasticLoadBalancer.class, LoadBalancer.class);<a name="line.400"></a>
409 <span class="sourceLineNo">401</span> internalBalancer = ReflectionUtils.newInstance(balancerKlass, config);<a name="line.401"></a>
410 <span class="sourceLineNo">402</span> internalBalancer.setMasterServices(masterServices);<a name="line.402"></a>
411 <span class="sourceLineNo">403</span> internalBalancer.setClusterMetrics(clusterStatus);<a name="line.403"></a>
412 <span class="sourceLineNo">404</span> internalBalancer.setConf(config);<a name="line.404"></a>
413 <span class="sourceLineNo">405</span> internalBalancer.initialize();<a name="line.405"></a>
414 <span class="sourceLineNo">406</span> }<a name="line.406"></a>
415 <span class="sourceLineNo">407</span><a name="line.407"></a>
416 <span class="sourceLineNo">408</span> public boolean isOnline() {<a name="line.408"></a>
417 <span class="sourceLineNo">409</span> if (this.rsGroupInfoManager == null) {<a name="line.409"></a>
418 <span class="sourceLineNo">410</span> return false;<a name="line.410"></a>
419 <span class="sourceLineNo">411</span> }<a name="line.411"></a>
420 <span class="sourceLineNo">412</span><a name="line.412"></a>
421 <span class="sourceLineNo">413</span> return this.rsGroupInfoManager.isOnline();<a name="line.413"></a>
422 <span class="sourceLineNo">414</span> }<a name="line.414"></a>
423 <span class="sourceLineNo">415</span><a name="line.415"></a>
424 <span class="sourceLineNo">416</span> @Override<a name="line.416"></a>
425 <span class="sourceLineNo">417</span> public void setClusterLoad(Map&lt;TableName, Map&lt;ServerName, List&lt;RegionInfo&gt;&gt;&gt; clusterLoad) {<a name="line.417"></a>
426 <span class="sourceLineNo">418</span> }<a name="line.418"></a>
427 <span class="sourceLineNo">419</span><a name="line.419"></a>
428 <span class="sourceLineNo">420</span> @Override<a name="line.420"></a>
429 <span class="sourceLineNo">421</span> public void regionOnline(RegionInfo regionInfo, ServerName sn) {<a name="line.421"></a>
430 <span class="sourceLineNo">422</span> }<a name="line.422"></a>
431 <span class="sourceLineNo">423</span><a name="line.423"></a>
432 <span class="sourceLineNo">424</span> @Override<a name="line.424"></a>
433 <span class="sourceLineNo">425</span> public void regionOffline(RegionInfo regionInfo) {<a name="line.425"></a>
434 <span class="sourceLineNo">426</span> }<a name="line.426"></a>
435 <span class="sourceLineNo">427</span><a name="line.427"></a>
436 <span class="sourceLineNo">428</span> @Override<a name="line.428"></a>
437 <span class="sourceLineNo">429</span> public void onConfigurationChange(Configuration conf) {<a name="line.429"></a>
438 <span class="sourceLineNo">430</span> //DO nothing for now<a name="line.430"></a>
439 <span class="sourceLineNo">431</span> }<a name="line.431"></a>
440 <span class="sourceLineNo">432</span><a name="line.432"></a>
441 <span class="sourceLineNo">433</span> @Override<a name="line.433"></a>
442 <span class="sourceLineNo">434</span> public void stop(String why) {<a name="line.434"></a>
443 <span class="sourceLineNo">435</span> }<a name="line.435"></a>
444 <span class="sourceLineNo">436</span><a name="line.436"></a>
445 <span class="sourceLineNo">437</span> @Override<a name="line.437"></a>
446 <span class="sourceLineNo">438</span> public boolean isStopped() {<a name="line.438"></a>
447 <span class="sourceLineNo">439</span> return false;<a name="line.439"></a>
448 <span class="sourceLineNo">440</span> }<a name="line.440"></a>
449 <span class="sourceLineNo">441</span><a name="line.441"></a>
450 <span class="sourceLineNo">442</span> @VisibleForTesting<a name="line.442"></a>
451 <span class="sourceLineNo">443</span> public void setRsGroupInfoManager(RSGroupInfoManager rsGroupInfoManager) {<a name="line.443"></a>
452 <span class="sourceLineNo">444</span> this.rsGroupInfoManager = rsGroupInfoManager;<a name="line.444"></a>
453 <span class="sourceLineNo">445</span> }<a name="line.445"></a>
454 <span class="sourceLineNo">446</span>}<a name="line.446"></a>
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515 </pre>
516 </div>
517 </body>
518 </html>