View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.replication.regionserver;
19  
20  import static org.junit.Assert.assertEquals;
21  import static org.mockito.Mockito.mock;
22  import static org.mockito.Mockito.when;
23  
24  import java.util.List;
25  
26  import org.apache.hadoop.conf.Configuration;
27  import org.apache.hadoop.hbase.ServerName;
28  import org.apache.hadoop.hbase.testclassification.SmallTests;
29  import org.apache.hadoop.hbase.client.HConnection;
30  import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.AdminService;
31  import org.apache.hadoop.hbase.replication.HBaseReplicationEndpoint;
32  import org.apache.hadoop.hbase.replication.regionserver.ReplicationSinkManager.SinkPeer;
33  import org.junit.Before;
34  import org.junit.Test;
35  import org.junit.experimental.categories.Category;
36  
37  import com.google.common.collect.Lists;
38  
39  @Category(SmallTests.class)
40  public class TestReplicationSinkManager {
41  
42    private static final String PEER_CLUSTER_ID = "PEER_CLUSTER_ID";
43  
44    private HBaseReplicationEndpoint replicationEndpoint;
45    private ReplicationSinkManager sinkManager;
46  
47    @Before
48    public void setUp() {
49      replicationEndpoint = mock(HBaseReplicationEndpoint.class);
50      sinkManager = new ReplicationSinkManager(mock(HConnection.class),
51                        PEER_CLUSTER_ID, replicationEndpoint, new Configuration());
52    }
53  
54    @Test
55    public void testChooseSinks() {
56      List<ServerName> serverNames = Lists.newArrayList();
57      int totalServers = 20;
58      for (int i = 0; i < totalServers; i++) {
59        serverNames.add(mock(ServerName.class));
60      }
61  
62      when(replicationEndpoint.getRegionServers())
63            .thenReturn(serverNames);
64  
65      sinkManager.chooseSinks();
66  
67      int expected = (int) (totalServers * ReplicationSinkManager.DEFAULT_REPLICATION_SOURCE_RATIO);
68      assertEquals(expected, sinkManager.getNumSinks());
69  
70    }
71  
72    @Test
73    public void testChooseSinks_LessThanRatioAvailable() {
74      List<ServerName> serverNames = Lists.newArrayList(mock(ServerName.class),
75        mock(ServerName.class));
76  
77      when(replicationEndpoint.getRegionServers())
78            .thenReturn(serverNames);
79  
80      sinkManager.chooseSinks();
81  
82      assertEquals(1, sinkManager.getNumSinks());
83    }
84  
85    @Test
86    public void testReportBadSink() {
87      ServerName serverNameA = mock(ServerName.class);
88      ServerName serverNameB = mock(ServerName.class);
89      when(replicationEndpoint.getRegionServers())
90        .thenReturn(Lists.newArrayList(serverNameA, serverNameB));
91  
92      sinkManager.chooseSinks();
93      // Sanity check
94      assertEquals(1, sinkManager.getNumSinks());
95  
96      SinkPeer sinkPeer = new SinkPeer(serverNameA, mock(AdminService.BlockingInterface.class));
97  
98      sinkManager.reportBadSink(sinkPeer);
99  
100     // Just reporting a bad sink once shouldn't have an effect
101     assertEquals(1, sinkManager.getNumSinks());
102 
103   }
104 
105   /**
106    * Once a SinkPeer has been reported as bad more than BAD_SINK_THRESHOLD times, it should not
107    * be replicated to anymore.
108    */
109   @Test
110   public void testReportBadSink_PastThreshold() {
111     List<ServerName> serverNames = Lists.newArrayList();
112     int totalServers = 30;
113     for (int i = 0; i < totalServers; i++) {
114       serverNames.add(mock(ServerName.class));
115     }
116     when(replicationEndpoint.getRegionServers())
117           .thenReturn(serverNames);
118 
119 
120     sinkManager.chooseSinks();
121     // Sanity check
122     int expected = (int) (totalServers * ReplicationSinkManager.DEFAULT_REPLICATION_SOURCE_RATIO);
123     assertEquals(expected, sinkManager.getNumSinks());
124 
125     ServerName serverName = sinkManager.getSinksForTesting().get(0);
126 
127     SinkPeer sinkPeer = new SinkPeer(serverName, mock(AdminService.BlockingInterface.class));
128 
129     sinkManager.reportSinkSuccess(sinkPeer); // has no effect, counter does not go negative
130     for (int i = 0; i <= ReplicationSinkManager.DEFAULT_BAD_SINK_THRESHOLD; i++) {
131       sinkManager.reportBadSink(sinkPeer);
132     }
133 
134     // Reporting a bad sink more than the threshold count should remove it
135     // from the list of potential sinks
136     assertEquals(expected - 1, sinkManager.getNumSinks());
137 
138     //
139     // now try a sink that has some successes
140     //
141     serverName = sinkManager.getSinksForTesting().get(0);
142 
143     sinkPeer = new SinkPeer(serverName, mock(AdminService.BlockingInterface.class));
144     for (int i = 0; i <= ReplicationSinkManager.DEFAULT_BAD_SINK_THRESHOLD-1; i++) {
145       sinkManager.reportBadSink(sinkPeer);
146     }
147     sinkManager.reportSinkSuccess(sinkPeer); // one success
148     sinkManager.reportBadSink(sinkPeer);
149 
150     // did not remove the sink, since we had one successful try
151     assertEquals(expected - 1, sinkManager.getNumSinks());
152 
153     for (int i = 0; i <= ReplicationSinkManager.DEFAULT_BAD_SINK_THRESHOLD-2; i++) {
154       sinkManager.reportBadSink(sinkPeer);
155     }
156     // still not remove, since the success reset the counter
157     assertEquals(expected - 1, sinkManager.getNumSinks());
158 
159     sinkManager.reportBadSink(sinkPeer);
160     // but we exhausted the tries
161     assertEquals(expected - 2, sinkManager.getNumSinks());
162   }
163 
164   @Test
165   public void testReportBadSink_DownToZeroSinks() {
166     List<ServerName> serverNames = Lists.newArrayList();
167     int totalServers = 4;
168     for (int i = 0; i < totalServers; i++) {
169       serverNames.add(mock(ServerName.class));
170     }
171     when(replicationEndpoint.getRegionServers())
172           .thenReturn(serverNames);
173 
174 
175     sinkManager.chooseSinks();
176     // Sanity check
177     List<ServerName> sinkList = sinkManager.getSinksForTesting();
178     int expected = (int) (totalServers * ReplicationSinkManager.DEFAULT_REPLICATION_SOURCE_RATIO);
179     assertEquals(expected, sinkList.size());
180 
181     ServerName serverNameA = sinkList.get(0);
182     ServerName serverNameB = sinkList.get(1);
183 
184     SinkPeer sinkPeerA = new SinkPeer(serverNameA, mock(AdminService.BlockingInterface.class));
185     SinkPeer sinkPeerB = new SinkPeer(serverNameB, mock(AdminService.BlockingInterface.class));
186 
187     for (int i = 0; i <= ReplicationSinkManager.DEFAULT_BAD_SINK_THRESHOLD; i++) {
188       sinkManager.reportBadSink(sinkPeerA);
189       sinkManager.reportBadSink(sinkPeerB);
190     }
191 
192     // We've gone down to 0 good sinks, so the replication sinks
193     // should have been refreshed now, so out of 4 servers, 2 are not considered as they are
194     // reported as bad.
195     expected = (int) ((totalServers - 2) * ReplicationSinkManager.DEFAULT_REPLICATION_SOURCE_RATIO);
196     assertEquals(expected, sinkManager.getNumSinks());
197   }
198 
199 }