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