1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.master.handler;
20
21 import java.io.IOException;
22 import java.util.HashSet;
23 import java.util.List;
24 import java.util.Set;
25
26 import org.apache.commons.logging.Log;
27 import org.apache.commons.logging.LogFactory;
28 import org.apache.hadoop.hbase.HConstants;
29 import org.apache.hadoop.hbase.HRegionInfo;
30 import org.apache.hadoop.hbase.HTableDescriptor;
31 import org.apache.hadoop.hbase.MetaTableAccessor;
32 import org.apache.hadoop.hbase.Server;
33 import org.apache.hadoop.hbase.TableName;
34 import org.apache.hadoop.hbase.classification.InterfaceAudience;
35 import org.apache.hadoop.hbase.client.Connection;
36 import org.apache.hadoop.hbase.client.Result;
37 import org.apache.hadoop.hbase.client.ResultScanner;
38 import org.apache.hadoop.hbase.client.Scan;
39 import org.apache.hadoop.hbase.client.Table;
40 import org.apache.hadoop.hbase.executor.EventType;
41 import org.apache.hadoop.hbase.master.HMaster;
42 import org.apache.hadoop.hbase.master.MasterCoprocessorHost;
43 import org.apache.hadoop.hbase.master.MasterFileSystem;
44 import org.apache.hadoop.hbase.master.MasterServices;
45 import org.apache.hadoop.hbase.protobuf.generated.ZooKeeperProtos;
46 import org.apache.hadoop.hbase.util.Bytes;
47
48 @InterfaceAudience.Private
49 public class ModifyTableHandler extends TableEventHandler {
50 private static final Log LOG = LogFactory.getLog(ModifyTableHandler.class);
51
52 private final HTableDescriptor htd;
53
54 public ModifyTableHandler(final TableName tableName,
55 final HTableDescriptor htd, final Server server,
56 final MasterServices masterServices) {
57 super(EventType.C_M_MODIFY_TABLE, tableName, server, masterServices);
58
59 this.htd = htd;
60 }
61
62 @Override
63 protected void prepareWithTableLock() throws IOException {
64 super.prepareWithTableLock();
65
66
67 if (masterServices.getAssignmentManager().getTableStateManager()
68 .isTableState(this.htd.getTableName(), ZooKeeperProtos.Table.State.ENABLED)
69 && this.htd.getRegionReplication() != getTableDescriptor().getRegionReplication()) {
70 throw new IOException("REGION_REPLICATION change is not supported for enabled tables");
71 }
72 }
73
74 @Override
75 protected void handleTableOperation(List<HRegionInfo> hris)
76 throws IOException {
77 MasterCoprocessorHost cpHost = ((HMaster) this.server).getMasterCoprocessorHost();
78 if (cpHost != null) {
79 cpHost.preModifyTableHandler(this.tableName, this.htd);
80 }
81
82 HTableDescriptor oldHtd = getTableDescriptor();
83 this.masterServices.getTableDescriptors().add(this.htd);
84 deleteFamilyFromFS(hris, oldHtd.getFamiliesKeys());
85 removeReplicaColumnsIfNeeded(this.htd.getRegionReplication(), oldHtd.getRegionReplication(),
86 htd.getTableName());
87 if (cpHost != null) {
88 cpHost.postModifyTableHandler(this.tableName, this.htd);
89 }
90 }
91
92 private void removeReplicaColumnsIfNeeded(int newReplicaCount, int oldReplicaCount,
93 TableName table) throws IOException {
94 if (newReplicaCount >= oldReplicaCount) return;
95 Set<byte[]> tableRows = new HashSet<byte[]>();
96 Scan scan = MetaTableAccessor.getScanForTableName(table);
97 scan.addColumn(HConstants.CATALOG_FAMILY, HConstants.REGIONINFO_QUALIFIER);
98 Connection connection = this.masterServices.getConnection();
99 try (Table metaTable = connection.getTable(TableName.META_TABLE_NAME)) {
100 ResultScanner resScanner = metaTable.getScanner(scan);
101 for (Result result : resScanner) {
102 tableRows.add(result.getRow());
103 }
104 MetaTableAccessor.removeRegionReplicasFromMeta(tableRows, newReplicaCount,
105 oldReplicaCount - newReplicaCount, masterServices.getConnection());
106 }
107 }
108
109
110
111
112 private void deleteFamilyFromFS(final List<HRegionInfo> hris, final Set<byte[]> oldFamilies) {
113 try {
114 Set<byte[]> newFamilies = this.htd.getFamiliesKeys();
115 MasterFileSystem mfs = this.masterServices.getMasterFileSystem();
116 for (byte[] familyName: oldFamilies) {
117 if (!newFamilies.contains(familyName)) {
118 LOG.debug("Removing family=" + Bytes.toString(familyName) +
119 " from table=" + this.tableName);
120 for (HRegionInfo hri: hris) {
121
122 mfs.deleteFamilyFromFS(hri, familyName);
123 }
124 }
125 }
126 } catch (IOException e) {
127 LOG.warn("Unable to remove on-disk directories for the removed families", e);
128 }
129 }
130
131 @Override
132 public String toString() {
133 String name = "UnknownServerName";
134 if(server != null && server.getServerName() != null) {
135 name = server.getServerName().toString();
136 }
137 return getClass().getSimpleName() + "-" + name + "-" + getSeqid() + "-" +
138 tableName;
139 }
140 }