in geode-membership/src/main/java/org/apache/geode/distributed/internal/membership/gms/membership/GMSJoinLeave.java [2444:2588]
void createAndSendView(List<AbstractGMSMessage<ID>> requests)
throws InterruptedException, ViewAbandonedException {
List<ID> joinReqs = new ArrayList<>(10);
Map<ID, Integer> joinPorts = new HashMap<>(10);
Set<ID> leaveReqs = new HashSet<>(10);
List<ID> removalReqs = new ArrayList<>(10);
List<String> removalReasons = new ArrayList<>(10);
GMSMembershipView<ID> oldView = currentView;
List<ID> oldMembers;
if (oldView != null) {
oldMembers = new ArrayList<>(oldView.getMembers());
} else {
oldMembers = Collections.emptyList();
}
Set<ID> oldIDs = new HashSet<>();
for (AbstractGMSMessage<ID> msg : requests) {
logger.debug("processing request {}", msg);
ID mbr;
switch (msg.getDSFID()) {
case JOIN_REQUEST:
JoinRequestMessage<ID> jmsg = (JoinRequestMessage<ID>) msg;
mbr = jmsg.getMemberID();
int port = jmsg.getFailureDetectionPort();
if (!joinReqs.contains(mbr)) {
if (mbr.getVmViewId() >= 0 && oldMembers.contains(mbr)) {
// already joined in a previous view
logger.info("Ignoring join request from member {} who has already joined", mbr);
} else {
joinReqs.add(mbr);
joinPorts.put(mbr, port);
if (services.getConfig().isUDPSecurityEnabled() ||
services.getConfig().isMulticastEnabled()) {
// send a join response so the new member can get the multicast messaging digest
// and cluster key
JoinResponseMessage<ID> response = new JoinResponseMessage<>(jmsg.getSender(),
services.getMessenger().getClusterSecretKey(), jmsg.getRequestId());
services.getMessenger().send(response);
}
}
}
break;
case LEAVE_REQUEST_MESSAGE:
mbr = ((LeaveRequestMessage<ID>) msg).getMemberID();
if (oldMembers.contains(mbr)) {
leaveReqs.add(mbr);
}
break;
case REMOVE_MEMBER_REQUEST:
// process these after gathering all leave-requests so that
// we don't kick out a member that's shutting down
break;
default:
logger.warn("Unknown membership request encountered: {}", msg);
break;
}
}
for (AbstractGMSMessage<ID> msg : requests) {
switch (msg.getDSFID()) {
case REMOVE_MEMBER_REQUEST:
ID mbr = ((RemoveMemberMessage<ID>) msg).getMemberID();
if (!leaveReqs.contains(mbr)) {
if (oldMembers.contains(mbr) && !removalReqs.contains(mbr)) {
removalReqs.add(mbr);
removalReasons.add(((RemoveMemberMessage<ID>) msg).getReason());
} else {
// unknown, probably rogue, process - send it a removal message
sendRemoveMessages(Collections.singletonList(mbr),
Collections.singletonList(((RemoveMemberMessage<ID>) msg).getReason()),
new HashSet<>());
}
}
break;
default:
break;
}
}
for (ID mbr : oldIDs) {
if (!leaveReqs.contains(mbr) && !removalReqs.contains(mbr)) {
removalReqs.add(mbr);
removalReasons.add("Removal of old ID that has been reused");
}
}
if (removalReqs.isEmpty() && leaveReqs.isEmpty() && joinReqs.isEmpty()) {
return;
}
GMSMembershipView<ID> newView;
synchronized (viewInstallationLock) {
int viewNumber = 0;
List<ID> mbrs;
if (currentView == null) {
mbrs = new ArrayList<>();
} else {
viewNumber = currentView.getViewId() + 1;
mbrs = new ArrayList<>(oldMembers);
}
mbrs.removeAll(leaveReqs);
mbrs.removeAll(removalReqs);
// add joinReqs after removing old members because an ID may
// be reused in an auto-reconnect and get a new vmViewID
mbrs.addAll(joinReqs);
newView = new GMSMembershipView<>(localAddress, viewNumber, mbrs, leaveReqs,
new HashSet<>(removalReqs));
for (ID mbr : joinReqs) {
if (mbrs.contains(mbr)) {
newView.setFailureDetectionPort(mbr, joinPorts.get(mbr));
}
}
if (currentView != null) {
newView.setFailureDetectionPorts(currentView);
newView.setPublicKeys(currentView);
}
}
// if there are no membership changes then abort creation of
// the new view
if (joinReqs.isEmpty() && newView.getMembers().equals(currentView.getMembers())) {
logger.info("membership hasn't changed - aborting new view {}", newView);
return;
}
for (ID mbr : joinReqs) {
if (mbr.getVmViewId() < 0) {
mbr.setVmViewId(newView.getViewId());
}
}
if (isShutdown()) {
return;
}
// send removal messages before installing the view so we stop
// getting messages from members that have been kicked out
sendRemoveMessages(removalReqs, removalReasons, oldIDs);
prepareAndSendView(newView, joinReqs, leaveReqs, newView.getCrashedMembers());
return;
}