/*
* 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 org.rakam.kume.join.multicast;
import org.rakam.kume.Cluster;
import org.rakam.kume.ClusterCheckAndMergeOperation;
import org.rakam.kume.ClusterMembership;
import org.rakam.kume.JoinerService;
import org.rakam.kume.Member;
import org.rakam.kume.ServiceContext;
import org.rakam.kume.transport.Request;
import com.google.common.base.Throwables;
import com.google.common.cache.CacheBuilder;
import io.netty.channel.nio.NioEventLoopGroup;
import org.rakam.kume.MemberState;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.InetSocketAddress;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
public class MulticastJoinerService implements JoinerService
{
final static Logger LOGGER = LoggerFactory.getLogger(Cluster.class);
private final MulticastServerHandler multicastServer;
private final Cluster cluster;
private final Member localMember;
NioEventLoopGroup workerGroup = new NioEventLoopGroup(1);
private AtomicInteger currentTerm;
private long lastContactedTimeMaster;
private Member master;
final private Map<Member, Long> heartbeatMap = new ConcurrentHashMap<>();
private ScheduledFuture<?> heartbeatTask;
private ConcurrentMap<InetSocketAddress, Integer> pendingUserVotes = CacheBuilder.newBuilder().expireAfterWrite(100, TimeUnit.SECONDS).<InetSocketAddress, Integer>build().asMap();
private MemberState memberState;
private Map<Long, Request> pendingConsensusMessages = new ConcurrentHashMap<>();
private AtomicLong lastCommitIndex = new AtomicLong();
public MulticastJoinerService(ServiceContext ctx) {
cluster = ctx.getCluster();
localMember = cluster.getLocalMember();
InetSocketAddress multicastAddress = new InetSocketAddress("224.0.67.67", 5001);
try {
multicastServer = new MulticastServerHandler(ctx.getCluster(), multicastAddress)
.start();
} catch (InterruptedException e) {
throw new IllegalStateException("Failed to bind UDP " + multicastAddress);
}
LOGGER.info("{} started , listening UDP multicast server {}", localMember, multicastAddress);
multicastServer.setAutoRead(true);
}
private synchronized void changeMaster(Member masterMember) {
master = masterMember;
memberState = masterMember.equals(localMember) ? MemberState.MASTER : MemberState.FOLLOWER;
multicastServer.setJoinGroup(memberState == MemberState.MASTER);
}
public MemberState memberState() {
return memberState;
}
public synchronized void removeMemberAsMaster(Member member, boolean replicate) {
// if (!isMaster())
// throw new IllegalStateException();
// heartbeatMap.remove(member);
// members.remove(member);
// if(replicate) {
// internalBus.sendAllMembers((cluster, ctx) -> {
// cluster.clusterConnection.remove(member);
// Cluster.LOGGER.info("Member removed {}", member);
// cluster.membershipListeners.forEach(l -> Throwables.propagate(() -> l.memberRemoved(member)));
// }, true);
// }
}
// workerGroup.scheduleWithFixedDelay(() -> {
// ClusterCheckAndMergeOperation req = new ClusterCheckAndMergeOperation();
// multicastServer.sendMulticast(req);
// }, 0, 2000, TimeUnit.MILLISECONDS);
public void joinCluster() {
multicastServer.sendMulticast(new ClusterCheckAndMergeOperation());
}
protected synchronized void changeCluster(Set<Member> newClusterMembers, Member masterMember, boolean isNew) {
// try {
// pause();
// clusterConnection.clear();
// master = masterMember;
// members = newClusterMembers;
// messageHandlers.cleanUp();
// LOGGER.info("Joined a cluster of {} nodes.", members.size());
// multicastServer.setJoinGroup(masterMember.equals(localMember));
// if (!isNew)
// membershipListeners.forEach(x -> eventLoop.execute(() -> x.clusterChanged()));
// } finally {
// resume();
// }
}
@Override
public void onClose() {
heartbeatTask.cancel(true);
try {
multicastServer.close();
} catch (InterruptedException e) {
throw Throwables.propagate(e);
}
}
@Override
public void onStart(ClusterMembership membership) {
}
}