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