001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase;
019
020import static org.junit.Assert.assertEquals;
021import static org.junit.Assert.assertFalse;
022import static org.junit.Assert.assertNotNull;
023import static org.junit.Assert.assertNull;
024import static org.junit.Assert.assertTrue;
025
026import org.apache.hadoop.hbase.client.RegionInfo;
027import org.apache.hadoop.hbase.client.RegionInfoBuilder;
028import org.apache.hadoop.hbase.testclassification.ClientTests;
029import org.apache.hadoop.hbase.testclassification.SmallTests;
030import org.junit.ClassRule;
031import org.junit.Test;
032import org.junit.experimental.categories.Category;
033
034@Category({ ClientTests.class, SmallTests.class })
035public class TestRegionLocations {
036
037  @ClassRule
038  public static final HBaseClassTestRule CLASS_RULE =
039    HBaseClassTestRule.forClass(TestRegionLocations.class);
040
041  ServerName sn0 = ServerName.valueOf("host0", 10, 10);
042  ServerName sn1 = ServerName.valueOf("host1", 10, 10);
043  ServerName sn2 = ServerName.valueOf("host2", 10, 10);
044  ServerName sn3 = ServerName.valueOf("host3", 10, 10);
045
046  RegionInfo info0 = hri(0);
047  RegionInfo info1 = hri(1);
048  RegionInfo info2 = hri(2);
049  RegionInfo info9 = hri(9);
050
051  long regionId1 = 1000;
052  long regionId2 = 2000;
053
054  @Test
055  public void testSizeMethods() {
056    RegionLocations list = new RegionLocations();
057    assertTrue(list.isEmpty());
058    assertEquals(0, list.size());
059    assertEquals(0, list.numNonNullElements());
060
061    list = hrll((HRegionLocation) null);
062    assertTrue(list.isEmpty());
063    assertEquals(1, list.size());
064    assertEquals(0, list.numNonNullElements());
065
066    RegionInfo info0 = hri(0);
067    list = hrll(hrl(info0, null));
068    assertTrue(list.isEmpty());
069    assertEquals(1, list.size());
070    assertEquals(0, list.numNonNullElements());
071
072    RegionInfo info9 = hri(9);
073    list = hrll(hrl(info9, null));
074    assertTrue(list.isEmpty());
075    assertEquals(10, list.size());
076    assertEquals(0, list.numNonNullElements());
077
078    list = hrll(hrl(info0, null), hrl(info9, null));
079    assertTrue(list.isEmpty());
080    assertEquals(10, list.size());
081    assertEquals(0, list.numNonNullElements());
082  }
083
084  private RegionInfo hri(int replicaId) {
085    return hri(regionId1, replicaId);
086  }
087
088  private RegionInfo hri(long regionId, int replicaId) {
089    TableName table = TableName.valueOf("table");
090    byte[] startKey = HConstants.EMPTY_START_ROW;
091    byte[] endKey = HConstants.EMPTY_END_ROW;
092    RegionInfo info = RegionInfoBuilder.newBuilder(table).setStartKey(startKey).setEndKey(endKey)
093      .setRegionId(regionId).setReplicaId(replicaId).build();
094    return info;
095  }
096
097  private HRegionLocation hrl(RegionInfo hri, ServerName sn) {
098    return new HRegionLocation(hri, sn);
099  }
100
101  private HRegionLocation hrl(RegionInfo hri, ServerName sn, long seqNum) {
102    return new HRegionLocation(hri, sn, seqNum);
103  }
104
105  private RegionLocations hrll(HRegionLocation... locations) {
106    return new RegionLocations(locations);
107  }
108
109  @Test
110  public void testRemoveByServer() {
111    RegionLocations list;
112
113    // test remove from empty list
114    list = new RegionLocations();
115    assertTrue(list == list.removeByServer(sn0));
116
117    // test remove from single element list
118    list = hrll(hrl(info0, sn0));
119    assertTrue(list == list.removeByServer(sn1));
120    list = list.removeByServer(sn0);
121    assertEquals(0, list.numNonNullElements());
122
123    // test remove from multi element list
124    list = hrll(hrl(info0, sn0), hrl(info1, sn1), hrl(info2, sn2), hrl(info9, sn2));
125    assertTrue(list == list.removeByServer(sn3)); // no region is mapped to sn3
126    list = list.removeByServer(sn0);
127    assertNull(list.getRegionLocation(0));
128    assertEquals(sn1, list.getRegionLocation(1).getServerName());
129    assertEquals(sn2, list.getRegionLocation(2).getServerName());
130    assertNull(list.getRegionLocation(5));
131    assertEquals(sn2, list.getRegionLocation(9).getServerName());
132
133    // test multi-element remove from multi element list
134    list = hrll(hrl(info0, sn1), hrl(info1, sn1), hrl(info2, sn0), hrl(info9, sn0));
135    list = list.removeByServer(sn0);
136    assertEquals(sn1, list.getRegionLocation(0).getServerName());
137    assertEquals(sn1, list.getRegionLocation(1).getServerName());
138    assertNull(list.getRegionLocation(2));
139    assertNull(list.getRegionLocation(5));
140    assertNull(list.getRegionLocation(9));
141  }
142
143  @Test
144  public void testRemove() {
145    RegionLocations list;
146
147    // test remove from empty list
148    list = new RegionLocations();
149    assertTrue(list == list.remove(hrl(info0, sn0)));
150
151    // test remove from single element list
152    list = hrll(hrl(info0, sn0));
153    assertTrue(list == list.remove(hrl(info0, sn1)));
154    list = list.remove(hrl(info0, sn0));
155    assertTrue(list.isEmpty());
156
157    // test remove from multi element list
158    list = hrll(hrl(info0, sn0), hrl(info1, sn1), hrl(info2, sn2), hrl(info9, sn2));
159    assertTrue(list == list.remove(hrl(info1, sn3))); // no region is mapped to sn3
160    list = list.remove(hrl(info0, sn0));
161    assertNull(list.getRegionLocation(0));
162    assertEquals(sn1, list.getRegionLocation(1).getServerName());
163    assertEquals(sn2, list.getRegionLocation(2).getServerName());
164    assertNull(list.getRegionLocation(5));
165    assertEquals(sn2, list.getRegionLocation(9).getServerName());
166
167    list = list.remove(hrl(info9, sn2));
168    assertNull(list.getRegionLocation(0));
169    assertEquals(sn1, list.getRegionLocation(1).getServerName());
170    assertEquals(sn2, list.getRegionLocation(2).getServerName());
171    assertNull(list.getRegionLocation(5));
172    assertNull(list.getRegionLocation(9));
173
174    // test multi-element remove from multi element list
175    list = hrll(hrl(info0, sn1), hrl(info1, sn1), hrl(info2, sn0), hrl(info9, sn0));
176    list = list.remove(hrl(info9, sn0));
177    assertEquals(sn1, list.getRegionLocation(0).getServerName());
178    assertEquals(sn1, list.getRegionLocation(1).getServerName());
179    assertEquals(sn0, list.getRegionLocation(2).getServerName());
180    assertNull(list.getRegionLocation(5));
181    assertNull(list.getRegionLocation(9));
182  }
183
184  @Test
185  public void testUpdateLocation() {
186    RegionLocations list;
187
188    // test add to empty list
189    list = new RegionLocations();
190    list = list.updateLocation(hrl(info0, sn1), false, false);
191    assertEquals(sn1, list.getRegionLocation(0).getServerName());
192
193    // test add to non-empty list
194    list = list.updateLocation(hrl(info9, sn3, 10), false, false);
195    assertEquals(sn3, list.getRegionLocation(9).getServerName());
196    assertEquals(10, list.size());
197    list = list.updateLocation(hrl(info2, sn2, 10), false, false);
198    assertEquals(sn2, list.getRegionLocation(2).getServerName());
199    assertEquals(10, list.size());
200
201    // test update greater SeqNum
202    list = list.updateLocation(hrl(info2, sn3, 11), false, false);
203    assertEquals(sn3, list.getRegionLocation(2).getServerName());
204    assertEquals(sn3, list.getRegionLocation(9).getServerName());
205
206    // test update equal SeqNum
207    list = list.updateLocation(hrl(info2, sn1, 11), false, false); // should not update
208    assertEquals(sn3, list.getRegionLocation(2).getServerName());
209    assertEquals(sn3, list.getRegionLocation(9).getServerName());
210    list = list.updateLocation(hrl(info2, sn1, 11), true, false); // should update
211    assertEquals(sn1, list.getRegionLocation(2).getServerName());
212    assertEquals(sn3, list.getRegionLocation(9).getServerName());
213
214    // test force update
215    list = list.updateLocation(hrl(info2, sn2, 9), false, true); // should update
216    assertEquals(sn2, list.getRegionLocation(2).getServerName());
217    assertEquals(sn3, list.getRegionLocation(9).getServerName());
218  }
219
220  @Test
221  public void testMergeLocations() {
222    RegionLocations list1, list2;
223
224    // test merge empty lists
225    list1 = new RegionLocations();
226    list2 = new RegionLocations();
227
228    assertTrue(list1 == list1.mergeLocations(list2));
229
230    // test merge non-empty and empty
231    list2 = hrll(hrl(info0, sn0));
232    list1 = list1.mergeLocations(list2);
233    assertEquals(sn0, list1.getRegionLocation(0).getServerName());
234
235    // test merge empty and non empty
236    list1 = hrll();
237    list1 = list2.mergeLocations(list1);
238    assertEquals(sn0, list1.getRegionLocation(0).getServerName());
239
240    // test merge non intersecting
241    list1 = hrll(hrl(info0, sn0), hrl(info1, sn1));
242    list2 = hrll(hrl(info2, sn2));
243    list1 = list2.mergeLocations(list1);
244    assertEquals(sn0, list1.getRegionLocation(0).getServerName());
245    assertEquals(sn1, list1.getRegionLocation(1).getServerName());
246    assertEquals(2, list1.size()); // the size is taken from the argument list to merge
247
248    // do the other way merge as well
249    list1 = hrll(hrl(info0, sn0), hrl(info1, sn1));
250    list2 = hrll(hrl(info2, sn2));
251    list1 = list1.mergeLocations(list2);
252    assertEquals(sn0, list1.getRegionLocation(0).getServerName());
253    assertEquals(sn1, list1.getRegionLocation(1).getServerName());
254    assertEquals(sn2, list1.getRegionLocation(2).getServerName());
255
256    // test intersecting lists same seqNum
257    list1 = hrll(hrl(info0, sn0), hrl(info1, sn1));
258    list2 = hrll(hrl(info0, sn2), hrl(info1, sn2), hrl(info9, sn3));
259    list1 = list2.mergeLocations(list1); // list1 should override
260    assertEquals(2, list1.size());
261    assertEquals(sn0, list1.getRegionLocation(0).getServerName());
262    assertEquals(sn1, list1.getRegionLocation(1).getServerName());
263
264    // do the other way
265    list1 = hrll(hrl(info0, sn0), hrl(info1, sn1));
266    list2 = hrll(hrl(info0, sn2), hrl(info1, sn2), hrl(info9, sn3));
267    list1 = list1.mergeLocations(list2); // list2 should override
268    assertEquals(10, list1.size());
269    assertEquals(sn2, list1.getRegionLocation(0).getServerName());
270    assertEquals(sn2, list1.getRegionLocation(1).getServerName());
271    assertEquals(sn3, list1.getRegionLocation(9).getServerName());
272
273    // test intersecting lists different seqNum
274    list1 = hrll(hrl(info0, sn0, 10), hrl(info1, sn1, 10));
275    list2 = hrll(hrl(info0, sn2, 11), hrl(info1, sn2, 11), hrl(info9, sn3, 11));
276    list1 = list1.mergeLocations(list2); // list2 should override because of seqNum
277    assertEquals(10, list1.size());
278    assertEquals(sn2, list1.getRegionLocation(0).getServerName());
279    assertEquals(sn2, list1.getRegionLocation(1).getServerName());
280    assertEquals(sn3, list1.getRegionLocation(9).getServerName());
281
282    // do the other way
283    list1 = hrll(hrl(info0, sn0, 10), hrl(info1, sn1, 10));
284    list2 = hrll(hrl(info0, sn2, 11), hrl(info1, sn2, 11), hrl(info9, sn3, 11));
285    list1 = list1.mergeLocations(list2); // list2 should override
286    assertEquals(10, list1.size());
287    assertEquals(sn2, list1.getRegionLocation(0).getServerName());
288    assertEquals(sn2, list1.getRegionLocation(1).getServerName());
289    assertEquals(sn3, list1.getRegionLocation(9).getServerName());
290  }
291
292  @Test
293  public void testMergeLocationsWithDifferentRegionId() {
294    RegionLocations list1, list2;
295
296    // test merging two lists. But the list2 contains region replicas with a different region id
297    RegionInfo info0 = hri(regionId1, 0);
298    RegionInfo info1 = hri(regionId1, 1);
299    RegionInfo info2 = hri(regionId2, 2);
300
301    list1 = hrll(hrl(info2, sn1));
302    list2 = hrll(hrl(info0, sn2), hrl(info1, sn2));
303    list1 = list2.mergeLocations(list1);
304    assertNull(list1.getRegionLocation(0));
305    assertNull(list1.getRegionLocation(1));
306    assertNotNull(list1.getRegionLocation(2));
307    assertEquals(sn1, list1.getRegionLocation(2).getServerName());
308    assertEquals(3, list1.size());
309
310    // try the other way merge
311    list1 = hrll(hrl(info2, sn1));
312    list2 = hrll(hrl(info0, sn2), hrl(info1, sn2));
313    list2 = list1.mergeLocations(list2);
314    assertNotNull(list2.getRegionLocation(0));
315    assertNotNull(list2.getRegionLocation(1));
316    assertNull(list2.getRegionLocation(2));
317  }
318
319  @Test
320  public void testUpdateLocationWithDifferentRegionId() {
321    RegionLocations list;
322
323    RegionInfo info0 = hri(regionId1, 0);
324    RegionInfo info1 = hri(regionId2, 1);
325    RegionInfo info2 = hri(regionId1, 2);
326
327    list = new RegionLocations(hrl(info0, sn1), hrl(info2, sn1));
328
329    list = list.updateLocation(hrl(info1, sn2), false, true); // force update
330
331    // the other locations should be removed now
332    assertNull(list.getRegionLocation(0));
333    assertNotNull(list.getRegionLocation(1));
334    assertNull(list.getRegionLocation(2));
335    assertEquals(sn2, list.getRegionLocation(1).getServerName());
336    assertEquals(3, list.size());
337  }
338
339  @Test
340  public void testConstructWithNullElements() {
341    // RegionLocations can contain null elements as well. These null elements can
342
343    RegionLocations list = new RegionLocations((HRegionLocation) null);
344    assertTrue(list.isEmpty());
345    assertEquals(1, list.size());
346    assertEquals(0, list.numNonNullElements());
347
348    list = new RegionLocations(null, hrl(info1, sn0));
349    assertFalse(list.isEmpty());
350    assertEquals(2, list.size());
351    assertEquals(1, list.numNonNullElements());
352
353    list = new RegionLocations(hrl(info0, sn0), null);
354    assertEquals(2, list.size());
355    assertEquals(1, list.numNonNullElements());
356
357    list = new RegionLocations(null, hrl(info2, sn0), null, hrl(info9, sn0));
358    assertEquals(10, list.size());
359    assertEquals(2, list.numNonNullElements());
360
361    list = new RegionLocations(null, hrl(info2, sn0), null, hrl(info9, sn0), null);
362    assertEquals(11, list.size());
363    assertEquals(2, list.numNonNullElements());
364
365    list = new RegionLocations(null, hrl(info2, sn0), null, hrl(info9, sn0), null, null);
366    assertEquals(12, list.size());
367    assertEquals(2, list.numNonNullElements());
368  }
369}