/*
* Copyright (c) 2008-2012, Hazel Bilisim Ltd. All Rights Reserved.
*
* Licensed 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 com.hazelcast.impl;
import com.hazelcast.cluster.JoinInfo;
import com.hazelcast.config.Config;
import com.hazelcast.core.Member;
import com.hazelcast.impl.base.SystemLogService;
import com.hazelcast.logging.ILogger;
import com.hazelcast.nio.Address;
import com.hazelcast.nio.Connection;
import java.util.Collection;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
public abstract class AbstractJoiner implements Joiner {
private final long joinStartTime = System.currentTimeMillis();
protected final Config config;
protected final Node node;
protected volatile ILogger logger;
private final AtomicInteger tryCount = new AtomicInteger(0);
protected final SystemLogService systemLogService;
public AbstractJoiner(Node node) {
this.node = node;
this.systemLogService = node.getSystemLogService();
if (node.loggingService != null) {
this.logger = node.loggingService.getLogger(this.getClass().getName());
}
this.config = node.config;
}
public abstract void doJoin(AtomicBoolean joined);
public void join(AtomicBoolean joined) {
doJoin(joined);
postJoin();
}
private void postJoin() {
systemLogService.logJoin("PostJoin master:" + node.getMasterAddress() + ", isMaster " + node.isMaster());
if (!node.isActive()) {
return;
}
if (tryCount.incrementAndGet() == 5) {
node.setAsMaster();
}
if (!node.isMaster()) {
boolean allConnected = false;
int checkCount = 0;
long maxJoinMillis = node.getGroupProperties().MAX_JOIN_SECONDS.getInteger() * 1000;
if (node.joined()) {
systemLogService.logJoin("Waiting for all connections");
while (checkCount++ < node.groupProperties.CONNECT_ALL_WAIT_SECONDS.getInteger() && !allConnected) {
try {
//noinspection BusyWait
Thread.sleep(1000);
} catch (InterruptedException ignored) {
}
Set<Member> members = node.getClusterImpl().getMembers();
allConnected = true;
for (Member member : members) {
MemberImpl memberImpl = (MemberImpl) member;
if (!memberImpl.localMember() && node.connectionManager.getConnection(memberImpl.getAddress()) == null) {
allConnected = false;
systemLogService.logJoin("Not-connected to " + memberImpl.getAddress());
}
}
}
}
if (!node.joined() || !allConnected) {
if (System.currentTimeMillis() - joinStartTime < maxJoinMillis) {
logger.log(Level.WARNING, "Failed to connect, node joined= " + node.joined() + ", allConnected= " + allConnected + " to all other members after " + checkCount + " seconds.");
logger.log(Level.WARNING, "Rebooting after 10 seconds.");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
node.shutdown(false, true);
}
node.rejoin();
} else {
throw new RuntimeException("Failed to join in " + (maxJoinMillis / 1000) + " seconds!");
}
return;
} else {
node.clusterManager.finalizeJoin();
}
}
node.clusterManager.enqueueAndWait(new Processable() {
public void process() {
if (node.baseVariables.lsMembers.size() == 1) {
final StringBuilder sb = new StringBuilder();
sb.append("\n");
sb.append(node.clusterManager);
logger.log(Level.INFO, sb.toString());
}
}
}, 5);
}
protected void failedJoiningToMaster(boolean multicast, int tryCount) {
StringBuilder sb = new StringBuilder();
sb.append("\n");
sb.append("===========================");
sb.append("\n");
sb.append("Couldn't connect to discovered master! tryCount: ").append(tryCount);
sb.append("\n");
sb.append("address: ").append(node.address);
sb.append("\n");
sb.append("masterAddress: ").append(node.getMasterAddress());
sb.append("\n");
sb.append("multicast: ").append(multicast);
sb.append("\n");
sb.append("connection: ").append(node.connectionManager.getConnection(node.getMasterAddress()));
sb.append("===========================");
sb.append("\n");
throw new IllegalStateException(sb.toString());
}
boolean shouldMerge(JoinInfo joinInfo) {
boolean shouldMerge = false;
if (joinInfo != null) {
boolean validJoinRequest;
try {
try {
validJoinRequest = node.validateJoinRequest(joinInfo);
} catch (Exception e) {
validJoinRequest = false;
}
if (validJoinRequest) {
for (Member member : node.getClusterImpl().getMembers()) {
MemberImpl memberImpl = (MemberImpl) member;
if (memberImpl.getAddress().equals(joinInfo.address)) {
return false;
}
}
int currentMemberCount = node.getClusterImpl().getMembers().size();
if (joinInfo.getMemberCount() > currentMemberCount) {
// I should join the other cluster
logger.log(Level.FINEST, node.address + "Merging because : joinInfo.getMemberCount() > currentMemberCount" + joinInfo + ", this node member count: " + node.getClusterImpl().getMembers().size());
shouldMerge = true;
} else if (joinInfo.getMemberCount() == currentMemberCount) {
// compare the hashes
if (node.getThisAddress().hashCode() > joinInfo.address.hashCode()) {
logger.log(Level.FINEST, node.address + "Merging because : node.getThisAddress().hashCode() > joinInfo.address.hashCode()" + joinInfo + ", this node member count: " + node.getClusterImpl().getMembers().size());
shouldMerge = true;
}
}
}
} catch (Throwable e) {
logger.log(Level.SEVERE, e.getMessage(), e);
return false;
}
}
return shouldMerge;
}
protected void connectAndSendJoinRequest(Collection<Address> colPossibleAddresses) {
if (node.getFailedConnections().size() > 0)
for (Address possibleAddress : colPossibleAddresses) {
final Connection conn = node.connectionManager.getOrConnect(possibleAddress);
if (conn != null) {
logger.log(Level.FINEST, "sending join request for " + possibleAddress);
node.clusterManager.sendJoinRequest(possibleAddress, true);
}
}
}
}