1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.client;
20
21
22 import static org.junit.Assert.assertEquals;
23 import static org.junit.Assert.assertFalse;
24 import static org.junit.Assert.assertTrue;
25 import static org.junit.Assert.fail;
26
27 import java.io.IOException;
28 import java.util.ArrayList;
29 import java.util.HashMap;
30 import java.util.Iterator;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.Set;
34 import java.util.concurrent.atomic.AtomicBoolean;
35 import java.util.concurrent.atomic.AtomicInteger;
36 import java.util.concurrent.atomic.AtomicReference;
37
38 import org.apache.commons.logging.Log;
39 import org.apache.commons.logging.LogFactory;
40 import org.apache.hadoop.hbase.HBaseTestingUtility;
41 import org.apache.hadoop.hbase.HColumnDescriptor;
42 import org.apache.hadoop.hbase.HConstants;
43 import org.apache.hadoop.hbase.HRegionInfo;
44 import org.apache.hadoop.hbase.HTableDescriptor;
45 import org.apache.hadoop.hbase.InvalidFamilyOperationException;
46 import org.apache.hadoop.hbase.testclassification.LargeTests;
47 import org.apache.hadoop.hbase.ServerName;
48 import org.apache.hadoop.hbase.TableName;
49 import org.apache.hadoop.hbase.TableNotDisabledException;
50 import org.apache.hadoop.hbase.TableNotFoundException;
51 import org.apache.hadoop.hbase.ZooKeeperConnectionException;
52 import org.apache.hadoop.hbase.catalog.CatalogTracker;
53 import org.apache.hadoop.hbase.executor.EventHandler;
54 import org.apache.hadoop.hbase.util.Bytes;
55 import org.apache.hadoop.hbase.zookeeper.ZKTableReadOnly;
56 import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
57 import org.apache.zookeeper.KeeperException;
58 import org.junit.After;
59 import org.junit.AfterClass;
60 import org.junit.Before;
61 import org.junit.BeforeClass;
62 import org.junit.Test;
63 import org.junit.experimental.categories.Category;
64
65
66
67
68
69
70 @Category(LargeTests.class)
71 public class TestAdmin1 {
72 final Log LOG = LogFactory.getLog(getClass());
73 private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
74 private HBaseAdmin admin;
75
76 @BeforeClass
77 public static void setUpBeforeClass() throws Exception {
78 TEST_UTIL.getConfiguration().setBoolean("hbase.online.schema.update.enable", true);
79 TEST_UTIL.getConfiguration().setInt("hbase.regionserver.msginterval", 100);
80 TEST_UTIL.getConfiguration().setInt("hbase.client.pause", 250);
81 TEST_UTIL.getConfiguration().setInt("hbase.client.retries.number", 6);
82 TEST_UTIL.getConfiguration().setBoolean(
83 "hbase.master.enabletable.roundrobin", true);
84 TEST_UTIL.startMiniCluster(3);
85 }
86
87 @AfterClass
88 public static void tearDownAfterClass() throws Exception {
89 TEST_UTIL.shutdownMiniCluster();
90 }
91
92 @Before
93 public void setUp() throws Exception {
94 this.admin = TEST_UTIL.getHBaseAdmin();
95 }
96
97 @After
98 public void tearDown() throws Exception {
99 for (HTableDescriptor htd : this.admin.listTables()) {
100 TEST_UTIL.deleteTable(htd.getName());
101 }
102 }
103
104 @Test (timeout=300000)
105 public void testFailedCatalogTrackerGetCleansUpProperly()
106 throws ZooKeeperConnectionException, IOException {
107
108 final AtomicBoolean fail = new AtomicBoolean(false);
109 final AtomicReference<CatalogTracker> internalCt = new AtomicReference<CatalogTracker>();
110 HBaseAdmin doctoredAdmin = new HBaseAdmin(this.admin.getConfiguration()) {
111 @Override
112 protected CatalogTracker startCatalogTracker(CatalogTracker ct)
113 throws IOException, InterruptedException {
114 internalCt.set(ct);
115 super.startCatalogTracker(ct);
116 if (fail.get()) {
117 throw new IOException("Intentional test fail",
118 new KeeperException.ConnectionLossException());
119 }
120 return ct;
121 }
122 };
123 try {
124 CatalogTracker ct = doctoredAdmin.getCatalogTracker();
125 assertFalse(ct.isStopped());
126 doctoredAdmin.cleanupCatalogTracker(ct);
127 assertTrue(ct.isStopped());
128
129 fail.set(true);
130 boolean expectedException = false;
131 try {
132 doctoredAdmin.getCatalogTracker();
133 } catch (IOException ioe) {
134 assertTrue(ioe.getCause() instanceof KeeperException.ConnectionLossException);
135 expectedException = true;
136 }
137 if (!expectedException) fail("Didn't get expected exception!");
138
139 assertTrue("Internal CatalogTracker not closed down", internalCt.get().isStopped());
140 } finally {
141 doctoredAdmin.close();
142 }
143 }
144
145 @Test (timeout=300000)
146 public void testSplitFlushCompactUnknownTable() throws InterruptedException {
147 final String unknowntable = "fubar";
148 Exception exception = null;
149 try {
150 this.admin.compact(unknowntable);
151 } catch (IOException e) {
152 exception = e;
153 }
154 assertTrue(exception instanceof TableNotFoundException);
155
156 exception = null;
157 try {
158 this.admin.flush(unknowntable);
159 } catch (IOException e) {
160 exception = e;
161 }
162 assertTrue(exception instanceof TableNotFoundException);
163
164 exception = null;
165 try {
166 this.admin.split(unknowntable);
167 } catch (IOException e) {
168 exception = e;
169 }
170 assertTrue(exception instanceof TableNotFoundException);
171 }
172
173 @Test (timeout=300000)
174 public void testDeleteEditUnknownColumnFamilyAndOrTable() throws IOException {
175
176 final String nonexistent = "nonexistent";
177 HColumnDescriptor nonexistentHcd = new HColumnDescriptor(nonexistent);
178 Exception exception = null;
179 try {
180 this.admin.addColumn(nonexistent, nonexistentHcd);
181 } catch (IOException e) {
182 exception = e;
183 }
184 assertTrue(exception instanceof TableNotFoundException);
185
186 exception = null;
187 try {
188 this.admin.deleteTable(nonexistent);
189 } catch (IOException e) {
190 exception = e;
191 }
192 assertTrue(exception instanceof TableNotFoundException);
193
194 exception = null;
195 try {
196 this.admin.deleteColumn(nonexistent, nonexistent);
197 } catch (IOException e) {
198 exception = e;
199 }
200 assertTrue(exception instanceof TableNotFoundException);
201
202 exception = null;
203 try {
204 this.admin.disableTable(nonexistent);
205 } catch (IOException e) {
206 exception = e;
207 }
208 assertTrue(exception instanceof TableNotFoundException);
209
210 exception = null;
211 try {
212 this.admin.enableTable(nonexistent);
213 } catch (IOException e) {
214 exception = e;
215 }
216 assertTrue(exception instanceof TableNotFoundException);
217
218 exception = null;
219 try {
220 this.admin.modifyColumn(nonexistent, nonexistentHcd);
221 } catch (IOException e) {
222 exception = e;
223 }
224 assertTrue(exception instanceof TableNotFoundException);
225
226 exception = null;
227 try {
228 HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(nonexistent));
229 this.admin.modifyTable(htd.getTableName(), htd);
230 } catch (IOException e) {
231 exception = e;
232 }
233 assertTrue(exception instanceof TableNotFoundException);
234
235
236
237 final String tableName =
238 "testDeleteEditUnknownColumnFamilyAndOrTable" + System.currentTimeMillis();
239 HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(tableName));
240 htd.addFamily(new HColumnDescriptor("cf"));
241 this.admin.createTable(htd);
242 try {
243 exception = null;
244 try {
245 this.admin.deleteColumn(htd.getTableName(), nonexistentHcd.getName());
246 } catch (IOException e) {
247 exception = e;
248 }
249 assertTrue("found=" + exception.getClass().getName(),
250 exception instanceof InvalidFamilyOperationException);
251
252 exception = null;
253 try {
254 this.admin.modifyColumn(htd.getTableName(), nonexistentHcd);
255 } catch (IOException e) {
256 exception = e;
257 }
258 assertTrue("found=" + exception.getClass().getName(),
259 exception instanceof InvalidFamilyOperationException);
260 } finally {
261 this.admin.disableTable(tableName);
262 this.admin.deleteTable(tableName);
263 }
264 }
265
266 @Test (timeout=300000)
267 public void testDisableAndEnableTable() throws IOException {
268 final byte [] row = Bytes.toBytes("row");
269 final byte [] qualifier = Bytes.toBytes("qualifier");
270 final byte [] value = Bytes.toBytes("value");
271 final byte [] table = Bytes.toBytes("testDisableAndEnableTable");
272 HTable ht = TEST_UTIL.createTable(table, HConstants.CATALOG_FAMILY);
273 Put put = new Put(row);
274 put.add(HConstants.CATALOG_FAMILY, qualifier, value);
275 ht.put(put);
276 Get get = new Get(row);
277 get.addColumn(HConstants.CATALOG_FAMILY, qualifier);
278 ht.get(get);
279
280 this.admin.disableTable(ht.getName());
281 assertTrue("Table must be disabled.", TEST_UTIL.getHBaseCluster()
282 .getMaster().getAssignmentManager().getZKTable().isDisabledTable(
283 ht.getName()));
284
285
286 get = new Get(row);
287 get.addColumn(HConstants.CATALOG_FAMILY, qualifier);
288 boolean ok = false;
289 try {
290 ht.get(get);
291 } catch (org.apache.hadoop.hbase.DoNotRetryIOException e) {
292 ok = true;
293 }
294 assertTrue(ok);
295 this.admin.enableTable(table);
296 assertTrue("Table must be enabled.", TEST_UTIL.getHBaseCluster()
297 .getMaster().getAssignmentManager().getZKTable().isEnabledTable(
298 ht.getName()));
299
300
301 try {
302 ht.get(get);
303 } catch (RetriesExhaustedException e) {
304 ok = false;
305 }
306 assertTrue(ok);
307 ht.close();
308 }
309
310 @Test (timeout=300000)
311 public void testDisableAndEnableTables() throws IOException {
312 final byte [] row = Bytes.toBytes("row");
313 final byte [] qualifier = Bytes.toBytes("qualifier");
314 final byte [] value = Bytes.toBytes("value");
315 final byte [] table1 = Bytes.toBytes("testDisableAndEnableTable1");
316 final byte [] table2 = Bytes.toBytes("testDisableAndEnableTable2");
317 HTable ht1 = TEST_UTIL.createTable(table1, HConstants.CATALOG_FAMILY);
318 HTable ht2 = TEST_UTIL.createTable(table2, HConstants.CATALOG_FAMILY);
319 Put put = new Put(row);
320 put.add(HConstants.CATALOG_FAMILY, qualifier, value);
321 ht1.put(put);
322 ht2.put(put);
323 Get get = new Get(row);
324 get.addColumn(HConstants.CATALOG_FAMILY, qualifier);
325 ht1.get(get);
326 ht2.get(get);
327
328 this.admin.disableTables("testDisableAndEnableTable.*");
329
330
331 get = new Get(row);
332 get.addColumn(HConstants.CATALOG_FAMILY, qualifier);
333 boolean ok = false;
334 try {
335 ht1.get(get);
336 ht2.get(get);
337 } catch (org.apache.hadoop.hbase.DoNotRetryIOException e) {
338 ok = true;
339 }
340
341 assertTrue(ok);
342 this.admin.enableTables("testDisableAndEnableTable.*");
343
344
345 try {
346 ht1.get(get);
347 } catch (IOException e) {
348 ok = false;
349 }
350 try {
351 ht2.get(get);
352 } catch (IOException e) {
353 ok = false;
354 }
355 assertTrue(ok);
356
357 ht1.close();
358 ht2.close();
359 }
360
361 @Test (timeout=300000)
362 public void testCreateTable() throws IOException {
363 HTableDescriptor [] tables = admin.listTables();
364 int numTables = tables.length;
365 TEST_UTIL.createTable(Bytes.toBytes("testCreateTable"),
366 HConstants.CATALOG_FAMILY).close();
367 tables = this.admin.listTables();
368 assertEquals(numTables + 1, tables.length);
369 assertTrue("Table must be enabled.", TEST_UTIL.getHBaseCluster()
370 .getMaster().getAssignmentManager().getZKTable().isEnabledTable(
371 TableName.valueOf("testCreateTable")));
372 }
373
374 @Test (timeout=300000)
375 public void testTruncateTable() throws IOException {
376 testTruncateTable(TableName.valueOf("testTruncateTable"), false);
377 }
378
379 @Test (timeout=300000)
380 public void testTruncateTablePreservingSplits() throws IOException {
381 testTruncateTable(TableName.valueOf("testTruncateTablePreservingSplits"), true);
382 }
383
384 private void testTruncateTable(final TableName tableName, boolean preserveSplits)
385 throws IOException {
386 byte[][] splitKeys = new byte[2][];
387 splitKeys[0] = Bytes.toBytes(4);
388 splitKeys[1] = Bytes.toBytes(8);
389
390
391 HTable table = TEST_UTIL.createTable(tableName, HConstants.CATALOG_FAMILY, splitKeys);
392 try {
393 TEST_UTIL.loadNumericRows(table, HConstants.CATALOG_FAMILY, 0, 10);
394 assertEquals(10, TEST_UTIL.countRows(table));
395 } finally {
396 table.close();
397 }
398 assertEquals(3, TEST_UTIL.getHBaseCluster().getRegions(tableName).size());
399
400
401 this.admin.disableTable(tableName);
402 this.admin.truncateTable(tableName, preserveSplits);
403 table = new HTable(TEST_UTIL.getConfiguration(), tableName);
404 try {
405 assertEquals(0, TEST_UTIL.countRows(table));
406 } finally {
407 table.close();
408 }
409 if (preserveSplits) {
410 assertEquals(3, TEST_UTIL.getHBaseCluster().getRegions(tableName).size());
411 } else {
412 assertEquals(1, TEST_UTIL.getHBaseCluster().getRegions(tableName).size());
413 }
414 }
415
416 @Test (timeout=300000)
417 public void testGetTableDescriptor() throws IOException {
418 HColumnDescriptor fam1 = new HColumnDescriptor("fam1");
419 HColumnDescriptor fam2 = new HColumnDescriptor("fam2");
420 HColumnDescriptor fam3 = new HColumnDescriptor("fam3");
421 HTableDescriptor htd = new HTableDescriptor(TableName.valueOf("myTestTable"));
422 htd.addFamily(fam1);
423 htd.addFamily(fam2);
424 htd.addFamily(fam3);
425 this.admin.createTable(htd);
426 HTable table = new HTable(TEST_UTIL.getConfiguration(), "myTestTable");
427 HTableDescriptor confirmedHtd = table.getTableDescriptor();
428 assertEquals(htd.compareTo(confirmedHtd), 0);
429 table.close();
430 }
431
432 @Test (timeout=300000)
433 public void testHColumnValidName() {
434 boolean exceptionThrown;
435 try {
436 new HColumnDescriptor("\\test\\abc");
437 } catch(IllegalArgumentException iae) {
438 exceptionThrown = true;
439 assertTrue(exceptionThrown);
440 }
441 }
442
443
444
445
446
447
448 @Test (timeout=300000)
449 public void testOnlineChangeTableSchema() throws IOException, InterruptedException {
450 final TableName tableName =
451 TableName.valueOf("changeTableSchemaOnline");
452 TEST_UTIL.getMiniHBaseCluster().getMaster().getConfiguration().setBoolean(
453 "hbase.online.schema.update.enable", true);
454 HTableDescriptor [] tables = admin.listTables();
455 int numTables = tables.length;
456 TEST_UTIL.createTable(tableName, HConstants.CATALOG_FAMILY).close();
457 tables = this.admin.listTables();
458 assertEquals(numTables + 1, tables.length);
459
460
461 HTableDescriptor htd = this.admin.getTableDescriptor(tableName);
462
463 HTableDescriptor copy = new HTableDescriptor(htd);
464 assertTrue(htd.equals(copy));
465
466 long newFlushSize = htd.getMemStoreFlushSize() / 2;
467 if (newFlushSize <=0) {
468 newFlushSize = HTableDescriptor.DEFAULT_MEMSTORE_FLUSH_SIZE / 2;
469 }
470 copy.setMemStoreFlushSize(newFlushSize);
471 final String key = "anyoldkey";
472 assertTrue(htd.getValue(key) == null);
473 copy.setValue(key, key);
474 boolean expectedException = false;
475 try {
476 admin.modifyTable(tableName, copy);
477 } catch (TableNotDisabledException re) {
478 expectedException = true;
479 }
480 assertFalse(expectedException);
481 HTableDescriptor modifiedHtd = this.admin.getTableDescriptor(tableName);
482 assertFalse(htd.equals(modifiedHtd));
483 assertTrue(copy.equals(modifiedHtd));
484 assertEquals(newFlushSize, modifiedHtd.getMemStoreFlushSize());
485 assertEquals(key, modifiedHtd.getValue(key));
486
487
488 int countOfFamilies = modifiedHtd.getFamilies().size();
489 assertTrue(countOfFamilies > 0);
490 HColumnDescriptor hcd = modifiedHtd.getFamilies().iterator().next();
491 int maxversions = hcd.getMaxVersions();
492 final int newMaxVersions = maxversions + 1;
493 hcd.setMaxVersions(newMaxVersions);
494 final byte [] hcdName = hcd.getName();
495 expectedException = false;
496 try {
497 this.admin.modifyColumn(tableName, hcd);
498 } catch (TableNotDisabledException re) {
499 expectedException = true;
500 }
501 assertFalse(expectedException);
502 modifiedHtd = this.admin.getTableDescriptor(tableName);
503 HColumnDescriptor modifiedHcd = modifiedHtd.getFamily(hcdName);
504 assertEquals(newMaxVersions, modifiedHcd.getMaxVersions());
505
506
507 assertFalse(this.admin.isTableDisabled(tableName));
508 final String xtracolName = "xtracol";
509 HColumnDescriptor xtracol = new HColumnDescriptor(xtracolName);
510 xtracol.setValue(xtracolName, xtracolName);
511 expectedException = false;
512 try {
513 this.admin.addColumn(tableName, xtracol);
514 } catch (TableNotDisabledException re) {
515 expectedException = true;
516 }
517
518 assertFalse(expectedException);
519 modifiedHtd = this.admin.getTableDescriptor(tableName);
520 hcd = modifiedHtd.getFamily(xtracol.getName());
521 assertTrue(hcd != null);
522 assertTrue(hcd.getValue(xtracolName).equals(xtracolName));
523
524
525 this.admin.deleteColumn(tableName, xtracol.getName());
526 modifiedHtd = this.admin.getTableDescriptor(tableName);
527 hcd = modifiedHtd.getFamily(xtracol.getName());
528 assertTrue(hcd == null);
529
530
531 this.admin.disableTable(tableName);
532 this.admin.deleteTable(tableName);
533 this.admin.listTables();
534 assertFalse(this.admin.tableExists(tableName));
535 }
536
537 @Test (timeout=300000)
538 public void testShouldFailOnlineSchemaUpdateIfOnlineSchemaIsNotEnabled()
539 throws Exception {
540 final byte[] tableName = Bytes.toBytes("changeTableSchemaOnlineFailure");
541 TEST_UTIL.getMiniHBaseCluster().getMaster().getConfiguration().setBoolean(
542 "hbase.online.schema.update.enable", false);
543 HTableDescriptor[] tables = admin.listTables();
544 int numTables = tables.length;
545 TEST_UTIL.createTable(tableName, HConstants.CATALOG_FAMILY).close();
546 tables = this.admin.listTables();
547 assertEquals(numTables + 1, tables.length);
548
549
550 HTableDescriptor htd = this.admin.getTableDescriptor(tableName);
551
552 HTableDescriptor copy = new HTableDescriptor(htd);
553 assertTrue(htd.equals(copy));
554
555 long newFlushSize = htd.getMemStoreFlushSize() / 2;
556 if (newFlushSize <=0) {
557 newFlushSize = HTableDescriptor.DEFAULT_MEMSTORE_FLUSH_SIZE / 2;
558 }
559 copy.setMemStoreFlushSize(newFlushSize);
560 final String key = "anyoldkey";
561 assertTrue(htd.getValue(key) == null);
562 copy.setValue(key, key);
563 boolean expectedException = false;
564 try {
565 admin.modifyTable(tableName, copy);
566 } catch (TableNotDisabledException re) {
567 expectedException = true;
568 }
569 assertTrue("Online schema update should not happen.", expectedException);
570
571
572 TEST_UTIL.getMiniHBaseCluster().getMaster().getConfiguration().setBoolean(
573 "hbase.online.schema.update.enable", true);
574 }
575
576
577
578
579 static class DoneListener implements EventHandler.EventHandlerListener {
580 private final AtomicBoolean done;
581
582 DoneListener(final AtomicBoolean done) {
583 super();
584 this.done = done;
585 }
586
587 @Override
588 public void afterProcess(EventHandler event) {
589 this.done.set(true);
590 synchronized (this.done) {
591
592 this.done.notifyAll();
593 }
594 }
595
596 @Override
597 public void beforeProcess(EventHandler event) {
598
599 }
600 }
601
602 @SuppressWarnings("deprecation")
603 protected void verifyRoundRobinDistribution(HTable ht, int expectedRegions) throws IOException {
604 int numRS = ht.getConnection().getCurrentNrHRS();
605 Map<HRegionInfo, ServerName> regions = ht.getRegionLocations();
606 Map<ServerName, List<HRegionInfo>> server2Regions = new HashMap<ServerName, List<HRegionInfo>>();
607 for (Map.Entry<HRegionInfo, ServerName> entry : regions.entrySet()) {
608 ServerName server = entry.getValue();
609 List<HRegionInfo> regs = server2Regions.get(server);
610 if (regs == null) {
611 regs = new ArrayList<HRegionInfo>();
612 server2Regions.put(server, regs);
613 }
614 regs.add(entry.getKey());
615 }
616 float average = (float) expectedRegions/numRS;
617 int min = (int)Math.floor(average);
618 int max = (int)Math.ceil(average);
619 for (List<HRegionInfo> regionList : server2Regions.values()) {
620 assertTrue(regionList.size() == min || regionList.size() == max);
621 }
622 }
623
624 @Test (timeout=300000)
625 public void testCreateTableNumberOfRegions() throws IOException, InterruptedException {
626 byte[] tableName = Bytes.toBytes("testCreateTableNumberOfRegions");
627 HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(tableName));
628 desc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY));
629 admin.createTable(desc);
630 HTable ht = new HTable(TEST_UTIL.getConfiguration(), tableName);
631 Map<HRegionInfo, ServerName> regions = ht.getRegionLocations();
632 assertEquals("Table should have only 1 region", 1, regions.size());
633 ht.close();
634
635 byte [] TABLE_2 = Bytes.add(tableName, Bytes.toBytes("_2"));
636 desc = new HTableDescriptor(TableName.valueOf(TABLE_2));
637 desc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY));
638 admin.createTable(desc, new byte[][]{new byte[]{42}});
639 HTable ht2 = new HTable(TEST_UTIL.getConfiguration(), TABLE_2);
640 regions = ht2.getRegionLocations();
641 assertEquals("Table should have only 2 region", 2, regions.size());
642 ht2.close();
643
644 byte [] TABLE_3 = Bytes.add(tableName, Bytes.toBytes("_3"));
645 desc = new HTableDescriptor(TableName.valueOf(TABLE_3));
646 desc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY));
647 admin.createTable(desc, "a".getBytes(), "z".getBytes(), 3);
648 HTable ht3 = new HTable(TEST_UTIL.getConfiguration(), TABLE_3);
649 regions = ht3.getRegionLocations();
650 assertEquals("Table should have only 3 region", 3, regions.size());
651 ht3.close();
652
653 byte [] TABLE_4 = Bytes.add(tableName, Bytes.toBytes("_4"));
654 desc = new HTableDescriptor(TableName.valueOf(TABLE_4));
655 desc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY));
656 try {
657 admin.createTable(desc, "a".getBytes(), "z".getBytes(), 2);
658 fail("Should not be able to create a table with only 2 regions using this API.");
659 } catch (IllegalArgumentException eae) {
660
661 }
662
663 byte [] TABLE_5 = Bytes.add(tableName, Bytes.toBytes("_5"));
664 desc = new HTableDescriptor(TableName.valueOf(TABLE_5));
665 desc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY));
666 admin.createTable(desc, new byte[] {1}, new byte[] {127}, 16);
667 HTable ht5 = new HTable(TEST_UTIL.getConfiguration(), TABLE_5);
668 regions = ht5.getRegionLocations();
669 assertEquals("Table should have 16 region", 16, regions.size());
670 ht5.close();
671 }
672
673 @Test (timeout=300000)
674 public void testCreateTableWithRegions() throws IOException, InterruptedException {
675
676 byte[] tableName = Bytes.toBytes("testCreateTableWithRegions");
677
678 byte [][] splitKeys = {
679 new byte [] { 1, 1, 1 },
680 new byte [] { 2, 2, 2 },
681 new byte [] { 3, 3, 3 },
682 new byte [] { 4, 4, 4 },
683 new byte [] { 5, 5, 5 },
684 new byte [] { 6, 6, 6 },
685 new byte [] { 7, 7, 7 },
686 new byte [] { 8, 8, 8 },
687 new byte [] { 9, 9, 9 },
688 };
689 int expectedRegions = splitKeys.length + 1;
690
691 HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(tableName));
692 desc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY));
693 admin.createTable(desc, splitKeys);
694
695 boolean tableAvailable = admin.isTableAvailable(Bytes.toString(tableName), splitKeys);
696 assertTrue("Table should be created with splitKyes + 1 rows in META", tableAvailable);
697
698 HTable ht = new HTable(TEST_UTIL.getConfiguration(), tableName);
699 Map<HRegionInfo, ServerName> regions = ht.getRegionLocations();
700 assertEquals("Tried to create " + expectedRegions + " regions " +
701 "but only found " + regions.size(),
702 expectedRegions, regions.size());
703 System.err.println("Found " + regions.size() + " regions");
704
705 Iterator<HRegionInfo> hris = regions.keySet().iterator();
706 HRegionInfo hri = hris.next();
707 assertTrue(hri.getStartKey() == null || hri.getStartKey().length == 0);
708 assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[0]));
709 hri = hris.next();
710 assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[0]));
711 assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[1]));
712 hri = hris.next();
713 assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[1]));
714 assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[2]));
715 hri = hris.next();
716 assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[2]));
717 assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[3]));
718 hri = hris.next();
719 assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[3]));
720 assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[4]));
721 hri = hris.next();
722 assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[4]));
723 assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[5]));
724 hri = hris.next();
725 assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[5]));
726 assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[6]));
727 hri = hris.next();
728 assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[6]));
729 assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[7]));
730 hri = hris.next();
731 assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[7]));
732 assertTrue(Bytes.equals(hri.getEndKey(), splitKeys[8]));
733 hri = hris.next();
734 assertTrue(Bytes.equals(hri.getStartKey(), splitKeys[8]));
735 assertTrue(hri.getEndKey() == null || hri.getEndKey().length == 0);
736
737 verifyRoundRobinDistribution(ht, expectedRegions);
738 ht.close();
739
740
741
742
743 byte [] startKey = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
744 byte [] endKey = { 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 };
745
746
747
748
749 expectedRegions = 10;
750
751 byte [] TABLE_2 = Bytes.add(tableName, Bytes.toBytes("_2"));
752
753 desc = new HTableDescriptor(TableName.valueOf(TABLE_2));
754 desc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY));
755 admin = new HBaseAdmin(TEST_UTIL.getConfiguration());
756 admin.createTable(desc, startKey, endKey, expectedRegions);
757
758 HTable ht2 = new HTable(TEST_UTIL.getConfiguration(), TABLE_2);
759 regions = ht2.getRegionLocations();
760 assertEquals("Tried to create " + expectedRegions + " regions " +
761 "but only found " + regions.size(),
762 expectedRegions, regions.size());
763 System.err.println("Found " + regions.size() + " regions");
764
765 hris = regions.keySet().iterator();
766 hri = hris.next();
767 assertTrue(hri.getStartKey() == null || hri.getStartKey().length == 0);
768 assertTrue(Bytes.equals(hri.getEndKey(), new byte [] {1,1,1,1,1,1,1,1,1,1}));
769 hri = hris.next();
770 assertTrue(Bytes.equals(hri.getStartKey(), new byte [] {1,1,1,1,1,1,1,1,1,1}));
771 assertTrue(Bytes.equals(hri.getEndKey(), new byte [] {2,2,2,2,2,2,2,2,2,2}));
772 hri = hris.next();
773 assertTrue(Bytes.equals(hri.getStartKey(), new byte [] {2,2,2,2,2,2,2,2,2,2}));
774 assertTrue(Bytes.equals(hri.getEndKey(), new byte [] {3,3,3,3,3,3,3,3,3,3}));
775 hri = hris.next();
776 assertTrue(Bytes.equals(hri.getStartKey(), new byte [] {3,3,3,3,3,3,3,3,3,3}));
777 assertTrue(Bytes.equals(hri.getEndKey(), new byte [] {4,4,4,4,4,4,4,4,4,4}));
778 hri = hris.next();
779 assertTrue(Bytes.equals(hri.getStartKey(), new byte [] {4,4,4,4,4,4,4,4,4,4}));
780 assertTrue(Bytes.equals(hri.getEndKey(), new byte [] {5,5,5,5,5,5,5,5,5,5}));
781 hri = hris.next();
782 assertTrue(Bytes.equals(hri.getStartKey(), new byte [] {5,5,5,5,5,5,5,5,5,5}));
783 assertTrue(Bytes.equals(hri.getEndKey(), new byte [] {6,6,6,6,6,6,6,6,6,6}));
784 hri = hris.next();
785 assertTrue(Bytes.equals(hri.getStartKey(), new byte [] {6,6,6,6,6,6,6,6,6,6}));
786 assertTrue(Bytes.equals(hri.getEndKey(), new byte [] {7,7,7,7,7,7,7,7,7,7}));
787 hri = hris.next();
788 assertTrue(Bytes.equals(hri.getStartKey(), new byte [] {7,7,7,7,7,7,7,7,7,7}));
789 assertTrue(Bytes.equals(hri.getEndKey(), new byte [] {8,8,8,8,8,8,8,8,8,8}));
790 hri = hris.next();
791 assertTrue(Bytes.equals(hri.getStartKey(), new byte [] {8,8,8,8,8,8,8,8,8,8}));
792 assertTrue(Bytes.equals(hri.getEndKey(), new byte [] {9,9,9,9,9,9,9,9,9,9}));
793 hri = hris.next();
794 assertTrue(Bytes.equals(hri.getStartKey(), new byte [] {9,9,9,9,9,9,9,9,9,9}));
795 assertTrue(hri.getEndKey() == null || hri.getEndKey().length == 0);
796
797 verifyRoundRobinDistribution(ht2, expectedRegions);
798 ht2.close();
799
800
801
802 startKey = new byte [] { 0, 0, 0, 0, 0, 0 };
803 endKey = new byte [] { 1, 0, 0, 0, 0, 0 };
804
805 expectedRegions = 5;
806
807 byte [] TABLE_3 = Bytes.add(tableName, Bytes.toBytes("_3"));
808
809 desc = new HTableDescriptor(TableName.valueOf(TABLE_3));
810 desc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY));
811 admin = new HBaseAdmin(TEST_UTIL.getConfiguration());
812 admin.createTable(desc, startKey, endKey, expectedRegions);
813
814
815 HTable ht3 = new HTable(TEST_UTIL.getConfiguration(), TABLE_3);
816 regions = ht3.getRegionLocations();
817 assertEquals("Tried to create " + expectedRegions + " regions " +
818 "but only found " + regions.size(),
819 expectedRegions, regions.size());
820 System.err.println("Found " + regions.size() + " regions");
821
822 verifyRoundRobinDistribution(ht3, expectedRegions);
823 ht3.close();
824
825
826
827 splitKeys = new byte [][] {
828 new byte [] { 1, 1, 1 },
829 new byte [] { 2, 2, 2 },
830 new byte [] { 3, 3, 3 },
831 new byte [] { 2, 2, 2 }
832 };
833
834 byte [] TABLE_4 = Bytes.add(tableName, Bytes.toBytes("_4"));
835 desc = new HTableDescriptor(TableName.valueOf(TABLE_4));
836 desc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY));
837 HBaseAdmin ladmin = new HBaseAdmin(TEST_UTIL.getConfiguration());
838 try {
839 ladmin.createTable(desc, splitKeys);
840 assertTrue("Should not be able to create this table because of " +
841 "duplicate split keys", false);
842 } catch(IllegalArgumentException iae) {
843
844 }
845 ladmin.close();
846 }
847
848 @Test (timeout=300000)
849 public void testTableAvailableWithRandomSplitKeys() throws Exception {
850 byte[] tableName = Bytes.toBytes("testTableAvailableWithRandomSplitKeys");
851 HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(tableName));
852 desc.addFamily(new HColumnDescriptor("col"));
853 byte[][] splitKeys = new byte[1][];
854 splitKeys = new byte [][] {
855 new byte [] { 1, 1, 1 },
856 new byte [] { 2, 2, 2 }
857 };
858 admin.createTable(desc);
859 boolean tableAvailable = admin.isTableAvailable(Bytes.toString(tableName), splitKeys);
860 assertFalse("Table should be created with 1 row in META", tableAvailable);
861 }
862
863 @Test (timeout=300000)
864 public void testCreateTableWithOnlyEmptyStartRow() throws IOException {
865 byte[] tableName = Bytes.toBytes("testCreateTableWithOnlyEmptyStartRow");
866 byte[][] splitKeys = new byte[1][];
867 splitKeys[0] = HConstants.EMPTY_BYTE_ARRAY;
868 HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(tableName));
869 desc.addFamily(new HColumnDescriptor("col"));
870 try {
871 admin.createTable(desc, splitKeys);
872 fail("Test case should fail as empty split key is passed.");
873 } catch (IllegalArgumentException e) {
874 }
875 }
876
877 @Test (timeout=300000)
878 public void testCreateTableWithEmptyRowInTheSplitKeys() throws IOException{
879 byte[] tableName = Bytes.toBytes("testCreateTableWithEmptyRowInTheSplitKeys");
880 byte[][] splitKeys = new byte[3][];
881 splitKeys[0] = "region1".getBytes();
882 splitKeys[1] = HConstants.EMPTY_BYTE_ARRAY;
883 splitKeys[2] = "region2".getBytes();
884 HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(tableName));
885 desc.addFamily(new HColumnDescriptor("col"));
886 try {
887 admin.createTable(desc, splitKeys);
888 fail("Test case should fail as empty split key is passed.");
889 } catch (IllegalArgumentException e) {
890 LOG.info("Expected ", e);
891 }
892 }
893
894 @Test (timeout=120000)
895 public void testTableExist() throws IOException {
896 final byte [] table = Bytes.toBytes("testTableExist");
897 boolean exist;
898 exist = this.admin.tableExists(table);
899 assertEquals(false, exist);
900 TEST_UTIL.createTable(table, HConstants.CATALOG_FAMILY);
901 exist = this.admin.tableExists(table);
902 assertEquals(true, exist);
903 }
904
905
906
907
908
909
910 @Test (timeout=300000)
911 public void testForceSplit() throws Exception {
912 byte[][] familyNames = new byte[][] { Bytes.toBytes("cf") };
913 int[] rowCounts = new int[] { 6000 };
914 int numVersions = HColumnDescriptor.DEFAULT_VERSIONS;
915 int blockSize = 256;
916 splitTest(null, familyNames, rowCounts, numVersions, blockSize);
917
918 byte[] splitKey = Bytes.toBytes(3500);
919 splitTest(splitKey, familyNames, rowCounts, numVersions, blockSize);
920 }
921
922
923
924
925
926
927 @Test (timeout=300000)
928 public void testEnableTableRetainAssignment() throws IOException {
929 byte[] tableName = Bytes.toBytes("testEnableTableAssignment");
930 byte[][] splitKeys = { new byte[] { 1, 1, 1 }, new byte[] { 2, 2, 2 },
931 new byte[] { 3, 3, 3 }, new byte[] { 4, 4, 4 }, new byte[] { 5, 5, 5 },
932 new byte[] { 6, 6, 6 }, new byte[] { 7, 7, 7 }, new byte[] { 8, 8, 8 },
933 new byte[] { 9, 9, 9 } };
934 int expectedRegions = splitKeys.length + 1;
935 HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(tableName));
936 desc.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY));
937 admin.createTable(desc, splitKeys);
938 HTable ht = new HTable(TEST_UTIL.getConfiguration(), tableName);
939 Map<HRegionInfo, ServerName> regions = ht.getRegionLocations();
940 ht.close();
941 assertEquals("Tried to create " + expectedRegions + " regions "
942 + "but only found " + regions.size(), expectedRegions, regions.size());
943
944 admin.disableTable(tableName);
945
946 admin.enableTable(tableName);
947 Map<HRegionInfo, ServerName> regions2 = ht.getRegionLocations();
948
949
950 assertEquals(regions.size(), regions2.size());
951 for (Map.Entry<HRegionInfo, ServerName> entry : regions.entrySet()) {
952 assertEquals(regions2.get(entry.getKey()), entry.getValue());
953 }
954 }
955
956
957
958
959
960
961
962 @Test (timeout=300000)
963 public void testForceSplitMultiFamily() throws Exception {
964 int numVersions = HColumnDescriptor.DEFAULT_VERSIONS;
965
966
967
968
969 int blockSize = 256;
970 byte[][] familyNames = new byte[][] { Bytes.toBytes("cf1"),
971 Bytes.toBytes("cf2") };
972
973
974 int[] rowCounts = new int[] { 6000, 1 };
975 splitTest(null, familyNames, rowCounts, numVersions, blockSize);
976
977 rowCounts = new int[] { 1, 6000 };
978 splitTest(null, familyNames, rowCounts, numVersions, blockSize);
979
980
981
982 rowCounts = new int[] { 6000, 300 };
983 splitTest(null, familyNames, rowCounts, numVersions, blockSize);
984
985 rowCounts = new int[] { 300, 6000 };
986 splitTest(null, familyNames, rowCounts, numVersions, blockSize);
987
988 }
989
990 void splitTest(byte[] splitPoint, byte[][] familyNames, int[] rowCounts,
991 int numVersions, int blockSize) throws Exception {
992 TableName tableName = TableName.valueOf("testForceSplit");
993 StringBuilder sb = new StringBuilder();
994
995 for (int i = 0; i < rowCounts.length; i++) {
996 sb.append("_").append(Integer.toString(rowCounts[i]));
997 }
998 assertFalse(admin.tableExists(tableName));
999 final HTable table = TEST_UTIL.createTable(tableName, familyNames,
1000 numVersions, blockSize);
1001
1002 int rowCount = 0;
1003 byte[] q = new byte[0];
1004
1005
1006
1007 for (int index = 0; index < familyNames.length; index++) {
1008 ArrayList<Put> puts = new ArrayList<Put>(rowCounts[index]);
1009 for (int i = 0; i < rowCounts[index]; i++) {
1010 byte[] k = Bytes.toBytes(i);
1011 Put put = new Put(k);
1012 put.add(familyNames[index], q, k);
1013 puts.add(put);
1014 }
1015 table.put(puts);
1016
1017 if ( rowCount < rowCounts[index] ) {
1018 rowCount = rowCounts[index];
1019 }
1020 }
1021
1022
1023 Map<HRegionInfo, ServerName> m = table.getRegionLocations();
1024 LOG.info("Initial regions (" + m.size() + "): " + m);
1025 assertTrue(m.size() == 1);
1026
1027
1028 Scan scan = new Scan();
1029 ResultScanner scanner = table.getScanner(scan);
1030 int rows = 0;
1031 for(@SuppressWarnings("unused") Result result : scanner) {
1032 rows++;
1033 }
1034 scanner.close();
1035 assertEquals(rowCount, rows);
1036
1037
1038 scan = new Scan();
1039 scanner = table.getScanner(scan);
1040
1041 scanner.next();
1042
1043
1044 this.admin.split(tableName.getName(), splitPoint);
1045
1046 final AtomicInteger count = new AtomicInteger(0);
1047 Thread t = new Thread("CheckForSplit") {
1048 public void run() {
1049 for (int i = 0; i < 20; i++) {
1050 try {
1051 sleep(1000);
1052 } catch (InterruptedException e) {
1053 continue;
1054 }
1055
1056 Map<HRegionInfo, ServerName> regions = null;
1057 try {
1058 regions = table.getRegionLocations();
1059 } catch (IOException e) {
1060 e.printStackTrace();
1061 }
1062 if (regions == null) continue;
1063 count.set(regions.size());
1064 if (count.get() >= 2) {
1065 LOG.info("Found: " + regions);
1066 break;
1067 }
1068 LOG.debug("Cycle waiting on split");
1069 }
1070 LOG.debug("CheckForSplit thread exited, current region count: " + count.get());
1071 }
1072 };
1073 t.setPriority(Thread.NORM_PRIORITY - 2);
1074 t.start();
1075 t.join();
1076
1077
1078 rows = 1;
1079 for (@SuppressWarnings("unused") Result result : scanner) {
1080 rows++;
1081 if (rows > rowCount) {
1082 scanner.close();
1083 assertTrue("Scanned more than expected (" + rowCount + ")", false);
1084 }
1085 }
1086 scanner.close();
1087 assertEquals(rowCount, rows);
1088
1089 Map<HRegionInfo, ServerName> regions = null;
1090 try {
1091 regions = table.getRegionLocations();
1092 } catch (IOException e) {
1093 e.printStackTrace();
1094 }
1095 assertEquals(2, regions.size());
1096 Set<HRegionInfo> hRegionInfos = regions.keySet();
1097 HRegionInfo[] r = hRegionInfos.toArray(new HRegionInfo[hRegionInfos.size()]);
1098 if (splitPoint != null) {
1099
1100 assertEquals(Bytes.toString(splitPoint),
1101 Bytes.toString(r[0].getEndKey()));
1102 assertEquals(Bytes.toString(splitPoint),
1103 Bytes.toString(r[1].getStartKey()));
1104 LOG.debug("Properly split on " + Bytes.toString(splitPoint));
1105 } else {
1106 if (familyNames.length > 1) {
1107 int splitKey = Bytes.toInt(r[0].getEndKey());
1108
1109
1110 int deltaForLargestFamily = Math.abs(rowCount/2 - splitKey);
1111 LOG.debug("SplitKey=" + splitKey + "&deltaForLargestFamily=" + deltaForLargestFamily +
1112 ", r=" + r[0]);
1113 for (int index = 0; index < familyNames.length; index++) {
1114 int delta = Math.abs(rowCounts[index]/2 - splitKey);
1115 if (delta < deltaForLargestFamily) {
1116 assertTrue("Delta " + delta + " for family " + index
1117 + " should be at least deltaForLargestFamily " + deltaForLargestFamily,
1118 false);
1119 }
1120 }
1121 }
1122 }
1123 TEST_UTIL.deleteTable(tableName);
1124 table.close();
1125 }
1126
1127
1128
1129
1130
1131 @SuppressWarnings("deprecation")
1132 @Test (expected=IllegalArgumentException.class, timeout=300000)
1133 public void testEmptyHTableDescriptor() throws IOException {
1134 this.admin.createTable(new HTableDescriptor());
1135 }
1136
1137 @Test (expected=IllegalArgumentException.class, timeout=300000)
1138 public void testInvalidHColumnDescriptor() throws IOException {
1139 new HColumnDescriptor("/cfamily/name");
1140 }
1141
1142 @Test (timeout=300000)
1143 public void testEnableDisableAddColumnDeleteColumn() throws Exception {
1144 ZooKeeperWatcher zkw = HBaseTestingUtility.getZooKeeperWatcher(TEST_UTIL);
1145 TableName tableName = TableName.valueOf("testMasterAdmin");
1146 TEST_UTIL.createTable(tableName, HConstants.CATALOG_FAMILY).close();
1147 while (!ZKTableReadOnly.isEnabledTable(zkw,
1148 TableName.valueOf("testMasterAdmin"))) {
1149 Thread.sleep(10);
1150 }
1151 this.admin.disableTable(tableName);
1152 try {
1153 new HTable(TEST_UTIL.getConfiguration(), tableName);
1154 } catch (org.apache.hadoop.hbase.DoNotRetryIOException e) {
1155
1156 }
1157
1158 this.admin.addColumn(tableName, new HColumnDescriptor("col2"));
1159 this.admin.enableTable(tableName);
1160 try {
1161 this.admin.deleteColumn(tableName, Bytes.toBytes("col2"));
1162 } catch (TableNotDisabledException e) {
1163 LOG.info(e);
1164 }
1165 this.admin.disableTable(tableName);
1166 this.admin.deleteTable(tableName);
1167 }
1168 }