@Override public KeyValueScanner preStoreScannerOpen( final ObserverContext<RegionCoprocessorEnvironment> c, Store store, final Scan scan, final NavigableSet<byte[]> targetCols, KeyValueScanner s) throws IOException { TableName tn = store.getTableName(); if (!tn.isSystemTable()) { Long newTtl = ttls.get(store.getTableName()); Integer newVersions = versions.get(store.getTableName()); ScanInfo oldSI = store.getScanInfo(); HColumnDescriptor family = store.getFamily(); ScanInfo scanInfo = new ScanInfo( family.getName(), family.getMinVersions(), newVersions == null ? family.getMaxVersions() : newVersions, newTtl == null ? oldSI.getTtl() : newTtl, family.getKeepDeletedCells(), oldSI.getTimeToPurgeDeletes(), oldSI.getComparator()); return new StoreScanner( store, scanInfo, scan, targetCols, ((HStore) store).getHRegion().getReadpoint(IsolationLevel.READ_COMMITTED)); } else { return s; } }
@Override public InternalScanner preCompactScannerOpen( final ObserverContext<RegionCoprocessorEnvironment> c, Store store, List<? extends KeyValueScanner> scanners, ScanType scanType, long earliestPutTs, InternalScanner s) throws IOException { Long newTtl = ttls.get(store.getTableName()); Integer newVersions = versions.get(store.getTableName()); ScanInfo oldSI = store.getScanInfo(); HColumnDescriptor family = store.getFamily(); ScanInfo scanInfo = new ScanInfo( family.getName(), family.getMinVersions(), newVersions == null ? family.getMaxVersions() : newVersions, newTtl == null ? oldSI.getTtl() : newTtl, family.getKeepDeletedCells(), oldSI.getTimeToPurgeDeletes(), oldSI.getComparator()); Scan scan = new Scan(); scan.setMaxVersions(newVersions == null ? oldSI.getMaxVersions() : newVersions); return new StoreScanner( store, scanInfo, scan, scanners, scanType, store.getSmallestReadPoint(), earliestPutTs); }
@Override public InternalScanner preFlushScannerOpen( final ObserverContext<RegionCoprocessorEnvironment> c, Store store, KeyValueScanner memstoreScanner, InternalScanner s) throws IOException { Long newTtl = ttls.get(store.getTableName()); if (newTtl != null) { System.out.println("PreFlush:" + newTtl); } Integer newVersions = versions.get(store.getTableName()); ScanInfo oldSI = store.getScanInfo(); HColumnDescriptor family = store.getFamily(); ScanInfo scanInfo = new ScanInfo( family.getName(), family.getMinVersions(), newVersions == null ? family.getMaxVersions() : newVersions, newTtl == null ? oldSI.getTtl() : newTtl, family.getKeepDeletedCells(), oldSI.getTimeToPurgeDeletes(), oldSI.getComparator()); Scan scan = new Scan(); scan.setMaxVersions(newVersions == null ? oldSI.getMaxVersions() : newVersions); return new StoreScanner( store, scanInfo, scan, Collections.singletonList(memstoreScanner), ScanType.COMPACT_RETAIN_DELETES, store.getSmallestReadPoint(), HConstants.OLDEST_TIMESTAMP); }
/** * Restore the table descriptor back to pre-add * * @param env MasterProcedureEnv * @throws IOException */ private void restoreTableDescriptor(final MasterProcedureEnv env) throws IOException { HTableDescriptor htd = env.getMasterServices().getTableDescriptors().get(tableName); if (htd.hasFamily(cfDescriptor.getName())) { // Remove the column family from file system and update the table descriptor to // the before-add-column-family-state MasterDDLOperationHelper.deleteColumnFamilyFromFileSystem( env, tableName, getRegionInfoList(env), cfDescriptor.getName(), cfDescriptor.isMobEnabled()); env.getMasterServices().getTableDescriptors().add(unmodifiedHTableDescriptor); // Make sure regions are opened after table descriptor is updated. reOpenAllRegionsIfTableIsOnline(env); } }
/** * Enable in memory caching for .META. */ public static void setInfoFamilyCachingForMeta(final boolean b) { for (HColumnDescriptor hcd: HTableDescriptor.META_TABLEDESC.getColumnFamilies()) { if (Bytes.equals(hcd.getName(), HConstants.CATALOG_FAMILY)) { hcd.setBlockCacheEnabled(b); hcd.setInMemory(b); } } }
/** * This utility method creates a new Thrift ColumnDescriptor "struct" based on an Hbase * HColumnDescriptor object. * * @param in Hbase HColumnDescriptor object * @return Thrift ColumnDescriptor */ public static ColumnDescriptor colDescFromHbase(HColumnDescriptor in) { ColumnDescriptor col = new ColumnDescriptor(); col.name = ByteBuffer.wrap(Bytes.add(in.getName(), KeyValue.COLUMN_FAMILY_DELIM_ARRAY)); col.maxVersions = in.getMaxVersions(); col.compression = in.getCompression().toString(); col.inMemory = in.isInMemory(); col.blockCacheEnabled = in.isBlockCacheEnabled(); col.bloomFilterType = in.getBloomFilterType().toString(); return col; }
/** * Action before any real action of modifying column family. * * @param env MasterProcedureEnv * @throws IOException */ private void prepareModify(final MasterProcedureEnv env) throws IOException { // Checks whether the table is allowed to be modified. MasterDDLOperationHelper.checkTableModifiable(env, tableName); unmodifiedHTableDescriptor = env.getMasterServices().getTableDescriptors().get(tableName); if (unmodifiedHTableDescriptor == null) { throw new IOException("HTableDescriptor missing for " + tableName); } if (!unmodifiedHTableDescriptor.hasFamily(cfDescriptor.getName())) { throw new InvalidFamilyOperationException( "Family '" + getColumnFamilyName() + "' does not exist, so it cannot be modified"); } }
/** * Modify Column of a table * @param tableName * @param hcd HColumnDesciptor * @return Modified HTableDescriptor with the column modified. * @throws IOException */ public HTableDescriptor modifyColumn(byte[] tableName, HColumnDescriptor hcd) throws IOException { LOG.info("AddModifyColumn. Table = " + Bytes.toString(tableName) + " HCD = " + hcd.toString()); HTableDescriptor htd = this.services.getTableDescriptors().get(tableName); byte [] familyName = hcd.getName(); if(!htd.hasFamily(familyName)) { throw new InvalidFamilyOperationException("Family '" + Bytes.toString(familyName) + "' doesn't exists so cannot be modified"); } htd.addFamily(hcd); this.services.getTableDescriptors().add(htd); return htd; }
/** Add the column family to the file system */ private void updateTableDescriptor(final MasterProcedureEnv env) throws IOException { // Update table descriptor LOG.info("AddColumn. Table = " + tableName + " HCD = " + cfDescriptor.toString()); HTableDescriptor htd = env.getMasterServices().getTableDescriptors().get(tableName); if (htd.hasFamily(cfDescriptor.getName())) { // It is possible to reach this situation, as we could already add the column family // to table descriptor, but the master failover happens before we complete this state. // We should be able to handle running this function multiple times without causing problem. return; } htd.addFamily(cfDescriptor); env.getMasterServices().getTableDescriptors().add(htd); }
/** * Action before any real action of adding column family. * * @param env MasterProcedureEnv * @throws IOException */ private void prepareAdd(final MasterProcedureEnv env) throws IOException { // Checks whether the table is allowed to be modified. MasterDDLOperationHelper.checkTableModifiable(env, tableName); // In order to update the descriptor, we need to retrieve the old descriptor for comparison. unmodifiedHTableDescriptor = env.getMasterServices().getTableDescriptors().get(tableName); if (unmodifiedHTableDescriptor == null) { throw new IOException("HTableDescriptor missing for " + tableName); } if (unmodifiedHTableDescriptor.hasFamily(cfDescriptor.getName())) { throw new InvalidFamilyOperationException( "Column family '" + getColumnFamilyName() + "' in table '" + tableName + "' already exists so cannot be added"); } }
public void addMobRegion(HRegionInfo regionInfo, HColumnDescriptor[] hcds) throws IOException { // 0. Get the ManifestBuilder/RegionVisitor RegionVisitor visitor = createRegionVisitor(desc); // 1. dump region meta info into the snapshot directory LOG.debug("Storing mob region '" + regionInfo + "' region-info for snapshot."); Object regionData = visitor.regionOpen(regionInfo); monitor.rethrowException(); // 2. iterate through all the stores in the region LOG.debug("Creating references for mob files"); Path mobRegionPath = MobUtils.getMobRegionPath(conf, regionInfo.getTable()); for (HColumnDescriptor hcd : hcds) { // 2.1. build the snapshot reference for the store if it's a mob store if (!hcd.isMobEnabled()) { continue; } Object familyData = visitor.familyOpen(regionData, hcd.getName()); monitor.rethrowException(); Path storePath = MobUtils.getMobFamilyPath(mobRegionPath, hcd.getNameAsString()); List<StoreFileInfo> storeFiles = getStoreFiles(storePath); if (storeFiles == null) { if (LOG.isDebugEnabled()) { LOG.debug("No mob files under family: " + hcd.getNameAsString()); } continue; } addReferenceFiles(visitor, regionData, familyData, storeFiles, true); visitor.familyClose(regionData, familyData); } visitor.regionClose(regionData); }
@Test(timeout = 30000) public void testBulkLoad() throws IOException { // Create table then get the single region for our new table. LOG.debug("Creating test table"); HTableDescriptor hdt = HTU.createTableDescriptor("testBulkLoad"); hdt.setRegionReplication(NB_SERVERS); hdt.addCoprocessor(SlowMeCopro.class.getName()); Table table = HTU.createTable(hdt, new byte[][] {f}, HTU.getConfiguration()); // create hfiles to load. LOG.debug("Creating test data"); Path dir = HTU.getDataTestDirOnTestFS("testBulkLoad"); final int numRows = 10; final byte[] qual = Bytes.toBytes("qual"); final byte[] val = Bytes.toBytes("val"); final List<Pair<byte[], String>> famPaths = new ArrayList<Pair<byte[], String>>(); for (HColumnDescriptor col : hdt.getColumnFamilies()) { Path hfile = new Path(dir, col.getNameAsString()); TestHRegionServerBulkLoad.createHFile( HTU.getTestFileSystem(), hfile, col.getName(), qual, val, numRows); famPaths.add(new Pair<byte[], String>(col.getName(), hfile.toString())); } // bulk load HFiles LOG.debug("Loading test data"); @SuppressWarnings("deprecation") final HConnection conn = HTU.getHBaseAdmin().getConnection(); RegionServerCallable<Void> callable = new RegionServerCallable<Void>( conn, hdt.getTableName(), TestHRegionServerBulkLoad.rowkey(0)) { @Override public Void call(int timeout) throws Exception { LOG.debug( "Going to connect to server " + getLocation() + " for row " + Bytes.toStringBinary(getRow())); byte[] regionName = getLocation().getRegionInfo().getRegionName(); BulkLoadHFileRequest request = RequestConverter.buildBulkLoadHFileRequest(famPaths, regionName, true); getStub().bulkLoadHFile(null, request); return null; } }; RpcRetryingCallerFactory factory = new RpcRetryingCallerFactory(HTU.getConfiguration()); RpcRetryingCaller<Void> caller = factory.<Void>newCaller(); caller.callWithRetries(callable, 10000); // verify we can read them from the primary LOG.debug("Verifying data load"); for (int i = 0; i < numRows; i++) { byte[] row = TestHRegionServerBulkLoad.rowkey(i); Get g = new Get(row); Result r = table.get(g); Assert.assertFalse(r.isStale()); } // verify we can read them from the replica LOG.debug("Verifying replica queries"); try { SlowMeCopro.cdl.set(new CountDownLatch(1)); for (int i = 0; i < numRows; i++) { byte[] row = TestHRegionServerBulkLoad.rowkey(i); Get g = new Get(row); g.setConsistency(Consistency.TIMELINE); Result r = table.get(g); Assert.assertTrue(r.isStale()); } SlowMeCopro.cdl.get().countDown(); } finally { SlowMeCopro.cdl.get().countDown(); SlowMeCopro.sleepTime.set(0); } HTU.getHBaseAdmin().disableTable(hdt.getTableName()); HTU.deleteTable(hdt.getTableName()); }
/** * Verify schema modification takes. * * @throws IOException * @throws InterruptedException */ @Test(timeout = 300000) public void testOnlineChangeTableSchema() throws IOException, InterruptedException { final TableName tableName = TableName.valueOf("changeTableSchemaOnline"); TEST_UTIL .getMiniHBaseCluster() .getMaster() .getConfiguration() .setBoolean("hbase.online.schema.update.enable", true); HTableDescriptor[] tables = admin.listTables(); int numTables = tables.length; TEST_UTIL.createTable(tableName, HConstants.CATALOG_FAMILY).close(); tables = this.admin.listTables(); assertEquals(numTables + 1, tables.length); // FIRST, do htabledescriptor changes. HTableDescriptor htd = this.admin.getTableDescriptor(tableName); // Make a copy and assert copy is good. HTableDescriptor copy = new HTableDescriptor(htd); assertTrue(htd.equals(copy)); // Now amend the copy. Introduce differences. long newFlushSize = htd.getMemStoreFlushSize() / 2; if (newFlushSize <= 0) { newFlushSize = HTableDescriptor.DEFAULT_MEMSTORE_FLUSH_SIZE / 2; } copy.setMemStoreFlushSize(newFlushSize); final String key = "anyoldkey"; assertTrue(htd.getValue(key) == null); copy.setValue(key, key); boolean expectedException = false; try { admin.modifyTable(tableName, copy); } catch (TableNotDisabledException re) { expectedException = true; } assertFalse(expectedException); HTableDescriptor modifiedHtd = this.admin.getTableDescriptor(tableName); assertFalse(htd.equals(modifiedHtd)); assertTrue(copy.equals(modifiedHtd)); assertEquals(newFlushSize, modifiedHtd.getMemStoreFlushSize()); assertEquals(key, modifiedHtd.getValue(key)); // Now work on column family changes. int countOfFamilies = modifiedHtd.getFamilies().size(); assertTrue(countOfFamilies > 0); HColumnDescriptor hcd = modifiedHtd.getFamilies().iterator().next(); int maxversions = hcd.getMaxVersions(); final int newMaxVersions = maxversions + 1; hcd.setMaxVersions(newMaxVersions); final byte[] hcdName = hcd.getName(); expectedException = false; try { this.admin.modifyColumn(tableName, hcd); } catch (TableNotDisabledException re) { expectedException = true; } assertFalse(expectedException); modifiedHtd = this.admin.getTableDescriptor(tableName); HColumnDescriptor modifiedHcd = modifiedHtd.getFamily(hcdName); assertEquals(newMaxVersions, modifiedHcd.getMaxVersions()); // Try adding a column assertFalse(this.admin.isTableDisabled(tableName)); final String xtracolName = "xtracol"; HColumnDescriptor xtracol = new HColumnDescriptor(xtracolName); xtracol.setValue(xtracolName, xtracolName); expectedException = false; try { this.admin.addColumn(tableName, xtracol); } catch (TableNotDisabledException re) { expectedException = true; } // Add column should work even if the table is enabled assertFalse(expectedException); modifiedHtd = this.admin.getTableDescriptor(tableName); hcd = modifiedHtd.getFamily(xtracol.getName()); assertTrue(hcd != null); assertTrue(hcd.getValue(xtracolName).equals(xtracolName)); // Delete the just-added column. this.admin.deleteColumn(tableName, xtracol.getName()); modifiedHtd = this.admin.getTableDescriptor(tableName); hcd = modifiedHtd.getFamily(xtracol.getName()); assertTrue(hcd == null); // Delete the table this.admin.disableTable(tableName); this.admin.deleteTable(tableName); this.admin.listTables(); assertFalse(this.admin.tableExists(tableName)); }
@Test(timeout = 300000) public void testDeleteEditUnknownColumnFamilyAndOrTable() throws IOException { // Test we get exception if we try to final TableName nonexistentTable = TableName.valueOf("nonexistent"); final byte[] nonexistentColumn = Bytes.toBytes("nonexistent"); HColumnDescriptor nonexistentHcd = new HColumnDescriptor(nonexistentColumn); Exception exception = null; try { this.admin.addColumn(nonexistentTable, nonexistentHcd); } catch (IOException e) { exception = e; } assertTrue(exception instanceof TableNotFoundException); exception = null; try { this.admin.deleteTable(nonexistentTable); } catch (IOException e) { exception = e; } assertTrue(exception instanceof TableNotFoundException); exception = null; try { this.admin.deleteColumn(nonexistentTable, nonexistentColumn); } catch (IOException e) { exception = e; } assertTrue(exception instanceof TableNotFoundException); exception = null; try { this.admin.disableTable(nonexistentTable); } catch (IOException e) { exception = e; } assertTrue(exception instanceof TableNotFoundException); exception = null; try { this.admin.enableTable(nonexistentTable); } catch (IOException e) { exception = e; } assertTrue(exception instanceof TableNotFoundException); exception = null; try { this.admin.modifyColumn(nonexistentTable, nonexistentHcd); } catch (IOException e) { exception = e; } assertTrue(exception instanceof TableNotFoundException); exception = null; try { HTableDescriptor htd = new HTableDescriptor(nonexistentTable); htd.addFamily(new HColumnDescriptor(HConstants.CATALOG_FAMILY)); this.admin.modifyTable(htd.getTableName(), htd); } catch (IOException e) { exception = e; } assertTrue(exception instanceof TableNotFoundException); // Now make it so at least the table exists and then do tests against a // nonexistent column family -- see if we get right exceptions. final TableName tableName = TableName.valueOf( "testDeleteEditUnknownColumnFamilyAndOrTable" + System.currentTimeMillis()); HTableDescriptor htd = new HTableDescriptor(tableName); htd.addFamily(new HColumnDescriptor("cf")); this.admin.createTable(htd); try { exception = null; try { this.admin.deleteColumn(htd.getTableName(), nonexistentHcd.getName()); } catch (IOException e) { exception = e; } assertTrue( "found=" + exception.getClass().getName(), exception instanceof InvalidFamilyOperationException); exception = null; try { this.admin.modifyColumn(htd.getTableName(), nonexistentHcd); } catch (IOException e) { exception = e; } assertTrue( "found=" + exception.getClass().getName(), exception instanceof InvalidFamilyOperationException); } finally { this.admin.disableTable(tableName); this.admin.deleteTable(tableName); } }
/** {@inheritDoc} */ @Override public KijiTableLayout modifyTableLayout( TableLayoutDesc update, boolean dryRun, PrintStream printStream) throws IOException { final State state = mState.get(); Preconditions.checkState( state == State.OPEN, "Cannot modify table layout in Kiji instance %s in state %s.", this, state); Preconditions.checkNotNull(update); ensureValidationCompatibility(update); if (dryRun && (null == printStream)) { printStream = System.out; } final KijiMetaTable metaTable = getMetaTable(); final String tableName = update.getName(); // Throws a KijiTableNotFoundException if there is no table. metaTable.getTableLayout(tableName); final KijiURI tableURI = KijiURI.newBuilder(mURI).withTableName(tableName).build(); LOG.debug("Applying layout update {} on table {}", update, tableURI); KijiTableLayout newLayout = null; if (dryRun) { // Process column ids and perform validation, but don't actually update the meta table. final List<KijiTableLayout> layouts = metaTable.getTableLayoutVersions(tableName, 1); final KijiTableLayout currentLayout = layouts.isEmpty() ? null : layouts.get(0); newLayout = KijiTableLayout.createUpdatedLayout(update, currentLayout); } else { // Actually set it. if (mSystemVersion.compareTo(Versions.SYSTEM_2_0) >= 0) { try { // Use ZooKeeper to inform all watchers that a new table layout is available. final HBaseTableLayoutUpdater updater = new HBaseTableLayoutUpdater(this, tableURI, update); try { updater.update(); newLayout = updater.getNewLayout(); } finally { updater.close(); } } catch (KeeperException ke) { throw new IOException(ke); } } else { // System versions before system-2.0 do not enforce table layout update consistency or // validation. newLayout = metaTable.updateTableLayout(tableName, update); } } Preconditions.checkState(newLayout != null); if (dryRun) { printStream.println("This table layout is valid."); } LOG.debug("Computing new HBase schema"); final HTableSchemaTranslator translator = new HTableSchemaTranslator(); final HTableDescriptor newTableDescriptor = translator.toHTableDescriptor(mURI.getInstance(), newLayout); LOG.debug("Reading existing HBase schema"); final KijiManagedHBaseTableName hbaseTableName = KijiManagedHBaseTableName.getKijiTableName(mURI.getInstance(), tableName); HTableDescriptor currentTableDescriptor = null; byte[] tableNameAsBytes = hbaseTableName.toBytes(); try { currentTableDescriptor = getHBaseAdmin().getTableDescriptor(tableNameAsBytes); } catch (TableNotFoundException tnfe) { if (!dryRun) { throw tnfe; // Not in dry-run mode; table needs to exist. Rethrow exception. } } if (currentTableDescriptor == null) { if (dryRun) { printStream.println("Would create new table: " + tableName); currentTableDescriptor = HTableDescriptorComparator.makeEmptyTableDescriptor(hbaseTableName); } else { throw new RuntimeException( "Table " + hbaseTableName.getKijiTableName() + " does not exist"); } } LOG.debug("Existing table descriptor: {}", currentTableDescriptor); LOG.debug("New table descriptor: {}", newTableDescriptor); LOG.debug("Checking for differences between the new HBase schema and the existing one"); final HTableDescriptorComparator comparator = new HTableDescriptorComparator(); if (0 == comparator.compare(currentTableDescriptor, newTableDescriptor)) { LOG.debug("HBase schemas are the same. No need to change HBase schema"); if (dryRun) { printStream.println("This layout does not require any physical table schema changes."); } } else { LOG.debug("HBase schema must be changed, but no columns will be deleted"); if (dryRun) { printStream.println("Changes caused by this table layout:"); } else { LOG.debug("Disabling HBase table"); getHBaseAdmin().disableTable(hbaseTableName.toString()); } for (HColumnDescriptor newColumnDescriptor : newTableDescriptor.getFamilies()) { final String columnName = Bytes.toString(newColumnDescriptor.getName()); final ColumnId columnId = ColumnId.fromString(columnName); final String lgName = newLayout.getLocalityGroupIdNameMap().get(columnId); final HColumnDescriptor currentColumnDescriptor = currentTableDescriptor.getFamily(newColumnDescriptor.getName()); if (null == currentColumnDescriptor) { if (dryRun) { printStream.println(" Creating new locality group: " + lgName); } else { LOG.debug("Creating new column " + columnName); getHBaseAdmin().addColumn(hbaseTableName.toString(), newColumnDescriptor); } } else if (!newColumnDescriptor.equals(currentColumnDescriptor)) { if (dryRun) { printStream.println(" Modifying locality group: " + lgName); } else { LOG.debug("Modifying column " + columnName); getHBaseAdmin().modifyColumn(hbaseTableName.toString(), newColumnDescriptor); } } else { LOG.debug("No changes needed for column " + columnName); } } if (dryRun) { if (newTableDescriptor.getMaxFileSize() != currentTableDescriptor.getMaxFileSize()) { printStream.printf( " Changing max_filesize from %d to %d: %n", currentTableDescriptor.getMaxFileSize(), newTableDescriptor.getMaxFileSize()); } if (newTableDescriptor.getMaxFileSize() != currentTableDescriptor.getMaxFileSize()) { printStream.printf( " Changing memstore_flushsize from %d to %d: %n", currentTableDescriptor.getMemStoreFlushSize(), newTableDescriptor.getMemStoreFlushSize()); } } else { LOG.debug("Modifying table descriptor"); getHBaseAdmin().modifyTable(tableNameAsBytes, newTableDescriptor); } if (!dryRun) { LOG.debug("Re-enabling HBase table"); getHBaseAdmin().enableTable(hbaseTableName.toString()); } } return newLayout; }
/** * Verify schema modification takes. * * @throws IOException */ @Test public void testChangeTableSchema() throws IOException { final byte[] tableName = Bytes.toBytes("changeTableSchema"); HTableDescriptor[] tables = admin.listTables(); int numTables = tables.length; TEST_UTIL.createTable(tableName, HConstants.CATALOG_FAMILY); tables = this.admin.listTables(); assertEquals(numTables + 1, tables.length); // FIRST, do htabledescriptor changes. HTableDescriptor htd = this.admin.getTableDescriptor(tableName); // Make a copy and assert copy is good. HTableDescriptor copy = new HTableDescriptor(htd); assertTrue(htd.equals(copy)); // Now amend the copy. Introduce differences. long newFlushSize = htd.getMemStoreFlushSize() / 2; copy.setMemStoreFlushSize(newFlushSize); final String key = "anyoldkey"; assertTrue(htd.getValue(key) == null); copy.setValue(key, key); boolean expectedException = false; try { this.admin.modifyTable(tableName, copy); } catch (TableNotDisabledException re) { expectedException = true; } assertTrue(expectedException); this.admin.disableTable(tableName); assertTrue(this.admin.isTableDisabled(tableName)); modifyTable(tableName, copy); HTableDescriptor modifiedHtd = this.admin.getTableDescriptor(tableName); // Assert returned modifiedhcd is same as the copy. assertFalse(htd.equals(modifiedHtd)); assertTrue(copy.equals(modifiedHtd)); assertEquals(newFlushSize, modifiedHtd.getMemStoreFlushSize()); assertEquals(key, modifiedHtd.getValue(key)); // Reenable table to test it fails if not disabled. this.admin.enableTable(tableName); assertFalse(this.admin.isTableDisabled(tableName)); // Now work on column family changes. int countOfFamilies = modifiedHtd.getFamilies().size(); assertTrue(countOfFamilies > 0); HColumnDescriptor hcd = modifiedHtd.getFamilies().iterator().next(); int maxversions = hcd.getMaxVersions(); final int newMaxVersions = maxversions + 1; hcd.setMaxVersions(newMaxVersions); final byte[] hcdName = hcd.getName(); expectedException = false; try { this.admin.modifyColumn(tableName, hcd); } catch (TableNotDisabledException re) { expectedException = true; } assertTrue(expectedException); this.admin.disableTable(tableName); assertTrue(this.admin.isTableDisabled(tableName)); // Modify Column is synchronous this.admin.modifyColumn(tableName, hcd); modifiedHtd = this.admin.getTableDescriptor(tableName); HColumnDescriptor modifiedHcd = modifiedHtd.getFamily(hcdName); assertEquals(newMaxVersions, modifiedHcd.getMaxVersions()); // Try adding a column // Reenable table to test it fails if not disabled. this.admin.enableTable(tableName); assertFalse(this.admin.isTableDisabled(tableName)); final String xtracolName = "xtracol"; HColumnDescriptor xtracol = new HColumnDescriptor(xtracolName); xtracol.setValue(xtracolName, xtracolName); try { this.admin.addColumn(tableName, xtracol); } catch (TableNotDisabledException re) { expectedException = true; } assertTrue(expectedException); this.admin.disableTable(tableName); assertTrue(this.admin.isTableDisabled(tableName)); this.admin.addColumn(tableName, xtracol); modifiedHtd = this.admin.getTableDescriptor(tableName); hcd = modifiedHtd.getFamily(xtracol.getName()); assertTrue(hcd != null); assertTrue(hcd.getValue(xtracolName).equals(xtracolName)); // Delete the just-added column. this.admin.deleteColumn(tableName, xtracol.getName()); modifiedHtd = this.admin.getTableDescriptor(tableName); hcd = modifiedHtd.getFamily(xtracol.getName()); assertTrue(hcd == null); // Delete the table this.admin.deleteTable(tableName); this.admin.listTables(); assertFalse(this.admin.tableExists(tableName)); }