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