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 import org.apache.hadoop.hbase.util.ServerRegionReplicaUtil;
48
49 @InterfaceAudience.Private
50 public class ModifyTableHandler extends TableEventHandler {
51 private static final Log LOG = LogFactory.getLog(ModifyTableHandler.class);
52
53 private final HTableDescriptor htd;
54
55 public ModifyTableHandler(final TableName tableName,
56 final HTableDescriptor htd, final Server server,
57 final MasterServices masterServices) {
58 super(EventType.C_M_MODIFY_TABLE, tableName, server, masterServices);
59
60 this.htd = htd;
61 }
62
63 @Override
64 protected void prepareWithTableLock() throws IOException {
65 super.prepareWithTableLock();
66
67
68 if (masterServices.getAssignmentManager().getTableStateManager()
69 .isTableState(this.htd.getTableName(), ZooKeeperProtos.Table.State.ENABLED)
70 && this.htd.getRegionReplication() != getTableDescriptor().getRegionReplication()) {
71 throw new IOException("REGION_REPLICATION change is not supported for enabled tables");
72 }
73 }
74
75 @Override
76 protected void handleTableOperation(List<HRegionInfo> hris)
77 throws IOException {
78 MasterCoprocessorHost cpHost = ((HMaster) this.server).getMasterCoprocessorHost();
79 if (cpHost != null) {
80 cpHost.preModifyTableHandler(this.tableName, this.htd);
81 }
82
83 HTableDescriptor oldHtd = getTableDescriptor();
84 this.masterServices.getTableDescriptors().add(this.htd);
85 deleteFamilyFromFS(hris, oldHtd.getFamiliesKeys());
86 removeReplicaColumnsIfNeeded(this.htd.getRegionReplication(), oldHtd.getRegionReplication(),
87 htd.getTableName());
88
89 if (htd.getRegionReplication() > 1 && oldHtd.getRegionReplication() <= 1) {
90 ServerRegionReplicaUtil.setupRegionReplicaReplication(server.getConfiguration());
91 }
92 if (cpHost != null) {
93 cpHost.postModifyTableHandler(this.tableName, this.htd);
94 }
95 }
96
97 private void removeReplicaColumnsIfNeeded(int newReplicaCount, int oldReplicaCount,
98 TableName table) throws IOException {
99 if (newReplicaCount >= oldReplicaCount) return;
100 Set<byte[]> tableRows = new HashSet<byte[]>();
101 Scan scan = MetaTableAccessor.getScanForTableName(table);
102 scan.addColumn(HConstants.CATALOG_FAMILY, HConstants.REGIONINFO_QUALIFIER);
103 Connection connection = this.masterServices.getConnection();
104 try (Table metaTable = connection.getTable(TableName.META_TABLE_NAME)) {
105 ResultScanner resScanner = metaTable.getScanner(scan);
106 for (Result result : resScanner) {
107 tableRows.add(result.getRow());
108 }
109 MetaTableAccessor.removeRegionReplicasFromMeta(tableRows, newReplicaCount,
110 oldReplicaCount - newReplicaCount, masterServices.getConnection());
111 }
112 }
113
114
115
116
117 private void deleteFamilyFromFS(final List<HRegionInfo> hris, final Set<byte[]> oldFamilies) {
118 try {
119 Set<byte[]> newFamilies = this.htd.getFamiliesKeys();
120 MasterFileSystem mfs = this.masterServices.getMasterFileSystem();
121 for (byte[] familyName: oldFamilies) {
122 if (!newFamilies.contains(familyName)) {
123 LOG.debug("Removing family=" + Bytes.toString(familyName) +
124 " from table=" + this.tableName);
125 for (HRegionInfo hri: hris) {
126
127 mfs.deleteFamilyFromFS(hri, familyName);
128 }
129 }
130 }
131 } catch (IOException e) {
132 LOG.warn("Unable to remove on-disk directories for the removed families", e);
133 }
134 }
135
136 @Override
137 public String toString() {
138 String name = "UnknownServerName";
139 if(server != null && server.getServerName() != null) {
140 name = server.getServerName().toString();
141 }
142 return getClass().getSimpleName() + "-" + name + "-" + getSeqid() + "-" +
143 tableName;
144 }
145 }