1   /**
2    * Copyright 2011 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  
23  import static org.junit.Assert.assertEquals;
24  import static org.junit.Assert.assertFalse;
25  import static org.junit.Assert.assertTrue;
26  import static org.junit.Assert.fail;
27  
28  import java.io.IOException;
29  import java.util.ArrayList;
30  import java.util.HashMap;
31  import java.util.Iterator;
32  import java.util.List;
33  import java.util.Map;
34  import java.util.concurrent.atomic.AtomicBoolean;
35  import java.util.concurrent.atomic.AtomicInteger;
36  
37  import org.apache.commons.logging.Log;
38  import org.apache.commons.logging.LogFactory;
39  import org.apache.hadoop.conf.Configuration;
40  import org.apache.hadoop.hbase.HBaseTestingUtility;
41  import org.apache.hadoop.hbase.HColumnDescriptor;
42  import org.apache.hadoop.hbase.HConstants;
43  import org.apache.hadoop.hbase.HRegionInfo;
44  import org.apache.hadoop.hbase.HServerAddress;
45  import org.apache.hadoop.hbase.HServerInfo;
46  import org.apache.hadoop.hbase.HTableDescriptor;
47  import org.apache.hadoop.hbase.NotServingRegionException;
48  import org.apache.hadoop.hbase.ServerName;
49  import org.apache.hadoop.hbase.TableExistsException;
50  import org.apache.hadoop.hbase.TableNotDisabledException;
51  import org.apache.hadoop.hbase.TableNotEnabledException;
52  import org.apache.hadoop.hbase.TableNotFoundException;
53  import org.apache.hadoop.hbase.executor.EventHandler;
54  import org.apache.hadoop.hbase.executor.EventHandler.EventType;
55  import org.apache.hadoop.hbase.executor.ExecutorService;
56  import org.apache.hadoop.hbase.ipc.HRegionInterface;
57  import org.apache.hadoop.hbase.master.MasterServices;
58  import org.apache.hadoop.hbase.regionserver.HRegion;
59  import org.apache.hadoop.hbase.regionserver.HRegionServer;
60  import org.apache.hadoop.hbase.regionserver.wal.HLog;
61  import org.apache.hadoop.hbase.regionserver.wal.TestHLogUtils;
62  import org.apache.hadoop.hbase.InvalidFamilyOperationException;
63  import org.apache.hadoop.hbase.util.Bytes;
64  import org.apache.hadoop.hbase.zookeeper.ZKAssign;
65  import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
66  import org.apache.zookeeper.KeeperException;
67  import org.junit.After;
68  import org.junit.AfterClass;
69  import org.junit.Before;
70  import org.junit.BeforeClass;
71  import org.junit.Test;
72  
73  
74  /**
75   * Class to test HBaseAdmin.
76   * Spins up the minicluster once at test start and then takes it down afterward.
77   * Add any testing of HBaseAdmin functionality here.
78   */
79  public class TestAdmin {
80    final Log LOG = LogFactory.getLog(getClass());
81    private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
82    private HBaseAdmin admin;
83  
84    @BeforeClass
85    public static void setUpBeforeClass() throws Exception {
86      TEST_UTIL.getConfiguration().setBoolean("hbase.online.schema.update.enable", true);
87      TEST_UTIL.getConfiguration().setInt("hbase.regionserver.msginterval", 100);
88      TEST_UTIL.getConfiguration().setInt("hbase.client.pause", 250);
89      TEST_UTIL.getConfiguration().setInt("hbase.client.retries.number", 6);
90      TEST_UTIL.startMiniCluster(3);
91    }
92  
93    @AfterClass
94    public static void tearDownAfterClass() throws Exception {
95      TEST_UTIL.shutdownMiniCluster();
96    }
97  
98    @Before
99    public void setUp() throws Exception {
100     this.admin = new HBaseAdmin(TEST_UTIL.getConfiguration());
101   }
102 
103   @After
104   public void tearDown() throws Exception {
105     this.admin.close();
106   }
107 
108   @Test
109   public void testDeleteEditUnknownColumnFamilyAndOrTable() throws IOException {
110     // Test we get exception if we try to 
111     final String nonexistent = "nonexistent";
112     HColumnDescriptor nonexistentHcd = new HColumnDescriptor(nonexistent);
113     Exception exception = null;
114     try {
115       this.admin.addColumn(nonexistent, nonexistentHcd);
116     } catch (IOException e) {
117       exception = e;
118     }
119     assertTrue(exception instanceof TableNotFoundException);
120 
121     exception = null;
122     try {
123       this.admin.deleteTable(nonexistent);
124     } catch (IOException e) {
125       exception = e;
126     }
127     assertTrue(exception instanceof TableNotFoundException);
128 
129     exception = null;
130     try {
131       this.admin.deleteColumn(nonexistent, nonexistent);
132     } catch (IOException e) {
133       exception = e;
134     }
135     assertTrue(exception instanceof TableNotFoundException);
136 
137     exception = null;
138     try {
139       this.admin.disableTable(nonexistent);
140     } catch (IOException e) {
141       exception = e;
142     }
143     assertTrue(exception instanceof TableNotFoundException);
144 
145     exception = null;
146     try {
147       this.admin.enableTable(nonexistent);
148     } catch (IOException e) {
149       exception = e;
150     }
151     assertTrue(exception instanceof TableNotFoundException);
152 
153     exception = null;
154     try {
155       this.admin.modifyColumn(nonexistent, nonexistentHcd);
156     } catch (IOException e) {
157       exception = e;
158     }
159     assertTrue(exception instanceof TableNotFoundException);
160 
161     exception = null;
162     try {
163       HTableDescriptor htd = new HTableDescriptor(nonexistent);
164       this.admin.modifyTable(htd.getName(), htd);
165     } catch (IOException e) {
166       exception = e;
167     }
168     assertTrue(exception instanceof TableNotFoundException);
169 
170     // Now make it so at least the table exists and then do tests against a
171     // nonexistent column family -- see if we get right exceptions.
172     final String tableName = "t";
173     HTableDescriptor htd = new HTableDescriptor(tableName);
174     htd.addFamily(new HColumnDescriptor("cf"));
175     this.admin.createTable(htd);
176     try {
177       exception = null;
178       try {
179         this.admin.deleteColumn(htd.getName(), nonexistentHcd.getName());
180       } catch (IOException e) {
181         exception = e;
182       }
183       assertTrue(exception instanceof InvalidFamilyOperationException);
184 
185       exception = null;
186       try {
187         this.admin.modifyColumn(htd.getName(), nonexistentHcd);
188       } catch (IOException e) {
189         exception = e;
190       }
191       assertTrue(exception instanceof InvalidFamilyOperationException);
192     } finally {
193       this.admin.disableTable(tableName);
194       this.admin.deleteTable(tableName);
195     }
196   }
197 
198   @Test
199   public void testDisableAndEnableTable() throws IOException {
200     final byte [] row = Bytes.toBytes("row");
201     final byte [] qualifier = Bytes.toBytes("qualifier");
202     final byte [] value = Bytes.toBytes("value");
203     final byte [] table = Bytes.toBytes("testDisableAndEnableTable");
204     HTable ht = TEST_UTIL.createTable(table, HConstants.CATALOG_FAMILY);
205     Put put = new Put(row);
206     put.add(HConstants.CATALOG_FAMILY, qualifier, value);
207     ht.put(put);
208     Get get = new Get(row);
209     get.addColumn(HConstants.CATALOG_FAMILY, qualifier);
210     ht.get(get);
211 
212     this.admin.disableTable(table);
213 
214     // Test that table is disabled
215     get = new Get(row);
216     get.addColumn(HConstants.CATALOG_FAMILY, qualifier);
217     boolean ok = false;
218     try {
219       ht.get(get);
220     } catch (NotServingRegionException e) {
221       ok = true;
222     } catch (RetriesExhaustedException e) {
223       ok = true;
224     }
225     assertTrue(ok);
226     this.admin.enableTable(table);
227 
228     // Test that table is enabled
229     try {
230       ht.get(get);
231     } catch (RetriesExhaustedException e) {
232       ok = false;
233     }
234     assertTrue(ok);
235   }
236 
237   @Test
238   public void testDisableAndEnableTables() throws IOException {
239     final byte [] row = Bytes.toBytes("row");
240     final byte [] qualifier = Bytes.toBytes("qualifier");
241     final byte [] value = Bytes.toBytes("value");
242     final byte [] table1 = Bytes.toBytes("testDisableAndEnableTable1");
243     final byte [] table2 = Bytes.toBytes("testDisableAndEnableTable2");
244     HTable ht1 = TEST_UTIL.createTable(table1, HConstants.CATALOG_FAMILY);
245     HTable ht2 = TEST_UTIL.createTable(table2, HConstants.CATALOG_FAMILY);
246     Put put = new Put(row);
247     put.add(HConstants.CATALOG_FAMILY, qualifier, value);
248     ht1.put(put);
249     ht2.put(put);
250     Get get = new Get(row);
251     get.addColumn(HConstants.CATALOG_FAMILY, qualifier);
252     ht1.get(get);
253     ht2.get(get);
254 
255     this.admin.disableTables("testDisableAndEnableTable.*");
256 
257     // Test that tables are disabled
258     get = new Get(row);
259     get.addColumn(HConstants.CATALOG_FAMILY, qualifier);
260     boolean ok = false;
261     try {
262       ht1.get(get);
263       ht2.get(get);
264     } catch (NotServingRegionException e) {
265       ok = true;
266     } catch (RetriesExhaustedException e) {
267       ok = true;
268     }
269     assertTrue(ok);
270     this.admin.enableTables("testDisableAndEnableTable.*");
271 
272     // Test that tables are enabled
273     try {
274       ht1.get(get);
275     } catch (RetriesExhaustedException e) {
276       ok = false;
277     }
278     try {
279       ht2.get(get);
280     } catch (RetriesExhaustedException e) {
281       ok = false;
282     }
283     assertTrue(ok);
284   }
285 
286   @Test
287   public void testCreateTable() throws IOException {
288     HTableDescriptor [] tables = admin.listTables();
289     int numTables = tables.length;
290     TEST_UTIL.createTable(Bytes.toBytes("testCreateTable"),
291       HConstants.CATALOG_FAMILY);
292     tables = this.admin.listTables();
293     assertEquals(numTables + 1, tables.length);
294   }
295 
296   @Test
297   public void testGetTableDescriptor() throws IOException {
298     HColumnDescriptor fam1 = new HColumnDescriptor("fam1");
299     HColumnDescriptor fam2 = new HColumnDescriptor("fam2");
300     HColumnDescriptor fam3 = new HColumnDescriptor("fam3");
301     HTableDescriptor htd = new HTableDescriptor("myTestTable");
302     htd.addFamily(fam1);
303     htd.addFamily(fam2);
304     htd.addFamily(fam3);
305     this.admin.createTable(htd);
306     HTable table = new HTable(TEST_UTIL.getConfiguration(), "myTestTable");
307     HTableDescriptor confirmedHtd = table.getTableDescriptor();
308     assertEquals(htd.compareTo(confirmedHtd), 0);
309   }
310 
311   @Test
312   public void testHColumnValidName() {
313        boolean exceptionThrown = false;
314        try {
315        HColumnDescriptor fam1 = new HColumnDescriptor("\\test\\abc");
316        } catch(IllegalArgumentException iae) {
317            exceptionThrown = true;
318            assertTrue(exceptionThrown);
319        }
320    }
321   /**
322    * Verify schema modification takes.
323    * @throws IOException
324    * @throws InterruptedException
325    */
326   @Test 
327   public void testOnlineChangeTableSchema() throws IOException, InterruptedException {
328     final byte [] tableName = Bytes.toBytes("changeTableSchemaOnline");
329     TEST_UTIL.getMiniHBaseCluster().getMaster().getConfiguration().setBoolean(
330         "hbase.online.schema.update.enable", true);
331     HTableDescriptor [] tables = admin.listTables();
332     int numTables = tables.length;
333     TEST_UTIL.createTable(tableName, HConstants.CATALOG_FAMILY);
334     tables = this.admin.listTables();
335     assertEquals(numTables + 1, tables.length);
336 
337     // FIRST, do htabledescriptor changes.
338     HTableDescriptor htd = this.admin.getTableDescriptor(tableName);
339     // Make a copy and assert copy is good.
340     HTableDescriptor copy = new HTableDescriptor(htd);
341     assertTrue(htd.equals(copy));
342     // Now amend the copy. Introduce differences.
343     long newFlushSize = htd.getMemStoreFlushSize() / 2;
344     copy.setMemStoreFlushSize(newFlushSize);
345     final String key = "anyoldkey";
346     assertTrue(htd.getValue(key) == null);
347     copy.setValue(key, key);
348     boolean expectedException = false;
349     try {
350       modifyTable(tableName, copy);
351     } catch (TableNotDisabledException re) {
352       expectedException = true;
353     }
354     assertFalse(expectedException);
355     HTableDescriptor modifiedHtd = this.admin.getTableDescriptor(tableName);
356     assertFalse(htd.equals(modifiedHtd));
357     assertTrue(copy.equals(modifiedHtd));
358     assertEquals(newFlushSize, modifiedHtd.getMemStoreFlushSize());
359     assertEquals(key, modifiedHtd.getValue(key));
360 
361     // Now work on column family changes.
362     htd = this.admin.getTableDescriptor(tableName);
363     int countOfFamilies = modifiedHtd.getFamilies().size();
364     assertTrue(countOfFamilies > 0);
365     HColumnDescriptor hcd = modifiedHtd.getFamilies().iterator().next();
366     int maxversions = hcd.getMaxVersions();
367     final int newMaxVersions = maxversions + 1;
368     hcd.setMaxVersions(newMaxVersions);
369     final byte [] hcdName = hcd.getName();
370     expectedException = false;
371     try {
372       this.admin.modifyColumn(tableName, hcd);
373     } catch (TableNotDisabledException re) {
374       expectedException = true;
375     }
376     assertFalse(expectedException);
377     modifiedHtd = this.admin.getTableDescriptor(tableName);
378     HColumnDescriptor modifiedHcd = modifiedHtd.getFamily(hcdName);
379     assertEquals(newMaxVersions, modifiedHcd.getMaxVersions());
380 
381     // Try adding a column
382     assertFalse(this.admin.isTableDisabled(tableName));
383     final String xtracolName = "xtracol";
384     htd = this.admin.getTableDescriptor(tableName);
385     HColumnDescriptor xtracol = new HColumnDescriptor(xtracolName);
386     xtracol.setValue(xtracolName, xtracolName);
387     expectedException = false;
388     try {
389       this.admin.addColumn(tableName, xtracol);
390     } catch (TableNotDisabledException re) {
391       expectedException = true;
392     }
393     // Add column should work even if the table is enabled
394     assertFalse(expectedException);
395     modifiedHtd = this.admin.getTableDescriptor(tableName);
396     hcd = modifiedHtd.getFamily(xtracol.getName());
397     assertTrue(hcd != null);
398     assertTrue(hcd.getValue(xtracolName).equals(xtracolName));
399 
400     // Delete the just-added column.
401     this.admin.deleteColumn(tableName, xtracol.getName());
402     modifiedHtd = this.admin.getTableDescriptor(tableName);
403     hcd = modifiedHtd.getFamily(xtracol.getName());
404     assertTrue(hcd == null);
405 
406     // Delete the table
407     this.admin.disableTable(tableName);
408     this.admin.deleteTable(tableName);
409     this.admin.listTables();
410     assertFalse(this.admin.tableExists(tableName));
411   }
412   
413   @Test
414   public void testShouldFailOnlineSchemaUpdateIfOnlineSchemaIsNotEnabled()
415       throws Exception {
416     final byte[] tableName = Bytes.toBytes("changeTableSchemaOnlineFailure");
417     TEST_UTIL.getMiniHBaseCluster().getMaster().getConfiguration().setBoolean(
418         "hbase.online.schema.update.enable", false);
419     HTableDescriptor[] tables = admin.listTables();
420     int numTables = tables.length;
421     TEST_UTIL.createTable(tableName, HConstants.CATALOG_FAMILY);
422     tables = this.admin.listTables();
423     assertEquals(numTables + 1, tables.length);
424 
425     // FIRST, do htabledescriptor changes.
426     HTableDescriptor htd = this.admin.getTableDescriptor(tableName);
427     // Make a copy and assert copy is good.
428     HTableDescriptor copy = new HTableDescriptor(htd);
429     assertTrue(htd.equals(copy));
430     // Now amend the copy. Introduce differences.
431     long newFlushSize = htd.getMemStoreFlushSize() / 2;
432     copy.setMemStoreFlushSize(newFlushSize);
433     final String key = "anyoldkey";
434     assertTrue(htd.getValue(key) == null);
435     copy.setValue(key, key);
436     boolean expectedException = false;
437     try {
438       modifyTable(tableName, copy);
439     } catch (TableNotDisabledException re) {
440       expectedException = true;
441     }
442     assertTrue("Online schema update should not happen.", expectedException);
443   }
444 
445   /**
446    * Modify table is async so wait on completion of the table operation in master.
447    * @param tableName
448    * @param htd
449    * @throws IOException
450    */
451   private void modifyTable(final byte [] tableName, final HTableDescriptor htd)
452   throws IOException {
453     MasterServices services = TEST_UTIL.getMiniHBaseCluster().getMaster();
454     ExecutorService executor = services.getExecutorService();
455     AtomicBoolean done = new AtomicBoolean(false);
456     executor.registerListener(EventType.C_M_MODIFY_TABLE, new DoneListener(done));
457     this.admin.modifyTable(tableName, htd);
458     while (!done.get()) {
459       synchronized (done) {
460         try {
461           done.wait(100);
462         } catch (InterruptedException e) {
463           e.printStackTrace();
464         }
465       }
466     }
467     executor.unregisterListener(EventType.C_M_MODIFY_TABLE);
468   }
469 
470   /**
471    * Listens for when an event is done in Master.
472    */
473   static class DoneListener implements EventHandler.EventHandlerListener {
474     private final AtomicBoolean done;
475 
476     DoneListener(final AtomicBoolean done) {
477       super();
478       this.done = done;
479     }
480 
481     @Override
482     public void afterProcess(EventHandler event) {
483       this.done.set(true);
484       synchronized (this.done) {
485         // Wake anyone waiting on this value to change.
486         this.done.notifyAll();
487       }
488     }
489 
490     @Override
491     public void beforeProcess(EventHandler event) {
492       // continue
493     }
494   }
495 
496   protected void verifyRoundRobinDistribution(HTable ht, int expectedRegions) throws IOException {
497     int numRS = ht.getConnection().getCurrentNrHRS();
498     Map<HRegionInfo,HServerAddress> regions = ht.getRegionsInfo();
499     Map<HServerAddress, List<HRegionInfo>> server2Regions = new HashMap<HServerAddress, List<HRegionInfo>>();
500     for (Map.Entry<HRegionInfo,HServerAddress> entry : regions.entrySet()) {
501       HServerAddress server = entry.getValue();
502       List<HRegionInfo> regs = server2Regions.get(server);
503       if (regs == null) {
504         regs = new ArrayList<HRegionInfo>();
505         server2Regions.put(server, regs);
506       }
507       regs.add(entry.getKey());
508     }
509     float average = (float) expectedRegions/numRS;
510     int min = (int)Math.floor(average);
511     int max = (int)Math.ceil(average);
512     for (List<HRegionInfo> regionList : server2Regions.values()) {
513       assertTrue(regionList.size() == min || regionList.size() == max);
514     }
515   }
516 
517   @Test
518   public void testCreateTableWithRegions() throws IOException, InterruptedException {
519 
520     byte[] tableName = Bytes.toBytes("testCreateTableWithRegions");
521 
522     byte [][] splitKeys = {
523         new byte [] { 1, 1, 1 },
524         new byte [] { 2, 2, 2 },
525         new byte [] { 3, 3, 3 },
526         new byte [] { 4, 4, 4 },
527         new byte [] { 5, 5, 5 },
528         new byte [] { 6, 6, 6 },
529         new byte [] { 7, 7, 7 },
530         new byte [] { 8, 8, 8 },
531         new byte [] { 9, 9, 9 },
532     };
533     int expectedRegions = splitKeys.length + 1;
534 
535     HTableDescriptor desc = new HTableDescriptor(tableName);
536     desc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY));
537     admin.createTable(desc, splitKeys);
538 
539     HTable ht = new HTable(TEST_UTIL.getConfiguration(), tableName);
540     Map<HRegionInfo,HServerAddress> regions = ht.getRegionsInfo();
541     assertEquals("Tried to create " + expectedRegions + " regions " +
542         "but only found " + regions.size(),
543         expectedRegions, regions.size());
544     System.err.println("Found " + regions.size() + " regions");
545 
546     Iterator<HRegionInfo> hris = regions.keySet().iterator();
547     HRegionInfo hri = hris.next();
548     assertTrue(hri.getStartKey() == null || hri.getStartKey().length == 0);
549     assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[0]));
550     hri = hris.next();
551     assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[0]));
552     assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[1]));
553     hri = hris.next();
554     assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[1]));
555     assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[2]));
556     hri = hris.next();
557     assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[2]));
558     assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[3]));
559     hri = hris.next();
560     assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[3]));
561     assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[4]));
562     hri = hris.next();
563     assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[4]));
564     assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[5]));
565     hri = hris.next();
566     assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[5]));
567     assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[6]));
568     hri = hris.next();
569     assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[6]));
570     assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[7]));
571     hri = hris.next();
572     assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[7]));
573     assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[8]));
574     hri = hris.next();
575     assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[8]));
576     assertTrue(hri.getEndKey() == null || hri.getEndKey().length == 0);
577 
578     verifyRoundRobinDistribution(ht, expectedRegions);
579 
580     // Now test using start/end with a number of regions
581 
582     // Use 80 bit numbers to make sure we aren't limited
583     byte [] startKey = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
584     byte [] endKey =   { 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 };
585 
586     // Splitting into 10 regions, we expect (null,1) ... (9, null)
587     // with (1,2) (2,3) (3,4) (4,5) (5,6) (6,7) (7,8) (8,9) in the middle
588 
589     expectedRegions = 10;
590 
591     byte [] TABLE_2 = Bytes.add(tableName, Bytes.toBytes("_2"));
592 
593     desc = new HTableDescriptor(TABLE_2);
594     desc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY));
595     admin = new HBaseAdmin(TEST_UTIL.getConfiguration());
596     admin.createTable(desc, startKey, endKey, expectedRegions);
597 
598     ht = new HTable(TEST_UTIL.getConfiguration(), TABLE_2);
599     regions = ht.getRegionsInfo();
600     assertEquals("Tried to create " + expectedRegions + " regions " +
601         "but only found " + regions.size(),
602         expectedRegions, regions.size());
603     System.err.println("Found " + regions.size() + " regions");
604 
605     hris = regions.keySet().iterator();
606     hri = hris.next();
607     assertTrue(hri.getStartKey() == null || hri.getStartKey().length == 0);
608     assertTrue(Bytes.equals(hri.getEndKey(), new byte [] {1,1,1,1,1,1,1,1,1,1}));
609     hri = hris.next();
610     assertTrue(Bytes.equals(hri.getStartKey(), new byte [] {1,1,1,1,1,1,1,1,1,1}));
611     assertTrue(Bytes.equals(hri.getEndKey(), new byte [] {2,2,2,2,2,2,2,2,2,2}));
612     hri = hris.next();
613     assertTrue(Bytes.equals(hri.getStartKey(), new byte [] {2,2,2,2,2,2,2,2,2,2}));
614     assertTrue(Bytes.equals(hri.getEndKey(), new byte [] {3,3,3,3,3,3,3,3,3,3}));
615     hri = hris.next();
616     assertTrue(Bytes.equals(hri.getStartKey(), new byte [] {3,3,3,3,3,3,3,3,3,3}));
617     assertTrue(Bytes.equals(hri.getEndKey(), new byte [] {4,4,4,4,4,4,4,4,4,4}));
618     hri = hris.next();
619     assertTrue(Bytes.equals(hri.getStartKey(), new byte [] {4,4,4,4,4,4,4,4,4,4}));
620     assertTrue(Bytes.equals(hri.getEndKey(), new byte [] {5,5,5,5,5,5,5,5,5,5}));
621     hri = hris.next();
622     assertTrue(Bytes.equals(hri.getStartKey(), new byte [] {5,5,5,5,5,5,5,5,5,5}));
623     assertTrue(Bytes.equals(hri.getEndKey(), new byte [] {6,6,6,6,6,6,6,6,6,6}));
624     hri = hris.next();
625     assertTrue(Bytes.equals(hri.getStartKey(), new byte [] {6,6,6,6,6,6,6,6,6,6}));
626     assertTrue(Bytes.equals(hri.getEndKey(), new byte [] {7,7,7,7,7,7,7,7,7,7}));
627     hri = hris.next();
628     assertTrue(Bytes.equals(hri.getStartKey(), new byte [] {7,7,7,7,7,7,7,7,7,7}));
629     assertTrue(Bytes.equals(hri.getEndKey(), new byte [] {8,8,8,8,8,8,8,8,8,8}));
630     hri = hris.next();
631     assertTrue(Bytes.equals(hri.getStartKey(), new byte [] {8,8,8,8,8,8,8,8,8,8}));
632     assertTrue(Bytes.equals(hri.getEndKey(), new byte [] {9,9,9,9,9,9,9,9,9,9}));
633     hri = hris.next();
634     assertTrue(Bytes.equals(hri.getStartKey(), new byte [] {9,9,9,9,9,9,9,9,9,9}));
635     assertTrue(hri.getEndKey() == null || hri.getEndKey().length == 0);
636 
637     verifyRoundRobinDistribution(ht, expectedRegions);
638 
639     // Try once more with something that divides into something infinite
640 
641     startKey = new byte [] { 0, 0, 0, 0, 0, 0 };
642     endKey = new byte [] { 1, 0, 0, 0, 0, 0 };
643 
644     expectedRegions = 5;
645 
646     byte [] TABLE_3 = Bytes.add(tableName, Bytes.toBytes("_3"));
647 
648     desc = new HTableDescriptor(TABLE_3);
649     desc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY));
650     admin = new HBaseAdmin(TEST_UTIL.getConfiguration());
651     admin.createTable(desc, startKey, endKey, expectedRegions);
652 
653     ht = new HTable(TEST_UTIL.getConfiguration(), TABLE_3);
654     regions = ht.getRegionsInfo();
655     assertEquals("Tried to create " + expectedRegions + " regions " +
656         "but only found " + regions.size(),
657         expectedRegions, regions.size());
658     System.err.println("Found " + regions.size() + " regions");
659 
660     verifyRoundRobinDistribution(ht, expectedRegions);
661 
662     // Try an invalid case where there are duplicate split keys
663     splitKeys = new byte [][] {
664         new byte [] { 1, 1, 1 },
665         new byte [] { 2, 2, 2 },
666         new byte [] { 3, 3, 3 },
667         new byte [] { 2, 2, 2 }
668     };
669 
670     byte [] TABLE_4 = Bytes.add(tableName, Bytes.toBytes("_4"));
671     desc = new HTableDescriptor(TABLE_4);
672     desc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY));
673     admin = new HBaseAdmin(TEST_UTIL.getConfiguration());
674     try {
675       admin.createTable(desc, splitKeys);
676       assertTrue("Should not be able to create this table because of " +
677           "duplicate split keys", false);
678     } catch(IllegalArgumentException iae) {
679       // Expected
680     }
681   }
682 
683   @Test
684   public void testTableExist() throws IOException {
685     final byte [] table = Bytes.toBytes("testTableExist");
686     boolean exist = false;
687     exist = this.admin.tableExists(table);
688     assertEquals(false, exist);
689     TEST_UTIL.createTable(table, HConstants.CATALOG_FAMILY);
690     exist = this.admin.tableExists(table);
691     assertEquals(true, exist);
692   }
693 
694   /**
695    * Tests forcing split from client and having scanners successfully ride over split.
696    * @throws Exception
697    * @throws IOException
698    */
699   @Test
700   public void testForceSplit() throws Exception {
701     byte[][] familyNames = new byte[][] { Bytes.toBytes("cf") };
702     int[] rowCounts = new int[] { 6000 };
703     int numVersions = HColumnDescriptor.DEFAULT_VERSIONS;
704     int blockSize = 256;
705     splitTest(null, familyNames, rowCounts, numVersions, blockSize);
706 
707     byte[] splitKey = Bytes.toBytes(3500);
708     splitTest(splitKey, familyNames, rowCounts, numVersions, blockSize);
709   }
710 
711   /**
712    * Multi-family scenario. Tests forcing split from client and
713    * having scanners successfully ride over split.
714    * @throws Exception
715    * @throws IOException
716    */
717   @Test
718   public void testForceSplitMultiFamily() throws Exception {
719     int numVersions = HColumnDescriptor.DEFAULT_VERSIONS;
720 
721     // use small HFile block size so that we can have lots of blocks in HFile
722     // Otherwise, if there is only one block,
723     // HFileBlockIndex.midKey()'s value == startKey
724     int blockSize = 256;
725     byte[][] familyNames = new byte[][] { Bytes.toBytes("cf1"),
726       Bytes.toBytes("cf2") };
727 
728     // one of the column families isn't splittable
729     int[] rowCounts = new int[] { 6000, 1 };
730     splitTest(null, familyNames, rowCounts, numVersions, blockSize);
731 
732     rowCounts = new int[] { 1, 6000 };
733     splitTest(null, familyNames, rowCounts, numVersions, blockSize);
734 
735     // one column family has much smaller data than the other
736     // the split key should be based on the largest column family
737     rowCounts = new int[] { 6000, 300 };
738     splitTest(null, familyNames, rowCounts, numVersions, blockSize);
739 
740     rowCounts = new int[] { 300, 6000 };
741     splitTest(null, familyNames, rowCounts, numVersions, blockSize);
742 
743   }
744 
745   void splitTest(byte[] splitPoint, byte[][] familyNames, int[] rowCounts,
746     int numVersions, int blockSize) throws Exception {
747     byte [] tableName = Bytes.toBytes("testForceSplit");
748     assertFalse(admin.tableExists(tableName));
749     final HTable table = TEST_UTIL.createTable(tableName, familyNames,
750       numVersions, blockSize);
751     try {
752       int rowCount = 0;
753 
754       // insert rows into column families. The number of rows that have values
755       // in a specific column family is decided by rowCounts[familyIndex]
756       for (int index = 0; index < familyNames.length; index++) {
757         for (int i = 0; i < rowCounts[index]; i++) {
758           byte[] k = Bytes.toBytes(i);
759           Put put = new Put(k);
760           put.add(familyNames[index], new byte[0], k);
761           table.put(put);
762         }
763 
764         if ( rowCount < rowCounts[index] ) {
765           rowCount = rowCounts[index];
766         }
767       }
768 
769       // get the initial layout (should just be one region)
770       Map<HRegionInfo,HServerAddress> m = table.getRegionsInfo();
771       System.out.println("Initial regions (" + m.size() + "): " + m);
772       assertTrue(m.size() == 1);
773 
774       // Verify row count
775       Scan scan = new Scan();
776       ResultScanner scanner = table.getScanner(scan);
777       int rows = 0;
778       for(@SuppressWarnings("unused") Result result : scanner) {
779         rows++;
780       }
781       scanner.close();
782       assertEquals(rowCount, rows);
783 
784       // Have an outstanding scan going on to make sure we can scan over splits.
785       scan = new Scan();
786       scanner = table.getScanner(scan);
787       // Scan first row so we are into first region before split happens.
788       scanner.next();
789 
790       final AtomicInteger count = new AtomicInteger(0);
791       Thread t = new Thread("CheckForSplit") {
792         public void run() {
793           for (int i = 0; i < 20; i++) {
794             try {
795               sleep(1000);
796             } catch (InterruptedException e) {
797               continue;
798             }
799             // check again    table = new HTable(conf, tableName);
800             Map<HRegionInfo, HServerAddress> regions = null;
801             try {
802               regions = table.getRegionsInfo();
803             } catch (IOException e) {
804               e.printStackTrace();
805             }
806             if (regions == null) continue;
807             count.set(regions.size());
808             if (count.get() >= 2) break;
809             LOG.debug("Cycle waiting on split");
810           }
811         }
812       };
813       t.start();
814       // Split the table
815       this.admin.split(tableName, splitPoint);
816       t.join();
817 
818       // Verify row count
819       rows = 1; // We counted one row above.
820       for (@SuppressWarnings("unused") Result result : scanner) {
821         rows++;
822         if (rows > rowCount) {
823           scanner.close();
824           assertTrue("Scanned more than expected (" + rowCount + ")", false);
825         }
826       }
827       scanner.close();
828       assertEquals(rowCount, rows);
829 
830       Map<HRegionInfo, HServerAddress> regions = null;
831       try {
832         regions = table.getRegionsInfo();
833       } catch (IOException e) {
834         e.printStackTrace();
835       }
836       assertEquals(2, regions.size());
837       HRegionInfo[] r = regions.keySet().toArray(new HRegionInfo[0]);
838       if (splitPoint != null) {
839         // make sure the split point matches our explicit configuration
840         assertEquals(Bytes.toString(splitPoint),
841             Bytes.toString(r[0].getEndKey()));
842         assertEquals(Bytes.toString(splitPoint),
843             Bytes.toString(r[1].getStartKey()));
844         LOG.debug("Properly split on " + Bytes.toString(splitPoint));
845       } else {
846         if (familyNames.length > 1) {
847           int splitKey = Bytes.toInt(r[0].getEndKey());
848           // check if splitKey is based on the largest column family
849           // in terms of it store size
850           int deltaForLargestFamily = Math.abs(rowCount/2 - splitKey);
851           for (int index = 0; index < familyNames.length; index++) {
852             int delta = Math.abs(rowCounts[index]/2 - splitKey);
853             assertTrue(delta >= deltaForLargestFamily);
854           }
855         }
856       }
857     } finally {
858       TEST_UTIL.deleteTable(tableName);
859     }
860   }
861 
862   /**
863    * HADOOP-2156
864    * @throws IOException
865    */
866   @Test (expected=IllegalArgumentException.class)
867   public void testEmptyHHTableDescriptor() throws IOException {
868     this.admin.createTable(new HTableDescriptor());
869   }
870 
871   @Test (expected=IllegalArgumentException.class)
872   public void testInvalidHColumnDescriptor() throws IOException {
873      new HColumnDescriptor("/cfamily/name");
874   }
875 
876   @Test
877   public void testEnableDisableAddColumnDeleteColumn() throws Exception {
878     byte [] tableName = Bytes.toBytes("testMasterAdmin");
879     TEST_UTIL.createTable(tableName, HConstants.CATALOG_FAMILY);
880     this.admin.disableTable(tableName);
881     try {
882       new HTable(TEST_UTIL.getConfiguration(), tableName);
883     } catch (org.apache.hadoop.hbase.client.RegionOfflineException e) {
884       // Expected
885     }
886     this.admin.addColumn(tableName, new HColumnDescriptor("col2"));
887     this.admin.enableTable(tableName);
888     try {
889       this.admin.deleteColumn(tableName, Bytes.toBytes("col2"));
890     } catch (TableNotDisabledException e) {
891       LOG.info(e);
892     }
893     this.admin.disableTable(tableName);
894     this.admin.deleteTable(tableName);
895   }
896 
897   @Test
898   public void testCreateBadTables() throws IOException {
899     String msg = null;
900     try {
901       this.admin.createTable(HTableDescriptor.ROOT_TABLEDESC);
902     } catch (IllegalArgumentException e) {
903       msg = e.toString();
904     }
905     assertTrue("Unexcepted exception message " + msg, msg != null &&
906       msg.startsWith(IllegalArgumentException.class.getName()) &&
907       msg.contains(HTableDescriptor.ROOT_TABLEDESC.getNameAsString()));
908     msg = null;
909     try {
910       this.admin.createTable(HTableDescriptor.META_TABLEDESC);
911     } catch(IllegalArgumentException e) {
912       msg = e.toString();
913     }
914     assertTrue("Unexcepted exception message " + msg, msg != null &&
915       msg.startsWith(IllegalArgumentException.class.getName()) &&
916       msg.contains(HTableDescriptor.META_TABLEDESC.getNameAsString()));
917 
918     // Now try and do concurrent creation with a bunch of threads.
919     final HTableDescriptor threadDesc =
920       new HTableDescriptor("threaded_testCreateBadTables");
921     threadDesc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY));
922     int count = 10;
923     Thread [] threads = new Thread [count];
924     final AtomicInteger successes = new AtomicInteger(0);
925     final AtomicInteger failures = new AtomicInteger(0);
926     final HBaseAdmin localAdmin = this.admin;
927     for (int i = 0; i < count; i++) {
928       threads[i] = new Thread(Integer.toString(i)) {
929         @Override
930         public void run() {
931           try {
932             localAdmin.createTable(threadDesc);
933             successes.incrementAndGet();
934           } catch (TableExistsException e) {
935             failures.incrementAndGet();
936           } catch (IOException e) {
937             throw new RuntimeException("Failed threaded create" + getName(), e);
938           }
939         }
940       };
941     }
942     for (int i = 0; i < count; i++) {
943       threads[i].start();
944     }
945     for (int i = 0; i < count; i++) {
946       while(threads[i].isAlive()) {
947         try {
948           Thread.sleep(100);
949         } catch (InterruptedException e) {
950           // continue
951         }
952       }
953     }
954     // All threads are now dead.  Count up how many tables were created and
955     // how many failed w/ appropriate exception.
956     assertEquals(1, successes.get());
957     assertEquals(count - 1, failures.get());
958   }
959 
960   /**
961    * Test for hadoop-1581 'HBASE: Unopenable tablename bug'.
962    * @throws Exception
963    */
964   @Test
965   public void testTableNameClash() throws Exception {
966     String name = "testTableNameClash";
967     admin.createTable(new HTableDescriptor(name + "SOMEUPPERCASE"));
968     admin.createTable(new HTableDescriptor(name));
969     // Before fix, below would fail throwing a NoServerForRegionException.
970     new HTable(TEST_UTIL.getConfiguration(), name);
971   }
972 
973   /***
974    * HMaster.createTable used to be kind of synchronous call
975    * Thus creating of table with lots of regions can cause RPC timeout
976    * After the fix to make createTable truly async, RPC timeout shouldn't be an
977    * issue anymore
978    * @throws Exception
979    */
980   @Test
981   public void testCreateTableRPCTimeOut() throws Exception {
982     String name = "testCreateTableRPCTimeOut";
983     TEST_UTIL.getConfiguration().setInt(HConstants.HBASE_RPC_TIMEOUT_KEY, 1500);
984 
985     int expectedRegions = 100;
986     // Use 80 bit numbers to make sure we aren't limited
987     byte [] startKey = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
988     byte [] endKey =   { 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 };
989     HBaseAdmin hbaseadmin = new HBaseAdmin(TEST_UTIL.getConfiguration());
990     hbaseadmin.createTable(new HTableDescriptor(name), startKey, endKey,
991       expectedRegions);
992   }
993 
994   /**
995    * Test read only tables
996    * @throws Exception
997    */
998   @Test
999   public void testReadOnlyTable() throws Exception {
1000     byte [] name = Bytes.toBytes("testReadOnlyTable");
1001     HTable table = TEST_UTIL.createTable(name, HConstants.CATALOG_FAMILY);
1002     byte[] value = Bytes.toBytes("somedata");
1003     // This used to use an empty row... That must have been a bug
1004     Put put = new Put(value);
1005     put.add(HConstants.CATALOG_FAMILY, HConstants.CATALOG_FAMILY, value);
1006     table.put(put);
1007   }
1008 
1009   /**
1010    * Test that user table names can contain '-' and '.' so long as they do not
1011    * start with same. HBASE-771
1012    * @throws IOException
1013    */
1014   @Test
1015   public void testTableNames() throws IOException {
1016     byte[][] illegalNames = new byte[][] {
1017         Bytes.toBytes("-bad"),
1018         Bytes.toBytes(".bad"),
1019         HConstants.ROOT_TABLE_NAME,
1020         HConstants.META_TABLE_NAME
1021     };
1022     for (int i = 0; i < illegalNames.length; i++) {
1023       try {
1024         new HTableDescriptor(illegalNames[i]);
1025         throw new IOException("Did not detect '" +
1026           Bytes.toString(illegalNames[i]) + "' as an illegal user table name");
1027       } catch (IllegalArgumentException e) {
1028         // expected
1029       }
1030     }
1031     byte[] legalName = Bytes.toBytes("g-oo.d");
1032     try {
1033       new HTableDescriptor(legalName);
1034     } catch (IllegalArgumentException e) {
1035       throw new IOException("Legal user table name: '" +
1036         Bytes.toString(legalName) + "' caused IllegalArgumentException: " +
1037         e.getMessage());
1038     }
1039   }
1040 
1041   /**
1042    * For HADOOP-2579
1043    * @throws IOException
1044    */
1045   @Test (expected=TableExistsException.class)
1046   public void testTableExistsExceptionWithATable() throws IOException {
1047     final byte [] name = Bytes.toBytes("testTableExistsExceptionWithATable");
1048     TEST_UTIL.createTable(name, HConstants.CATALOG_FAMILY);
1049     TEST_UTIL.createTable(name, HConstants.CATALOG_FAMILY);
1050   }
1051 
1052   /**
1053    * Can't disable a table if the table isn't in enabled state
1054    * @throws IOException
1055    */
1056   @Test (expected=TableNotEnabledException.class)
1057   public void testTableNotEnabledExceptionWithATable() throws IOException {
1058     final byte [] name = Bytes.toBytes(
1059       "testTableNotEnabledExceptionWithATable");
1060     TEST_UTIL.createTable(name, HConstants.CATALOG_FAMILY);
1061     this.admin.disableTable(name);
1062     this.admin.disableTable(name);
1063   }
1064 
1065   /**
1066    * Can't enable a table if the table isn't in disabled state
1067    * @throws IOException
1068    */
1069   @Test (expected=TableNotDisabledException.class)
1070   public void testTableNotDisabledExceptionWithATable() throws IOException {
1071     final byte [] name = Bytes.toBytes(
1072       "testTableNotDisabledExceptionWithATable");
1073     TEST_UTIL.createTable(name, HConstants.CATALOG_FAMILY);
1074     this.admin.enableTable(name);
1075   }
1076 
1077   /**
1078    * For HADOOP-2579
1079    * @throws IOException
1080    */
1081   @Test (expected=TableNotFoundException.class)
1082   public void testTableNotFoundExceptionWithoutAnyTables() throws IOException {
1083     new HTable(TEST_UTIL.getConfiguration(),
1084         "testTableNotFoundExceptionWithoutAnyTables");
1085   }
1086   @Test
1087   public void testShouldCloseTheRegionBasedOnTheEncodedRegionName()
1088       throws Exception {
1089     byte[] TABLENAME = Bytes.toBytes("TestHBACloseRegion");
1090     HBaseAdmin admin = createTable(TABLENAME);
1091 
1092     HRegionInfo info = null;
1093     HRegionServer rs = TEST_UTIL.getRSForFirstRegionInTable(TABLENAME);
1094     List<HRegionInfo> onlineRegions = rs.getOnlineRegions();
1095     for (HRegionInfo regionInfo : onlineRegions) {
1096       if (!regionInfo.isMetaTable()) {
1097         info = regionInfo;
1098         admin.closeRegionWithEncodedRegionName(regionInfo.getEncodedName(), rs
1099             .getServerName().getServerName());
1100       }
1101     }
1102     Thread.sleep(1000);
1103     onlineRegions = rs.getOnlineRegions();
1104     assertFalse("The region should not be present in online regions list.",
1105         onlineRegions.contains(info));
1106   }
1107 
1108   @Test
1109   public void testCloseRegionIfInvalidRegionNameIsPassed() throws Exception {
1110     byte[] TABLENAME = Bytes.toBytes("TestHBACloseRegion1");
1111     HBaseAdmin admin = createTable(TABLENAME);
1112 
1113     HRegionInfo info = null;
1114     HRegionServer rs = TEST_UTIL.getRSForFirstRegionInTable(TABLENAME);
1115     List<HRegionInfo> onlineRegions = rs.getOnlineRegions();
1116     for (HRegionInfo regionInfo : onlineRegions) {
1117       if (!regionInfo.isMetaTable()) {
1118         if (regionInfo.getRegionNameAsString().contains("TestHBACloseRegion1")) {
1119           info = regionInfo;
1120           admin.closeRegionWithEncodedRegionName("sample", rs.getServerName()
1121               .getServerName());
1122         }
1123       }
1124     }
1125     onlineRegions = rs.getOnlineRegions();
1126     assertTrue("The region should be present in online regions list.",
1127         onlineRegions.contains(info));
1128   }
1129 
1130   @Test
1131   public void testCloseRegionThatFetchesTheHRIFromMeta() throws Exception {
1132     byte[] TABLENAME = Bytes.toBytes("TestHBACloseRegion2");
1133     HBaseAdmin admin = createTable(TABLENAME);
1134 
1135     HRegionInfo info = null;
1136     HRegionServer rs = TEST_UTIL.getRSForFirstRegionInTable(TABLENAME);
1137     List<HRegionInfo> onlineRegions = rs.getOnlineRegions();
1138     for (HRegionInfo regionInfo : onlineRegions) {
1139       if (!regionInfo.isMetaTable()) {
1140 
1141         if (regionInfo.getRegionNameAsString().contains("TestHBACloseRegion2")) {
1142           info = regionInfo;
1143           admin.closeRegion(regionInfo.getRegionNameAsString(), rs
1144               .getServerName().getServerName());
1145         }
1146       }
1147     }
1148 
1149     boolean isInList = rs.getOnlineRegions().contains(info);
1150     long timeout = System.currentTimeMillis() + 2000;
1151     while ((System.currentTimeMillis() < timeout) && (isInList)) {
1152       Thread.sleep(100);
1153       isInList = rs.getOnlineRegions().contains(info);
1154     }
1155 
1156     assertFalse("The region should not be present in online regions list.",
1157       isInList);
1158   }
1159 
1160   @Test
1161   public void testCloseRegionWhenServerNameIsNull() throws Exception {
1162     byte[] TABLENAME = Bytes.toBytes("TestHBACloseRegion3");
1163     HBaseAdmin admin = createTable(TABLENAME);
1164 
1165     HRegionServer rs = TEST_UTIL.getRSForFirstRegionInTable(TABLENAME);
1166 
1167     try {
1168       List<HRegionInfo> onlineRegions = rs.getOnlineRegions();
1169       for (HRegionInfo regionInfo : onlineRegions) {
1170         if (!regionInfo.isMetaTable()) {
1171           if (regionInfo.getRegionNameAsString()
1172               .contains("TestHBACloseRegion3")) {
1173             admin.closeRegionWithEncodedRegionName(regionInfo.getEncodedName(),
1174                 null);
1175           }
1176         }
1177       }
1178       fail("The test should throw exception if the servername passed is null.");
1179     } catch (IllegalArgumentException e) {
1180     }
1181   }
1182   
1183 
1184   @Test
1185   public void testCloseRegionWhenServerNameIsEmpty() throws Exception {
1186     byte[] TABLENAME = Bytes.toBytes("TestHBACloseRegionWhenServerNameIsEmpty");
1187     HBaseAdmin admin = createTable(TABLENAME);
1188 
1189     HRegionServer rs = TEST_UTIL.getRSForFirstRegionInTable(TABLENAME);
1190 
1191     try {
1192       List<HRegionInfo> onlineRegions = rs.getOnlineRegions();
1193       for (HRegionInfo regionInfo : onlineRegions) {
1194         if (!regionInfo.isMetaTable()) {
1195           if (regionInfo.getRegionNameAsString()
1196               .contains("TestHBACloseRegionWhenServerNameIsEmpty")) {
1197             admin.closeRegionWithEncodedRegionName(regionInfo.getEncodedName(),
1198                 " ");
1199           }
1200         }
1201       }
1202       fail("The test should throw exception if the servername passed is empty.");
1203     } catch (IllegalArgumentException e) {
1204     }
1205   }
1206 
1207   @Test
1208   public void testCloseRegionWhenEncodedRegionNameIsNotGiven() throws Exception {
1209     byte[] TABLENAME = Bytes.toBytes("TestHBACloseRegion4");
1210     HBaseAdmin admin = createTable(TABLENAME);
1211 
1212     HRegionInfo info = null;
1213     HRegionServer rs = TEST_UTIL.getRSForFirstRegionInTable(TABLENAME);
1214 
1215     List<HRegionInfo> onlineRegions = rs.getOnlineRegions();
1216     for (HRegionInfo regionInfo : onlineRegions) {
1217       if (!regionInfo.isMetaTable()) {
1218         if (regionInfo.getRegionNameAsString().contains("TestHBACloseRegion4")) {
1219           info = regionInfo;
1220           admin.closeRegionWithEncodedRegionName(regionInfo
1221               .getRegionNameAsString(), rs.getServerName().getServerName());
1222         }
1223       }
1224     }
1225     onlineRegions = rs.getOnlineRegions();
1226     assertTrue("The region should be present in online regions list.",
1227         onlineRegions.contains(info));
1228   }
1229 
1230   private HBaseAdmin createTable(byte[] TABLENAME) throws IOException {
1231 
1232     Configuration config = TEST_UTIL.getConfiguration();
1233     HBaseAdmin admin = new HBaseAdmin(config);
1234 
1235     HTableDescriptor htd = new HTableDescriptor(TABLENAME);
1236     HColumnDescriptor hcd = new HColumnDescriptor("value");
1237 
1238     htd.addFamily(hcd);
1239     admin.createTable(htd, null);
1240     return admin;
1241   }
1242 
1243 
1244   @Test
1245   public void testHundredsOfTable() throws IOException{
1246     final int times = 100;
1247     HColumnDescriptor fam1 = new HColumnDescriptor("fam1");
1248     HColumnDescriptor fam2 = new HColumnDescriptor("fam2");
1249     HColumnDescriptor fam3 = new HColumnDescriptor("fam3");
1250 
1251     for(int i = 0; i < times; i++) {
1252       HTableDescriptor htd = new HTableDescriptor("table"+i);
1253       htd.addFamily(fam1);
1254       htd.addFamily(fam2);
1255       htd.addFamily(fam3);
1256       this.admin.createTable(htd);
1257     }
1258 
1259     for(int i = 0; i < times; i++) {
1260       String tableName = "table"+i;
1261       this.admin.disableTable(tableName);
1262       byte [] tableNameBytes = Bytes.toBytes(tableName);
1263       assertTrue(this.admin.isTableDisabled(tableNameBytes));
1264       this.admin.enableTable(tableName);
1265       assertFalse(this.admin.isTableDisabled(tableNameBytes));
1266       this.admin.disableTable(tableName);
1267       assertTrue(this.admin.isTableDisabled(tableNameBytes));
1268       this.admin.deleteTable(tableName);
1269     }
1270   }
1271   
1272 
1273   /**
1274    * For HBASE-2556
1275    * @throws IOException
1276    */  
1277   @Test
1278   public void testGetTableRegions() throws IOException {
1279 
1280     byte[] tableName = Bytes.toBytes("testGetTableRegions");
1281 
1282     int expectedRegions = 10;
1283 
1284     // Use 80 bit numbers to make sure we aren't limited
1285     byte [] startKey = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
1286     byte [] endKey =   { 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 };
1287 
1288 
1289     HTableDescriptor desc = new HTableDescriptor(tableName);
1290     desc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY));
1291     admin = new HBaseAdmin(TEST_UTIL.getConfiguration());
1292     admin.createTable(desc, startKey, endKey, expectedRegions);
1293 
1294     List<HRegionInfo> RegionInfos = admin.getTableRegions(tableName);
1295     
1296     assertEquals("Tried to create " + expectedRegions + " regions " +
1297         "but only found " + RegionInfos.size(),
1298         expectedRegions, RegionInfos.size());
1299     
1300  }
1301 
1302   @Test
1303   public void testHLogRollWriting() throws Exception {
1304     setUpforLogRolling();
1305     String className = this.getClass().getName();
1306     StringBuilder v = new StringBuilder(className);
1307     while (v.length() < 1000) {
1308       v.append(className);
1309     }
1310     byte[] value = Bytes.toBytes(v.toString());
1311     HRegionServer regionServer = startAndWriteData("TestLogRolling", value);
1312     LOG.info("after writing there are "
1313         + TestHLogUtils.getNumLogFiles(regionServer.getWAL()) + " log files");
1314 
1315     // flush all regions
1316 
1317     List<HRegion> regions = new ArrayList<HRegion>(regionServer
1318         .getOnlineRegionsLocalContext());
1319     for (HRegion r : regions) {
1320       r.flushcache();
1321     }
1322     admin.rollHLogWriter(regionServer.getServerName().getServerName());
1323     int count = TestHLogUtils.getNumLogFiles(regionServer.getWAL());
1324     LOG.info("after flushing all regions and rolling logs there are " +
1325         count + " log files");
1326     assertTrue(("actual count: " + count), count <= 2);
1327   }
1328 
1329   private void setUpforLogRolling() {
1330     // Force a region split after every 768KB
1331     TEST_UTIL.getConfiguration().setLong("hbase.hregion.max.filesize",
1332         768L * 1024L);
1333 
1334     // We roll the log after every 32 writes
1335     TEST_UTIL.getConfiguration().setInt("hbase.regionserver.maxlogentries", 32);
1336 
1337     TEST_UTIL.getConfiguration().setInt(
1338         "hbase.regionserver.logroll.errors.tolerated", 2);
1339     TEST_UTIL.getConfiguration().setInt("ipc.ping.interval", 10 * 1000);
1340     TEST_UTIL.getConfiguration().setInt("ipc.socket.timeout", 10 * 1000);
1341     TEST_UTIL.getConfiguration().setInt("hbase.rpc.timeout", 10 * 1000);
1342 
1343     // For less frequently updated regions flush after every 2 flushes
1344     TEST_UTIL.getConfiguration().setInt(
1345         "hbase.hregion.memstore.optionalflushcount", 2);
1346 
1347     // We flush the cache after every 8192 bytes
1348     TEST_UTIL.getConfiguration().setInt("hbase.hregion.memstore.flush.size",
1349         8192);
1350 
1351     // Increase the amount of time between client retries
1352     TEST_UTIL.getConfiguration().setLong("hbase.client.pause", 10 * 1000);
1353 
1354     // Reduce thread wake frequency so that other threads can get
1355     // a chance to run.
1356     TEST_UTIL.getConfiguration().setInt(HConstants.THREAD_WAKE_FREQUENCY,
1357         2 * 1000);
1358 
1359     /**** configuration for testLogRollOnDatanodeDeath ****/
1360     // make sure log.hflush() calls syncFs() to open a pipeline
1361     TEST_UTIL.getConfiguration().setBoolean("dfs.support.append", true);
1362     // lower the namenode & datanode heartbeat so the namenode
1363     // quickly detects datanode failures
1364     TEST_UTIL.getConfiguration().setInt("heartbeat.recheck.interval", 5000);
1365     TEST_UTIL.getConfiguration().setInt("dfs.heartbeat.interval", 1);
1366     // the namenode might still try to choose the recently-dead datanode
1367     // for a pipeline, so try to a new pipeline multiple times
1368     TEST_UTIL.getConfiguration().setInt("dfs.client.block.write.retries", 30);
1369     TEST_UTIL.getConfiguration().setInt(
1370         "hbase.regionserver.hlog.tolerable.lowreplication", 2);
1371     TEST_UTIL.getConfiguration().setInt(
1372         "hbase.regionserver.hlog.lowreplication.rolllimit", 3);
1373   }
1374   
1375   private HRegionServer startAndWriteData(String tableName, byte[] value)
1376       throws IOException {
1377     // When the META table can be opened, the region servers are running
1378     new HTable(TEST_UTIL.getConfiguration(), HConstants.META_TABLE_NAME);
1379     HRegionServer regionServer = TEST_UTIL.getHBaseCluster()
1380         .getRegionServerThreads().get(0).getRegionServer();
1381 
1382     // Create the test table and open it
1383     HTableDescriptor desc = new HTableDescriptor(tableName);
1384     desc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY));
1385     admin.createTable(desc);
1386     HTable table = new HTable(TEST_UTIL.getConfiguration(), tableName);
1387 
1388     regionServer = TEST_UTIL.getRSForFirstRegionInTable(Bytes
1389         .toBytes(tableName));
1390     for (int i = 1; i <= 256; i++) { // 256 writes should cause 8 log rolls
1391       Put put = new Put(Bytes.toBytes("row" + String.format("%1$04d", i)));
1392       put.add(HConstants.CATALOG_FAMILY, null, value);
1393       table.put(put);
1394       if (i % 32 == 0) {
1395         // After every 32 writes sleep to let the log roller run
1396         try {
1397           Thread.sleep(2000);
1398         } catch (InterruptedException e) {
1399           // continue
1400         }
1401       }
1402     }
1403     return regionServer;
1404   }
1405   
1406   /**
1407    * HBASE-4417 checkHBaseAvailable() doesn't close zk connections
1408    */
1409   @Test
1410   public void testCheckHBaseAvailableClosesConnection() throws Exception {
1411     Configuration conf = TEST_UTIL.getConfiguration();
1412     for(int i=0; i<1000;i++) {
1413       HBaseAdmin.checkHBaseAvailable(conf);
1414     }
1415   }
1416   
1417 }