| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more contributor license |
| * agreements. See the NOTICE file distributed with this work for additional information regarding |
| * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the License. You may obtain a |
| * copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software distributed under the License |
| * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
| * or implied. See the License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| package org.apache.geode.distributed.internal.membership; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNull; |
| import static org.junit.Assert.assertTrue; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.junit.experimental.categories.Category; |
| |
| import org.apache.geode.distributed.internal.ClusterDistributionManager; |
| import org.apache.geode.distributed.internal.membership.gms.GMSMembershipView; |
| import org.apache.geode.distributed.internal.membership.gms.api.MemberIdentifier; |
| import org.apache.geode.internal.net.SocketCreator; |
| import org.apache.geode.test.junit.categories.MembershipTest; |
| |
| @Category({MembershipTest.class}) |
| public class MembershipViewJUnitTest { |
| |
| private List<MemberIdentifier> members; |
| |
| @Before |
| public void initMembers() throws Exception { |
| int numMembers = 10; |
| members = new ArrayList<>(numMembers); |
| for (int i = 0; i < numMembers; i++) { |
| members.add(new InternalDistributedMember(SocketCreator.getLocalHost(), 1000 + i)); |
| } |
| // view creator is a locator |
| members.get(0).setVmKind(ClusterDistributionManager.LOCATOR_DM_TYPE); |
| members.get(0).setVmViewId(0); |
| members.get(0).setPreferredForCoordinator(true); |
| |
| // members who joined in view #1 |
| for (int i = 1; i < (numMembers - 1); i++) { |
| members.get(i).setVmViewId(1); |
| members.get(i).setVmKind(ClusterDistributionManager.NORMAL_DM_TYPE); |
| members.get(i).setPreferredForCoordinator(false); |
| } |
| |
| // member joining in this view |
| members.get(numMembers - 1).setVmViewId(2); |
| members.get(numMembers - 1).getMemberData() |
| .setVmKind(ClusterDistributionManager.NORMAL_DM_TYPE); |
| } |
| |
| private void setFailureDetectionPorts(GMSMembershipView view) { |
| int numMembers = members.size(); |
| // use the membership port as the FD port so it's easy to figure out problems |
| for (int i = 0; i < numMembers; i++) { |
| view.setFailureDetectionPort(members.get(i), members.get(i).getMembershipPort()); |
| } |
| } |
| |
| @Test |
| public void testCreateView() throws Exception { |
| int numMembers = members.size(); |
| GMSMembershipView view = new GMSMembershipView(members.get(0), 2, members); |
| setFailureDetectionPorts(view); |
| |
| assertTrue(view.getCreator().equals(members.get(0))); |
| assertEquals(2, view.getViewId()); |
| assertEquals(members, view.getMembers()); |
| assertEquals(0, view.getCrashedMembers().size()); |
| assertEquals(members.get(1), view.getLeadMember()); // a locator can't be lead member |
| assertEquals(0, view.getShutdownMembers().size()); |
| assertEquals(1, view.getNewMembers().size()); |
| assertEquals(members.get(numMembers - 1), view.getNewMembers().iterator().next()); |
| assertEquals(members.get(0), view.getCoordinator()); |
| |
| for (int i = 0; i < numMembers; i++) { |
| MemberIdentifier mbr = members.get(i); |
| assertEquals(mbr.getMembershipPort(), view.getFailureDetectionPort(mbr)); |
| } |
| |
| assertFalse(view.shouldBeCoordinator(members.get(1))); |
| assertTrue(view.shouldBeCoordinator(members.get(0))); |
| assertEquals(members.get(numMembers - 1), |
| view.getCoordinator(Collections.singletonList(members.get(0)))); |
| members.get(numMembers - 1).setPreferredForCoordinator(false); |
| assertEquals(members.get(1), view.getCoordinator(Collections.singletonList(members.get(0)))); |
| |
| members.get(numMembers - 1).setPreferredForCoordinator(true); |
| List<MemberIdentifier> preferred = view.getPreferredCoordinators( |
| Collections.<MemberIdentifier>singleton(members.get(1)), members.get(0), 2); |
| assertEquals(2, preferred.size()); |
| assertEquals(members.get(numMembers - 1), preferred.get(0)); |
| } |
| |
| @Test |
| public void testRemoveMembers() throws Exception { |
| int numMembers = members.size(); |
| GMSMembershipView view = new GMSMembershipView(members.get(0), 2, new ArrayList<>(members)); |
| setFailureDetectionPorts(view); |
| |
| for (int i = 1; i < numMembers; i += 2) { |
| view.remove(members.get(i)); |
| assertFalse(view.contains(members.get(i))); |
| } |
| |
| List<MemberIdentifier> remainingMembers = view.getMembers(); |
| int num = remainingMembers.size(); |
| for (int i = 0; i < num; i++) { |
| MemberIdentifier mbr = remainingMembers.get(i); |
| assertEquals(mbr.getMembershipPort(), view.getFailureDetectionPort((MemberIdentifier) mbr)); |
| } |
| } |
| |
| @Test |
| public void testRemoveAll() throws Exception { |
| int numMembers = members.size(); |
| GMSMembershipView view = new GMSMembershipView(members.get(0), 2, new ArrayList<>(members)); |
| setFailureDetectionPorts(view); |
| |
| Collection<MemberIdentifier> removals = new ArrayList<>(numMembers / 2); |
| for (int i = 1; i < numMembers; i += 2) { |
| removals.add(members.get(i)); |
| } |
| |
| view.removeAll(removals); |
| for (MemberIdentifier mbr : removals) { |
| assertFalse(view.contains(mbr)); |
| } |
| assertEquals(numMembers - removals.size(), view.size()); |
| |
| List<MemberIdentifier> remainingMembers = view.getMembers(); |
| int num = remainingMembers.size(); |
| for (int i = 0; i < num; i++) { |
| MemberIdentifier mbr = remainingMembers.get(i); |
| assertEquals(mbr.getMembershipPort(), view.getFailureDetectionPort((MemberIdentifier) mbr)); |
| } |
| } |
| |
| @Test |
| public void testCopyView() throws Exception { |
| GMSMembershipView view = new GMSMembershipView(members.get(0), 2, new ArrayList<>(members)); |
| setFailureDetectionPorts(view); |
| |
| GMSMembershipView newView = new GMSMembershipView(view, 3); |
| |
| assertTrue(newView.getCreator().equals(members.get(0))); |
| assertEquals(3, newView.getViewId()); |
| assertEquals(members, newView.getMembers()); |
| assertEquals(0, newView.getCrashedMembers().size()); |
| assertEquals(members.get(1), newView.getLeadMember()); // a locator can't be lead member |
| assertEquals(0, newView.getShutdownMembers().size()); |
| assertEquals(0, newView.getNewMembers().size()); |
| assertTrue(newView.equals(view)); |
| assertTrue(view.equals(newView)); |
| newView.remove(members.get(1)); |
| assertFalse(newView.equals(view)); |
| } |
| |
| @Test |
| public void testAddLotsOfMembers() throws Exception { |
| GMSMembershipView view = new GMSMembershipView(members.get(0), 2, new ArrayList<>(members)); |
| setFailureDetectionPorts(view); |
| |
| GMSMembershipView copy = new GMSMembershipView(view, 2); |
| |
| int oldSize = view.size(); |
| for (int i = 0; i < 100; i++) { |
| MemberIdentifier mbr = new InternalDistributedMember(SocketCreator.getLocalHost(), 2000 + i); |
| mbr.setVmKind(ClusterDistributionManager.NORMAL_DM_TYPE); |
| mbr.setVmViewId(2); |
| view.add(mbr); |
| view.setFailureDetectionPort(mbr, 2000 + i); |
| } |
| |
| assertEquals(oldSize + 100, view.size()); |
| for (MemberIdentifier mbr : view.getMembers()) { |
| assertEquals(mbr.getMembershipPort(), view.getFailureDetectionPort(mbr)); |
| } |
| |
| assertEquals(100, view.getNewMembers(copy).size()); |
| } |
| |
| @Test |
| public void testNullPublicKeysNotRetained() throws Exception { |
| GMSMembershipView view = new GMSMembershipView(members.get(0), 2, new ArrayList<>(members)); |
| setFailureDetectionPorts(view); |
| |
| GMSMembershipView newView = new GMSMembershipView(view, 3); |
| for (MemberIdentifier member : view.getMembers()) { |
| view.setPublicKey((MemberIdentifier) member, null); |
| } |
| newView.setPublicKeys(view); |
| for (MemberIdentifier member : view.getMembers()) { |
| assertNull(newView.getPublicKey((MemberIdentifier) member)); |
| assertNull(view.getPublicKey((MemberIdentifier) member)); |
| } |
| } |
| |
| /** |
| * Test that failed weight calculations are correctly performed. See bug #47342 |
| */ |
| @Test |
| public void testFailedWeight() throws Exception { |
| // in #47342 a new view was created that contained a member that was joining but |
| // was no longer reachable. The member was included in the failed-weight and not |
| // in the previous view-weight, causing a spurious network partition to be declared |
| MemberIdentifier members[] = |
| new MemberIdentifier[] { |
| new InternalDistributedMember("localhost", 1), |
| new InternalDistributedMember("localhost", 2), |
| new InternalDistributedMember("localhost", 3), |
| new InternalDistributedMember("localhost", 4), |
| new InternalDistributedMember("localhost", 5), |
| new InternalDistributedMember("localhost", 6)}; |
| int i = 0; |
| // weight 3 |
| members[i].setVmKind(ClusterDistributionManager.LOCATOR_DM_TYPE); |
| members[i++].setPreferredForCoordinator(true); |
| // weight 3 |
| members[i].setVmKind(ClusterDistributionManager.LOCATOR_DM_TYPE); |
| members[i++].setPreferredForCoordinator(true); |
| // weight 15 (cache+leader) |
| members[i].setVmKind(ClusterDistributionManager.NORMAL_DM_TYPE); |
| members[i++].setPreferredForCoordinator(false); |
| // weight 0 |
| members[i].setVmKind(ClusterDistributionManager.ADMIN_ONLY_DM_TYPE); |
| members[i++].setPreferredForCoordinator(false); |
| // weight 0 |
| members[i].setVmKind(ClusterDistributionManager.ADMIN_ONLY_DM_TYPE); |
| members[i++].setPreferredForCoordinator(false); |
| // weight 10 |
| members[i].setVmKind(ClusterDistributionManager.NORMAL_DM_TYPE); |
| members[i++].setPreferredForCoordinator(false); |
| |
| List<MemberIdentifier> vmbrs = new ArrayList<>(members.length); |
| for (i = 0; i < members.length; i++) { |
| vmbrs.add(members[i]); |
| } |
| GMSMembershipView lastView = |
| new GMSMembershipView((MemberIdentifier) members[0], 4, |
| (List<MemberIdentifier>) (List<?>) vmbrs); |
| MemberIdentifier leader = (MemberIdentifier) members[2]; |
| assertTrue(!leader.preferredForCoordinator()); |
| |
| MemberIdentifier joiningMember = new InternalDistributedMember("localhost", 7); |
| joiningMember.setVmKind(ClusterDistributionManager.NORMAL_DM_TYPE); |
| joiningMember.setPreferredForCoordinator(false); |
| |
| // have the joining member and another cache process (weight 10) in the failed members |
| // collection and check to make sure that the joining member is not included in failed |
| // weight calcs. |
| Set<MemberIdentifier> failedMembers = new HashSet<>(3); |
| failedMembers.add(joiningMember); |
| failedMembers.add(members[members.length - 1]); // cache |
| failedMembers.add(members[members.length - 2]); // admin |
| List<MemberIdentifier> newMbrs = |
| new ArrayList<>(lastView.getGMSMembers()); |
| newMbrs.removeAll(failedMembers); |
| GMSMembershipView newView = |
| new GMSMembershipView(members[0], 5, (List<MemberIdentifier>) (List<?>) newMbrs, |
| Collections.emptySet(), (Set<MemberIdentifier>) (Set<?>) failedMembers); |
| |
| int failedWeight = newView.getCrashedMemberWeight(lastView); |
| // System.out.println("last view = " + lastView); |
| // System.out.println("failed mbrs = " + failedMembers); |
| // System.out.println("failed weight = " + failedWeight); |
| assertEquals("failure weight calculation is incorrect", 10, failedWeight); |
| Set<MemberIdentifier> actual = newView.getActualCrashedMembers(lastView); |
| assertTrue(!actual.contains(members[members.length - 2])); |
| } |
| } |