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.jupiter.api.Assertions.assertEquals;
021import static org.junit.jupiter.api.Assertions.assertFalse;
022import static org.junit.jupiter.api.Assertions.assertNotNull;
023import static org.junit.jupiter.api.Assertions.assertNull;
024import static org.junit.jupiter.api.Assertions.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.jupiter.api.Tag;
031import org.junit.jupiter.api.Test;
032
033@Tag(ClientTests.TAG)
034@Tag(SmallTests.TAG)
035public class TestRegionLocations {
036
037  ServerName sn0 = ServerName.valueOf("host0", 10, 10);
038  ServerName sn1 = ServerName.valueOf("host1", 10, 10);
039  ServerName sn2 = ServerName.valueOf("host2", 10, 10);
040  ServerName sn3 = ServerName.valueOf("host3", 10, 10);
041
042  RegionInfo info0 = hri(0);
043  RegionInfo info1 = hri(1);
044  RegionInfo info2 = hri(2);
045  RegionInfo info9 = hri(9);
046
047  long regionId1 = 1000;
048  long regionId2 = 2000;
049
050  @Test
051  public void testSizeMethods() {
052    RegionLocations list = new RegionLocations();
053    assertTrue(list.isEmpty());
054    assertEquals(0, list.size());
055    assertEquals(0, list.numNonNullElements());
056
057    list = hrll((HRegionLocation) null);
058    assertTrue(list.isEmpty());
059    assertEquals(1, list.size());
060    assertEquals(0, list.numNonNullElements());
061
062    RegionInfo info0 = hri(0);
063    list = hrll(hrl(info0, null));
064    assertTrue(list.isEmpty());
065    assertEquals(1, list.size());
066    assertEquals(0, list.numNonNullElements());
067
068    RegionInfo info9 = hri(9);
069    list = hrll(hrl(info9, null));
070    assertTrue(list.isEmpty());
071    assertEquals(10, list.size());
072    assertEquals(0, list.numNonNullElements());
073
074    list = hrll(hrl(info0, null), hrl(info9, null));
075    assertTrue(list.isEmpty());
076    assertEquals(10, list.size());
077    assertEquals(0, list.numNonNullElements());
078  }
079
080  private RegionInfo hri(int replicaId) {
081    return hri(regionId1, replicaId);
082  }
083
084  private RegionInfo hri(long regionId, int replicaId) {
085    TableName table = TableName.valueOf("table");
086    byte[] startKey = HConstants.EMPTY_START_ROW;
087    byte[] endKey = HConstants.EMPTY_END_ROW;
088    RegionInfo info = RegionInfoBuilder.newBuilder(table).setStartKey(startKey).setEndKey(endKey)
089      .setRegionId(regionId).setReplicaId(replicaId).build();
090    return info;
091  }
092
093  private HRegionLocation hrl(RegionInfo hri, ServerName sn) {
094    return new HRegionLocation(hri, sn);
095  }
096
097  private HRegionLocation hrl(RegionInfo hri, ServerName sn, long seqNum) {
098    return new HRegionLocation(hri, sn, seqNum);
099  }
100
101  private RegionLocations hrll(HRegionLocation... locations) {
102    return new RegionLocations(locations);
103  }
104
105  @Test
106  public void testRemoveByServer() {
107    RegionLocations list;
108
109    // test remove from empty list
110    list = new RegionLocations();
111    assertTrue(list == list.removeByServer(sn0));
112
113    // test remove from single element list
114    list = hrll(hrl(info0, sn0));
115    assertTrue(list == list.removeByServer(sn1));
116    list = list.removeByServer(sn0);
117    assertEquals(0, list.numNonNullElements());
118
119    // test remove from multi element list
120    list = hrll(hrl(info0, sn0), hrl(info1, sn1), hrl(info2, sn2), hrl(info9, sn2));
121    assertTrue(list == list.removeByServer(sn3)); // no region is mapped to sn3
122    list = list.removeByServer(sn0);
123    assertNull(list.getRegionLocation(0));
124    assertEquals(sn1, list.getRegionLocation(1).getServerName());
125    assertEquals(sn2, list.getRegionLocation(2).getServerName());
126    assertNull(list.getRegionLocation(5));
127    assertEquals(sn2, list.getRegionLocation(9).getServerName());
128
129    // test multi-element remove from multi element list
130    list = hrll(hrl(info0, sn1), hrl(info1, sn1), hrl(info2, sn0), hrl(info9, sn0));
131    list = list.removeByServer(sn0);
132    assertEquals(sn1, list.getRegionLocation(0).getServerName());
133    assertEquals(sn1, list.getRegionLocation(1).getServerName());
134    assertNull(list.getRegionLocation(2));
135    assertNull(list.getRegionLocation(5));
136    assertNull(list.getRegionLocation(9));
137  }
138
139  @Test
140  public void testRemove() {
141    RegionLocations list;
142
143    // test remove from empty list
144    list = new RegionLocations();
145    assertTrue(list == list.remove(hrl(info0, sn0)));
146
147    // test remove from single element list
148    list = hrll(hrl(info0, sn0));
149    assertTrue(list == list.remove(hrl(info0, sn1)));
150    list = list.remove(hrl(info0, sn0));
151    assertTrue(list.isEmpty());
152
153    // test remove from multi element list
154    list = hrll(hrl(info0, sn0), hrl(info1, sn1), hrl(info2, sn2), hrl(info9, sn2));
155    assertTrue(list == list.remove(hrl(info1, sn3))); // no region is mapped to sn3
156    list = list.remove(hrl(info0, sn0));
157    assertNull(list.getRegionLocation(0));
158    assertEquals(sn1, list.getRegionLocation(1).getServerName());
159    assertEquals(sn2, list.getRegionLocation(2).getServerName());
160    assertNull(list.getRegionLocation(5));
161    assertEquals(sn2, list.getRegionLocation(9).getServerName());
162
163    list = list.remove(hrl(info9, sn2));
164    assertNull(list.getRegionLocation(0));
165    assertEquals(sn1, list.getRegionLocation(1).getServerName());
166    assertEquals(sn2, list.getRegionLocation(2).getServerName());
167    assertNull(list.getRegionLocation(5));
168    assertNull(list.getRegionLocation(9));
169
170    // test multi-element remove from multi element list
171    list = hrll(hrl(info0, sn1), hrl(info1, sn1), hrl(info2, sn0), hrl(info9, sn0));
172    list = list.remove(hrl(info9, sn0));
173    assertEquals(sn1, list.getRegionLocation(0).getServerName());
174    assertEquals(sn1, list.getRegionLocation(1).getServerName());
175    assertEquals(sn0, list.getRegionLocation(2).getServerName());
176    assertNull(list.getRegionLocation(5));
177    assertNull(list.getRegionLocation(9));
178  }
179
180  @Test
181  public void testUpdateLocation() {
182    RegionLocations list;
183
184    // test add to empty list
185    list = new RegionLocations();
186    list = list.updateLocation(hrl(info0, sn1), false, false);
187    assertEquals(sn1, list.getRegionLocation(0).getServerName());
188
189    // test add to non-empty list
190    list = list.updateLocation(hrl(info9, sn3, 10), false, false);
191    assertEquals(sn3, list.getRegionLocation(9).getServerName());
192    assertEquals(10, list.size());
193    list = list.updateLocation(hrl(info2, sn2, 10), false, false);
194    assertEquals(sn2, list.getRegionLocation(2).getServerName());
195    assertEquals(10, list.size());
196
197    // test update greater SeqNum
198    list = list.updateLocation(hrl(info2, sn3, 11), false, false);
199    assertEquals(sn3, list.getRegionLocation(2).getServerName());
200    assertEquals(sn3, list.getRegionLocation(9).getServerName());
201
202    // test update equal SeqNum
203    list = list.updateLocation(hrl(info2, sn1, 11), false, false); // should not update
204    assertEquals(sn3, list.getRegionLocation(2).getServerName());
205    assertEquals(sn3, list.getRegionLocation(9).getServerName());
206    list = list.updateLocation(hrl(info2, sn1, 11), true, false); // should update
207    assertEquals(sn1, list.getRegionLocation(2).getServerName());
208    assertEquals(sn3, list.getRegionLocation(9).getServerName());
209
210    // test force update
211    list = list.updateLocation(hrl(info2, sn2, 9), false, true); // should update
212    assertEquals(sn2, list.getRegionLocation(2).getServerName());
213    assertEquals(sn3, list.getRegionLocation(9).getServerName());
214  }
215
216  @Test
217  public void testMergeLocations() {
218    RegionLocations list1, list2;
219
220    // test merge empty lists
221    list1 = new RegionLocations();
222    list2 = new RegionLocations();
223
224    assertTrue(list1 == list1.mergeLocations(list2));
225
226    // test merge non-empty and empty
227    list2 = hrll(hrl(info0, sn0));
228    list1 = list1.mergeLocations(list2);
229    assertEquals(sn0, list1.getRegionLocation(0).getServerName());
230
231    // test merge empty and non empty
232    list1 = hrll();
233    list1 = list2.mergeLocations(list1);
234    assertEquals(sn0, list1.getRegionLocation(0).getServerName());
235
236    // test merge non intersecting
237    list1 = hrll(hrl(info0, sn0), hrl(info1, sn1));
238    list2 = hrll(hrl(info2, sn2));
239    list1 = list2.mergeLocations(list1);
240    assertEquals(sn0, list1.getRegionLocation(0).getServerName());
241    assertEquals(sn1, list1.getRegionLocation(1).getServerName());
242    assertEquals(2, list1.size()); // the size is taken from the argument list to merge
243
244    // do the other way merge as well
245    list1 = hrll(hrl(info0, sn0), hrl(info1, sn1));
246    list2 = hrll(hrl(info2, sn2));
247    list1 = list1.mergeLocations(list2);
248    assertEquals(sn0, list1.getRegionLocation(0).getServerName());
249    assertEquals(sn1, list1.getRegionLocation(1).getServerName());
250    assertEquals(sn2, list1.getRegionLocation(2).getServerName());
251
252    // test intersecting lists same seqNum
253    list1 = hrll(hrl(info0, sn0), hrl(info1, sn1));
254    list2 = hrll(hrl(info0, sn2), hrl(info1, sn2), hrl(info9, sn3));
255    list1 = list2.mergeLocations(list1); // list1 should override
256    assertEquals(2, list1.size());
257    assertEquals(sn0, list1.getRegionLocation(0).getServerName());
258    assertEquals(sn1, list1.getRegionLocation(1).getServerName());
259
260    // do the other way
261    list1 = hrll(hrl(info0, sn0), hrl(info1, sn1));
262    list2 = hrll(hrl(info0, sn2), hrl(info1, sn2), hrl(info9, sn3));
263    list1 = list1.mergeLocations(list2); // list2 should override
264    assertEquals(10, list1.size());
265    assertEquals(sn2, list1.getRegionLocation(0).getServerName());
266    assertEquals(sn2, list1.getRegionLocation(1).getServerName());
267    assertEquals(sn3, list1.getRegionLocation(9).getServerName());
268
269    // test intersecting lists different seqNum
270    list1 = hrll(hrl(info0, sn0, 10), hrl(info1, sn1, 10));
271    list2 = hrll(hrl(info0, sn2, 11), hrl(info1, sn2, 11), hrl(info9, sn3, 11));
272    list1 = list1.mergeLocations(list2); // list2 should override because of seqNum
273    assertEquals(10, list1.size());
274    assertEquals(sn2, list1.getRegionLocation(0).getServerName());
275    assertEquals(sn2, list1.getRegionLocation(1).getServerName());
276    assertEquals(sn3, list1.getRegionLocation(9).getServerName());
277
278    // do the other way
279    list1 = hrll(hrl(info0, sn0, 10), hrl(info1, sn1, 10));
280    list2 = hrll(hrl(info0, sn2, 11), hrl(info1, sn2, 11), hrl(info9, sn3, 11));
281    list1 = list1.mergeLocations(list2); // list2 should override
282    assertEquals(10, list1.size());
283    assertEquals(sn2, list1.getRegionLocation(0).getServerName());
284    assertEquals(sn2, list1.getRegionLocation(1).getServerName());
285    assertEquals(sn3, list1.getRegionLocation(9).getServerName());
286  }
287
288  @Test
289  public void testMergeLocationsWithDifferentRegionId() {
290    RegionLocations list1, list2;
291
292    // test merging two lists. But the list2 contains region replicas with a different region id
293    RegionInfo info0 = hri(regionId1, 0);
294    RegionInfo info1 = hri(regionId1, 1);
295    RegionInfo info2 = hri(regionId2, 2);
296
297    list1 = hrll(hrl(info2, sn1));
298    list2 = hrll(hrl(info0, sn2), hrl(info1, sn2));
299    list1 = list2.mergeLocations(list1);
300    assertNull(list1.getRegionLocation(0));
301    assertNull(list1.getRegionLocation(1));
302    assertNotNull(list1.getRegionLocation(2));
303    assertEquals(sn1, list1.getRegionLocation(2).getServerName());
304    assertEquals(3, list1.size());
305
306    // try the other way merge
307    list1 = hrll(hrl(info2, sn1));
308    list2 = hrll(hrl(info0, sn2), hrl(info1, sn2));
309    list2 = list1.mergeLocations(list2);
310    assertNotNull(list2.getRegionLocation(0));
311    assertNotNull(list2.getRegionLocation(1));
312    assertNull(list2.getRegionLocation(2));
313  }
314
315  @Test
316  public void testUpdateLocationWithDifferentRegionId() {
317    RegionLocations list;
318
319    RegionInfo info0 = hri(regionId1, 0);
320    RegionInfo info1 = hri(regionId2, 1);
321    RegionInfo info2 = hri(regionId1, 2);
322
323    list = new RegionLocations(hrl(info0, sn1), hrl(info2, sn1));
324
325    list = list.updateLocation(hrl(info1, sn2), false, true); // force update
326
327    // the other locations should be removed now
328    assertNull(list.getRegionLocation(0));
329    assertNotNull(list.getRegionLocation(1));
330    assertNull(list.getRegionLocation(2));
331    assertEquals(sn2, list.getRegionLocation(1).getServerName());
332    assertEquals(3, list.size());
333  }
334
335  @Test
336  public void testConstructWithNullElements() {
337    // RegionLocations can contain null elements as well. These null elements can
338
339    RegionLocations list = new RegionLocations((HRegionLocation) null);
340    assertTrue(list.isEmpty());
341    assertEquals(1, list.size());
342    assertEquals(0, list.numNonNullElements());
343
344    list = new RegionLocations(null, hrl(info1, sn0));
345    assertFalse(list.isEmpty());
346    assertEquals(2, list.size());
347    assertEquals(1, list.numNonNullElements());
348
349    list = new RegionLocations(hrl(info0, sn0), null);
350    assertEquals(2, list.size());
351    assertEquals(1, list.numNonNullElements());
352
353    list = new RegionLocations(null, hrl(info2, sn0), null, hrl(info9, sn0));
354    assertEquals(10, list.size());
355    assertEquals(2, list.numNonNullElements());
356
357    list = new RegionLocations(null, hrl(info2, sn0), null, hrl(info9, sn0), null);
358    assertEquals(11, list.size());
359    assertEquals(2, list.numNonNullElements());
360
361    list = new RegionLocations(null, hrl(info2, sn0), null, hrl(info9, sn0), null, null);
362    assertEquals(12, list.size());
363    assertEquals(2, list.numNonNullElements());
364  }
365}