001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019package org.apache.hadoop.hbase.replication; 020 021import java.util.Collection; 022import java.util.Collections; 023import java.util.HashMap; 024import java.util.List; 025import java.util.Map; 026import java.util.Set; 027import java.util.TreeMap; 028import org.apache.hadoop.hbase.TableName; 029import org.apache.hadoop.hbase.util.Bytes; 030import org.apache.yetus.audience.InterfaceAudience; 031 032/** 033 * A configuration for the replication peer cluster. 034 */ 035@InterfaceAudience.Public 036public class ReplicationPeerConfig { 037 038 private String clusterKey; 039 private String replicationEndpointImpl; 040 private final Map<byte[], byte[]> peerData; 041 private final Map<String, String> configuration; 042 private Map<TableName, ? extends Collection<String>> tableCFsMap = null; 043 private Set<String> namespaces = null; 044 // Default value is true, means replicate all user tables to peer cluster. 045 private boolean replicateAllUserTables = true; 046 private Map<TableName, ? extends Collection<String>> excludeTableCFsMap = null; 047 private Set<String> excludeNamespaces = null; 048 private long bandwidth = 0; 049 private final boolean serial; 050 051 private ReplicationPeerConfig(ReplicationPeerConfigBuilderImpl builder) { 052 this.clusterKey = builder.clusterKey; 053 this.replicationEndpointImpl = builder.replicationEndpointImpl; 054 this.peerData = Collections.unmodifiableMap(builder.peerData); 055 this.configuration = Collections.unmodifiableMap(builder.configuration); 056 this.tableCFsMap = 057 builder.tableCFsMap != null ? unmodifiableTableCFsMap(builder.tableCFsMap) : null; 058 this.namespaces = 059 builder.namespaces != null ? Collections.unmodifiableSet(builder.namespaces) : null; 060 this.replicateAllUserTables = builder.replicateAllUserTables; 061 this.excludeTableCFsMap = 062 builder.excludeTableCFsMap != null ? unmodifiableTableCFsMap(builder.excludeTableCFsMap) 063 : null; 064 this.excludeNamespaces = 065 builder.excludeNamespaces != null ? Collections.unmodifiableSet(builder.excludeNamespaces) 066 : null; 067 this.bandwidth = builder.bandwidth; 068 this.serial = builder.serial; 069 } 070 071 private Map<TableName, List<String>> 072 unmodifiableTableCFsMap(Map<TableName, List<String>> tableCFsMap) { 073 Map<TableName, List<String>> newTableCFsMap = new HashMap<>(); 074 tableCFsMap.forEach((table, cfs) -> newTableCFsMap.put(table, 075 cfs != null ? Collections.unmodifiableList(cfs) : null)); 076 return Collections.unmodifiableMap(newTableCFsMap); 077 } 078 079 /** 080 * @deprecated as release of 2.0.0, and it will be removed in 3.0.0. Use 081 * {@link ReplicationPeerConfigBuilder} to create new ReplicationPeerConfig. 082 */ 083 @Deprecated 084 public ReplicationPeerConfig() { 085 this.peerData = new TreeMap<>(Bytes.BYTES_COMPARATOR); 086 this.configuration = new HashMap<>(0); 087 this.serial = false; 088 } 089 090 /** 091 * Set the clusterKey which is the concatenation of the slave cluster's: 092 * hbase.zookeeper.quorum:hbase.zookeeper.property.clientPort:zookeeper.znode.parent 093 * @deprecated as release of 2.0.0, and it will be removed in 3.0.0. Use 094 * {@link ReplicationPeerConfigBuilder#setClusterKey(String)} instead. 095 */ 096 @Deprecated 097 public ReplicationPeerConfig setClusterKey(String clusterKey) { 098 this.clusterKey = clusterKey; 099 return this; 100 } 101 102 /** 103 * Sets the ReplicationEndpoint plugin class for this peer. 104 * @param replicationEndpointImpl a class implementing ReplicationEndpoint 105 * @deprecated as release of 2.0.0, and it will be removed in 3.0.0. Use 106 * {@link ReplicationPeerConfigBuilder#setReplicationEndpointImpl(String)} instead. 107 */ 108 @Deprecated 109 public ReplicationPeerConfig setReplicationEndpointImpl(String replicationEndpointImpl) { 110 this.replicationEndpointImpl = replicationEndpointImpl; 111 return this; 112 } 113 114 public String getClusterKey() { 115 return clusterKey; 116 } 117 118 public String getReplicationEndpointImpl() { 119 return replicationEndpointImpl; 120 } 121 122 public Map<byte[], byte[]> getPeerData() { 123 return peerData; 124 } 125 126 public Map<String, String> getConfiguration() { 127 return configuration; 128 } 129 130 public Map<TableName, List<String>> getTableCFsMap() { 131 return (Map<TableName, List<String>>) tableCFsMap; 132 } 133 134 /** 135 * @deprecated as release of 2.0.0, and it will be removed in 3.0.0. Use 136 * {@link ReplicationPeerConfigBuilder#setTableCFsMap(Map)} instead. 137 */ 138 @Deprecated 139 public ReplicationPeerConfig setTableCFsMap(Map<TableName, 140 ? extends Collection<String>> tableCFsMap) { 141 this.tableCFsMap = tableCFsMap; 142 return this; 143 } 144 145 public Set<String> getNamespaces() { 146 return this.namespaces; 147 } 148 149 /** 150 * @deprecated as release of 2.0.0, and it will be removed in 3.0.0. Use 151 * {@link ReplicationPeerConfigBuilder#setNamespaces(Set)} instead. 152 */ 153 @Deprecated 154 public ReplicationPeerConfig setNamespaces(Set<String> namespaces) { 155 this.namespaces = namespaces; 156 return this; 157 } 158 159 public long getBandwidth() { 160 return this.bandwidth; 161 } 162 163 /** 164 * @deprecated as release of 2.0.0, and it will be removed in 3.0.0. Use 165 * {@link ReplicationPeerConfigBuilder#setBandwidth(long)} instead. 166 */ 167 @Deprecated 168 public ReplicationPeerConfig setBandwidth(long bandwidth) { 169 this.bandwidth = bandwidth; 170 return this; 171 } 172 173 public boolean replicateAllUserTables() { 174 return this.replicateAllUserTables; 175 } 176 177 /** 178 * @deprecated as release of 2.0.0, and it will be removed in 3.0.0. Use 179 * {@link ReplicationPeerConfigBuilder#setReplicateAllUserTables(boolean)} instead. 180 */ 181 @Deprecated 182 public ReplicationPeerConfig setReplicateAllUserTables(boolean replicateAllUserTables) { 183 this.replicateAllUserTables = replicateAllUserTables; 184 return this; 185 } 186 187 public Map<TableName, List<String>> getExcludeTableCFsMap() { 188 return (Map<TableName, List<String>>) excludeTableCFsMap; 189 } 190 191 /** 192 * @deprecated as release of 2.0.0, and it will be removed in 3.0.0. Use 193 * {@link ReplicationPeerConfigBuilder#setExcludeTableCFsMap(Map)} instead. 194 */ 195 @Deprecated 196 public ReplicationPeerConfig setExcludeTableCFsMap(Map<TableName, 197 ? extends Collection<String>> tableCFsMap) { 198 this.excludeTableCFsMap = tableCFsMap; 199 return this; 200 } 201 202 public Set<String> getExcludeNamespaces() { 203 return this.excludeNamespaces; 204 } 205 206 /** 207 * @deprecated as release of 2.0.0, and it will be removed in 3.0.0. Use 208 * {@link ReplicationPeerConfigBuilder#setExcludeNamespaces(Set)} instead. 209 */ 210 @Deprecated 211 public ReplicationPeerConfig setExcludeNamespaces(Set<String> namespaces) { 212 this.excludeNamespaces = namespaces; 213 return this; 214 } 215 216 public static ReplicationPeerConfigBuilder newBuilder() { 217 return new ReplicationPeerConfigBuilderImpl(); 218 } 219 220 public boolean isSerial() { 221 return serial; 222 } 223 224 public static ReplicationPeerConfigBuilder newBuilder(ReplicationPeerConfig peerConfig) { 225 ReplicationPeerConfigBuilderImpl builder = new ReplicationPeerConfigBuilderImpl(); 226 builder.setClusterKey(peerConfig.getClusterKey()) 227 .setReplicationEndpointImpl(peerConfig.getReplicationEndpointImpl()) 228 .putAllPeerData(peerConfig.getPeerData()).putAllConfiguration(peerConfig.getConfiguration()) 229 .setTableCFsMap(peerConfig.getTableCFsMap()).setNamespaces(peerConfig.getNamespaces()) 230 .setReplicateAllUserTables(peerConfig.replicateAllUserTables()) 231 .setExcludeTableCFsMap(peerConfig.getExcludeTableCFsMap()) 232 .setExcludeNamespaces(peerConfig.getExcludeNamespaces()) 233 .setBandwidth(peerConfig.getBandwidth()).setSerial(peerConfig.isSerial()); 234 return builder; 235 } 236 237 static class ReplicationPeerConfigBuilderImpl implements ReplicationPeerConfigBuilder { 238 239 private String clusterKey; 240 241 private String replicationEndpointImpl; 242 243 private Map<byte[], byte[]> peerData = new TreeMap<>(Bytes.BYTES_COMPARATOR); 244 245 private Map<String, String> configuration = new HashMap<>(); 246 247 private Map<TableName, List<String>> tableCFsMap = null; 248 249 private Set<String> namespaces = null; 250 251 // Default value is true, means replicate all user tables to peer cluster. 252 private boolean replicateAllUserTables = true; 253 254 private Map<TableName, List<String>> excludeTableCFsMap = null; 255 256 private Set<String> excludeNamespaces = null; 257 258 private long bandwidth = 0; 259 260 private boolean serial = false; 261 262 @Override 263 public ReplicationPeerConfigBuilder setClusterKey(String clusterKey) { 264 this.clusterKey = clusterKey; 265 return this; 266 } 267 268 @Override 269 public ReplicationPeerConfigBuilder setReplicationEndpointImpl(String replicationEndpointImpl) { 270 this.replicationEndpointImpl = replicationEndpointImpl; 271 return this; 272 } 273 274 @Override 275 public ReplicationPeerConfigBuilder putConfiguration(String key, String value) { 276 this.configuration.put(key, value); 277 return this; 278 } 279 280 @Override 281 public ReplicationPeerConfigBuilder putPeerData(byte[] key, byte[] value) { 282 this.peerData.put(key, value); 283 return this; 284 } 285 286 @Override 287 public ReplicationPeerConfigBuilder 288 setTableCFsMap(Map<TableName, List<String>> tableCFsMap) { 289 this.tableCFsMap = tableCFsMap; 290 return this; 291 } 292 293 @Override 294 public ReplicationPeerConfigBuilder setNamespaces(Set<String> namespaces) { 295 this.namespaces = namespaces; 296 return this; 297 } 298 299 @Override 300 public ReplicationPeerConfigBuilder setReplicateAllUserTables(boolean replicateAllUserTables) { 301 this.replicateAllUserTables = replicateAllUserTables; 302 return this; 303 } 304 305 @Override 306 public ReplicationPeerConfigBuilder 307 setExcludeTableCFsMap(Map<TableName, List<String>> excludeTableCFsMap) { 308 this.excludeTableCFsMap = excludeTableCFsMap; 309 return this; 310 } 311 312 @Override 313 public ReplicationPeerConfigBuilder setExcludeNamespaces(Set<String> excludeNamespaces) { 314 this.excludeNamespaces = excludeNamespaces; 315 return this; 316 } 317 318 @Override 319 public ReplicationPeerConfigBuilder setBandwidth(long bandwidth) { 320 this.bandwidth = bandwidth; 321 return this; 322 } 323 324 @Override 325 public ReplicationPeerConfigBuilder setSerial(boolean serial) { 326 this.serial = serial; 327 return this; 328 } 329 330 @Override 331 public ReplicationPeerConfig build() { 332 // It would be nice to validate the configuration, but we have to work with "old" data 333 // from ZK which makes it much more difficult. 334 return new ReplicationPeerConfig(this); 335 } 336 } 337 338 @Override 339 public String toString() { 340 StringBuilder builder = new StringBuilder("clusterKey=").append(clusterKey).append(","); 341 builder.append("replicationEndpointImpl=").append(replicationEndpointImpl).append(","); 342 builder.append("replicateAllUserTables=").append(replicateAllUserTables).append(","); 343 if (replicateAllUserTables) { 344 if (excludeNamespaces != null) { 345 builder.append("excludeNamespaces=").append(excludeNamespaces.toString()).append(","); 346 } 347 if (excludeTableCFsMap != null) { 348 builder.append("excludeTableCFsMap=").append(excludeTableCFsMap.toString()).append(","); 349 } 350 } else { 351 if (namespaces != null) { 352 builder.append("namespaces=").append(namespaces.toString()).append(","); 353 } 354 if (tableCFsMap != null) { 355 builder.append("tableCFs=").append(tableCFsMap.toString()).append(","); 356 } 357 } 358 builder.append("bandwidth=").append(bandwidth).append(","); 359 builder.append("serial=").append(serial); 360 return builder.toString(); 361 } 362 363 /** 364 * Decide whether the table need replicate to the peer cluster 365 * @param table name of the table 366 * @return true if the table need replicate to the peer cluster 367 */ 368 public boolean needToReplicate(TableName table) { 369 String namespace = table.getNamespaceAsString(); 370 if (replicateAllUserTables) { 371 // replicate all user tables, but filter by exclude namespaces and table-cfs config 372 if (excludeNamespaces != null && excludeNamespaces.contains(namespace)) { 373 return false; 374 } 375 // trap here, must check existence first since HashMap allows null value. 376 if (excludeTableCFsMap == null || !excludeTableCFsMap.containsKey(table)) { 377 return true; 378 } 379 Collection<String> cfs = excludeTableCFsMap.get(table); 380 // if cfs is null or empty then we can make sure that we do not need to replicate this table, 381 // otherwise, we may still need to replicate the table but filter out some families. 382 return cfs != null && !cfs.isEmpty(); 383 } else { 384 // Not replicate all user tables, so filter by namespaces and table-cfs config 385 if (namespaces == null && tableCFsMap == null) { 386 return false; 387 } 388 // First filter by namespaces config 389 // If table's namespace in peer config, all the tables data are applicable for replication 390 if (namespaces != null && namespaces.contains(namespace)) { 391 return true; 392 } 393 return tableCFsMap != null && tableCFsMap.containsKey(table); 394 } 395 } 396}