View Javadoc

1   /**
2    * Copyright The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  package org.apache.hadoop.hbase.client;
21  
22  import static org.junit.Assert.assertEquals;
23  import static org.junit.Assert.assertTrue;
24  
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogFactory;
27  import org.apache.hadoop.hbase.HBaseTestingUtility;
28  import org.apache.hadoop.hbase.HRegionLocation;
29  import org.apache.hadoop.hbase.MiniHBaseCluster;
30  import org.apache.hadoop.hbase.ServerName;
31  import org.apache.hadoop.hbase.TableName;
32  import org.apache.hadoop.hbase.regionserver.HRegionServer;
33  import org.apache.hadoop.hbase.testclassification.ClientTests;
34  import org.apache.hadoop.hbase.testclassification.LargeTests;
35  import org.apache.hadoop.hbase.util.Bytes;
36  import org.apache.hadoop.hbase.util.Pair;
37  import org.junit.AfterClass;
38  import org.junit.BeforeClass;
39  import org.junit.Test;
40  import org.junit.experimental.categories.Category;
41  
42  import static org.junit.Assert.assertNotNull;
43  
44  @Category({ LargeTests.class, ClientTests.class })
45  public class TestHTableMultiplexerFlushCache {
46    private static final Log LOG = LogFactory.getLog(TestHTableMultiplexerFlushCache.class);
47    private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
48    private static byte[] FAMILY = Bytes.toBytes("testFamily");
49    private static byte[] QUALIFIER1 = Bytes.toBytes("testQualifier_1");
50    private static byte[] QUALIFIER2 = Bytes.toBytes("testQualifier_2");
51    private static byte[] VALUE1 = Bytes.toBytes("testValue1");
52    private static byte[] VALUE2 = Bytes.toBytes("testValue2");
53    private static int SLAVES = 3;
54    private static int PER_REGIONSERVER_QUEUE_SIZE = 100000;
55  
56    /**
57     * @throws java.lang.Exception
58     */
59    @BeforeClass
60    public static void setUpBeforeClass() throws Exception {
61      TEST_UTIL.startMiniCluster(SLAVES);
62    }
63  
64    /**
65     * @throws java.lang.Exception
66     */
67    @AfterClass
68    public static void tearDownAfterClass() throws Exception {
69      TEST_UTIL.shutdownMiniCluster();
70    }
71  
72    private static void checkExistence(HTable htable, byte[] row, byte[] family, byte[] quality,
73        byte[] value) throws Exception {
74      // verify that the Get returns the correct result
75      Result r;
76      Get get = new Get(row);
77      get.addColumn(family, quality);
78      int nbTry = 0;
79      do {
80        assertTrue("Fail to get from " + htable.getName() + " after " + nbTry + " tries", nbTry < 50);
81        nbTry++;
82        Thread.sleep(100);
83        r = htable.get(get);
84      } while (r == null || r.getValue(family, quality) == null);
85      assertEquals("value", Bytes.toStringBinary(value),
86        Bytes.toStringBinary(r.getValue(family, quality)));
87    }
88  
89    @Test
90    public void testOnRegionChange() throws Exception {
91      TableName TABLE = TableName.valueOf("testOnRegionChange");
92      final int NUM_REGIONS = 10;
93      HTable htable = TEST_UTIL.createTable(TABLE, new byte[][] { FAMILY }, 3,
94        Bytes.toBytes("aaaaa"), Bytes.toBytes("zzzzz"), NUM_REGIONS);
95  
96      HTableMultiplexer multiplexer = new HTableMultiplexer(TEST_UTIL.getConfiguration(), 
97        PER_REGIONSERVER_QUEUE_SIZE);
98      
99      byte[][] startRows = htable.getStartKeys();
100     byte[] row = startRows[1];
101     assertTrue("2nd region should not start with empty row", row != null && row.length > 0);
102 
103     Put put = new Put(row).add(FAMILY, QUALIFIER1, VALUE1);
104     assertTrue("multiplexer.put returns", multiplexer.put(TABLE, put));
105     
106     checkExistence(htable, row, FAMILY, QUALIFIER1, VALUE1);
107 
108     // Now let's shutdown the regionserver and let regions moved to other servers.
109     HRegionLocation loc = htable.getRegionLocation(row);
110     MiniHBaseCluster hbaseCluster = TEST_UTIL.getHBaseCluster(); 
111     hbaseCluster.stopRegionServer(loc.getServerName());
112     TEST_UTIL.waitUntilAllRegionsAssigned(TABLE);
113 
114     // put with multiplexer.
115     put = new Put(row).add(FAMILY, QUALIFIER2, VALUE2);
116     assertTrue("multiplexer.put returns", multiplexer.put(TABLE, put));
117 
118     checkExistence(htable, row, FAMILY, QUALIFIER2, VALUE2);
119   }
120 
121   @Test
122   public void testOnRegionMove() throws Exception {
123     // This test is doing near exactly the same thing that testOnRegionChange but avoiding the
124     // potential to get a ConnectionClosingException. By moving the region, we can be certain that
125     // the connection is still valid and that the implementation is correctly handling an invalid
126     // Region cache (and not just tearing down the entire connection).
127     TableName TABLE = TableName.valueOf("testOnRegionMove");
128     final int NUM_REGIONS = 10;
129     HTable htable = TEST_UTIL.createTable(TABLE, new byte[][] { FAMILY }, 3,
130       Bytes.toBytes("aaaaa"), Bytes.toBytes("zzzzz"), NUM_REGIONS);
131 
132     HTableMultiplexer multiplexer = new HTableMultiplexer(TEST_UTIL.getConfiguration(),
133       PER_REGIONSERVER_QUEUE_SIZE);
134 
135     final RegionLocator regionLocator = TEST_UTIL.getConnection().getRegionLocator(TABLE);
136     Pair<byte[][],byte[][]> startEndRows = regionLocator.getStartEndKeys();
137     byte[] row = startEndRows.getFirst()[1];
138     assertTrue("2nd region should not start with empty row", row != null && row.length > 0);
139 
140     Put put = new Put(row).addColumn(FAMILY, QUALIFIER1, VALUE1);
141     assertTrue("multiplexer.put returns", multiplexer.put(TABLE, put));
142 
143     checkExistence(htable, row, FAMILY, QUALIFIER1, VALUE1);
144 
145     final HRegionLocation loc = regionLocator.getRegionLocation(row);
146     final MiniHBaseCluster hbaseCluster = TEST_UTIL.getHBaseCluster();
147     // The current server for the region we're writing to
148     final ServerName originalServer = loc.getServerName();
149     ServerName newServer = null;
150     // Find a new server to move that region to
151     for (int i = 0; i < SLAVES; i++) {
152       HRegionServer rs = hbaseCluster.getRegionServer(i);
153       if (!rs.getServerName().equals(originalServer)) {
154         newServer = rs.getServerName();
155         break;
156       }
157     }
158     assertNotNull("Did not find a new RegionServer to use", newServer);
159 
160     // Move the region
161     LOG.info("Moving " + loc.getRegionInfo().getEncodedName() + " from " + originalServer
162         +  " to " + newServer);
163     TEST_UTIL.getHBaseAdmin().move(loc.getRegionInfo().getEncodedNameAsBytes(),
164         Bytes.toBytes(newServer.getServerName()));
165 
166     TEST_UTIL.waitUntilAllRegionsAssigned(TABLE);
167 
168     // Send a new Put
169     put = new Put(row).addColumn(FAMILY, QUALIFIER2, VALUE2);
170     assertTrue("multiplexer.put returns", multiplexer.put(TABLE, put));
171 
172     // We should see the update make it to the new server eventually
173     checkExistence(htable, row, FAMILY, QUALIFIER2, VALUE2);
174   }
175 }