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 */ 018package org.apache.hadoop.hbase.replication; 019 020import java.io.IOException; 021import java.util.List; 022import java.util.UUID; 023import java.util.concurrent.TimeUnit; 024import java.util.concurrent.TimeoutException; 025import org.apache.hadoop.conf.Configuration; 026import org.apache.hadoop.fs.FileSystem; 027import org.apache.hadoop.hbase.Abortable; 028import org.apache.hadoop.hbase.HBaseInterfaceAudience; 029import org.apache.hadoop.hbase.Server; 030import org.apache.hadoop.hbase.TableDescriptors; 031import org.apache.hadoop.hbase.replication.regionserver.MetricsSource; 032import org.apache.hadoop.hbase.replication.regionserver.ReplicationSourceInterface; 033import org.apache.hadoop.hbase.wal.WAL.Entry; 034import org.apache.yetus.audience.InterfaceAudience; 035 036/** 037 * ReplicationEndpoint is a plugin which implements replication to other HBase clusters, or other 038 * systems. ReplicationEndpoint implementation can be specified at the peer creation time by 039 * specifying it in the {@link ReplicationPeerConfig}. A ReplicationEndpoint is run in a thread in 040 * each region server in the same process. 041 * <p> 042 * ReplicationEndpoint is closely tied to ReplicationSource in a producer-consumer relation. 043 * ReplicationSource is an HBase-private class which tails the logs and manages the queue of logs 044 * plus management and persistence of all the state for replication. ReplicationEndpoint on the 045 * other hand is responsible for doing the actual shipping and persisting of the WAL entries in the 046 * other cluster. 047 */ 048@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.REPLICATION) 049public interface ReplicationEndpoint extends ReplicationPeerConfigListener { 050 // TODO: This class needs doc. Has a Context and a ReplicationContext. Then has #start, #stop. 051 // How they relate? Do we #start before #init(Context)? We fail fast if you don't? 052 053 @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.REPLICATION) 054 class Context { 055 private final ReplicationSourceInterface replicationSource; 056 private final Server server; 057 private final Configuration localConf; 058 private final Configuration conf; 059 private final FileSystem fs; 060 private final TableDescriptors tableDescriptors; 061 private final ReplicationPeer replicationPeer; 062 private final String peerId; 063 private final UUID clusterId; 064 private final MetricsSource metrics; 065 private final Abortable abortable; 066 067 @InterfaceAudience.Private 068 public Context(final ReplicationSourceInterface replicationSource, final Server server, 069 final Configuration localConf, final Configuration conf, final FileSystem fs, 070 final String peerId, final UUID clusterId, final ReplicationPeer replicationPeer, 071 final MetricsSource metrics, final TableDescriptors tableDescriptors, 072 final Abortable abortable) { 073 this.replicationSource = replicationSource; 074 this.server = server; 075 this.localConf = localConf; 076 this.conf = conf; 077 this.fs = fs; 078 this.clusterId = clusterId; 079 this.peerId = peerId; 080 this.replicationPeer = replicationPeer; 081 this.metrics = metrics; 082 this.tableDescriptors = tableDescriptors; 083 this.abortable = abortable; 084 } 085 086 public ReplicationSourceInterface getReplicationSource() { 087 return replicationSource; 088 } 089 090 public Server getServer() { 091 return server; 092 } 093 094 public Configuration getConfiguration() { 095 return conf; 096 } 097 098 public Configuration getLocalConfiguration() { 099 return localConf; 100 } 101 102 public FileSystem getFilesystem() { 103 return fs; 104 } 105 106 public UUID getClusterId() { 107 return clusterId; 108 } 109 110 public String getPeerId() { 111 return peerId; 112 } 113 114 public ReplicationPeerConfig getPeerConfig() { 115 return replicationPeer.getPeerConfig(); 116 } 117 118 public ReplicationPeer getReplicationPeer() { 119 return replicationPeer; 120 } 121 122 public MetricsSource getMetrics() { 123 return metrics; 124 } 125 126 public TableDescriptors getTableDescriptors() { 127 return tableDescriptors; 128 } 129 130 public Abortable getAbortable() { 131 return abortable; 132 } 133 } 134 135 /** 136 * Initialize the replication endpoint with the given context. 137 * @param context replication context 138 * @throws IOException error occur when initialize the endpoint. 139 */ 140 void init(Context context) throws IOException; 141 142 /** 143 * Whether or not, the replication endpoint can replicate to it's source cluster with the same 144 * UUID 145 */ 146 boolean canReplicateToSameCluster(); 147 148 /** 149 * Returns a UUID of the provided peer id. Every HBase cluster instance has a persisted associated 150 * UUID. If the replication is not performed to an actual HBase cluster (but some other system), 151 * the UUID returned has to uniquely identify the connected target system. 152 * @return a UUID or null if the peer cluster does not exist or is not connected. 153 */ 154 UUID getPeerUUID(); 155 156 /** 157 * Returns a WALEntryFilter to use for filtering out WALEntries from the log. Replication 158 * infrastructure will call this filter before sending the edits to shipEdits(). 159 * @return a {@link WALEntryFilter} or null. 160 */ 161 WALEntryFilter getWALEntryfilter(); 162 163 /** 164 * A context for {@link ReplicationEndpoint#replicate(ReplicateContext)} method. 165 */ 166 @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.REPLICATION) 167 static class ReplicateContext { 168 List<Entry> entries; 169 int size; 170 String walGroupId; 171 int timeout; 172 173 @InterfaceAudience.Private 174 public ReplicateContext() { 175 } 176 177 public ReplicateContext setEntries(List<Entry> entries) { 178 this.entries = entries; 179 return this; 180 } 181 182 public ReplicateContext setSize(int size) { 183 this.size = size; 184 return this; 185 } 186 187 public ReplicateContext setWalGroupId(String walGroupId) { 188 this.walGroupId = walGroupId; 189 return this; 190 } 191 192 public List<Entry> getEntries() { 193 return entries; 194 } 195 196 public int getSize() { 197 return size; 198 } 199 200 public String getWalGroupId() { 201 return walGroupId; 202 } 203 204 public void setTimeout(int timeout) { 205 this.timeout = timeout; 206 } 207 208 public int getTimeout() { 209 return this.timeout; 210 } 211 } 212 213 /** 214 * Replicate the given set of entries (in the context) to the other cluster. Can block until all 215 * the given entries are replicated. Upon this method is returned, all entries that were passed in 216 * the context are assumed to be persisted in the target cluster. 217 * @param replicateContext a context where WAL entries and other parameters can be obtained. 218 */ 219 boolean replicate(ReplicateContext replicateContext); 220 221 // The below methods are inspired by Guava Service. See 222 // https://github.com/google/guava/wiki/ServiceExplained for overview of Guava Service. 223 // Below we implement a subset only with different names on some methods so we can implement 224 // the below internally using Guava (without exposing our implementation to 225 // ReplicationEndpoint implementors. 226 227 /** 228 * Returns {@code true} if this service is RUNNING. 229 */ 230 boolean isRunning(); 231 232 /** Returns Return {@code true} is this service is STARTING (but not yet RUNNING). */ 233 boolean isStarting(); 234 235 /** 236 * Initiates service startup and returns immediately. A stopped service may not be restarted. 237 * Equivalent of startAsync call in Guava Service. 238 * @throws IllegalStateException if the service is not new, if it has been run already. 239 */ 240 void start(); 241 242 /** 243 * Waits for the {@link ReplicationEndpoint} to be up and running. 244 * @throws IllegalStateException if the service reaches a state from which it is not possible to 245 * enter the (internal) running state. e.g. if the state is 246 * terminated when this method is called then this will throw an 247 * IllegalStateException. 248 */ 249 void awaitRunning(); 250 251 /** 252 * Waits for the {@link ReplicationEndpoint} to to be up and running for no more than the given 253 * time. 254 * @param timeout the maximum time to wait 255 * @param unit the time unit of the timeout argument 256 * @throws TimeoutException if the service has not reached the given state within the 257 * deadline 258 * @throws IllegalStateException if the service reaches a state from which it is not possible to 259 * enter the (internal) running state. e.g. if the state is 260 * terminated when this method is called then this will throw an 261 * IllegalStateException. 262 */ 263 void awaitRunning(long timeout, TimeUnit unit) throws TimeoutException; 264 265 /** 266 * If the service is starting or running, this initiates service shutdown and returns immediately. 267 * If the service has already been stopped, this method returns immediately without taking action. 268 * Equivalent of stopAsync call in Guava Service. 269 */ 270 void stop(); 271 272 /** 273 * Waits for the {@link ReplicationEndpoint} to reach the terminated (internal) state. 274 * @throws IllegalStateException if the service FAILED. 275 */ 276 void awaitTerminated(); 277 278 /** 279 * Waits for the {@link ReplicationEndpoint} to reach a terminal state for no more than the given 280 * time. 281 * @param timeout the maximum time to wait 282 * @param unit the time unit of the timeout argument 283 * @throws TimeoutException if the service has not reached the given state within the 284 * deadline 285 * @throws IllegalStateException if the service FAILED. 286 */ 287 void awaitTerminated(long timeout, TimeUnit unit) throws TimeoutException; 288 289 /** 290 * Returns the {@link Throwable} that caused this service to fail. 291 * @throws IllegalStateException if this service's state isn't FAILED. 292 */ 293 Throwable failureCause(); 294 295 /** 296 * Hook invoked before persisting replication offsets. Eg: Buffered endpoints can flush/close WALs 297 * here. 298 */ 299 default void beforePersistingReplicationOffset() throws IOException { 300 } 301}