package io.teknek.nibiru.plugins; import java.io.IOException; import java.util.List; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicLong; import java.util.SortedMap; import org.codehaus.jackson.map.ObjectMapper; import io.teknek.nibiru.Destination; import io.teknek.nibiru.Server; import io.teknek.nibiru.client.Client; import io.teknek.nibiru.cluster.ClusterMember; import io.teknek.nibiru.coordinator.Coordinator; import io.teknek.nibiru.engine.atom.AtomKey; import io.teknek.nibiru.engine.atom.AtomValue; import io.teknek.nibiru.engine.atom.ColumnKey; import io.teknek.nibiru.engine.atom.ColumnValue; import io.teknek.nibiru.personality.ColumnFamilyPersonality; import io.teknek.nibiru.transport.BaseMessage; public class HintReplayer extends AbstractPlugin implements Runnable { ObjectMapper om = new ObjectMapper(); public static final String MY_NAME = "hint_replayer"; private volatile boolean goOn = true; private Thread runThread; private ColumnFamilyPersonality hintCf; private final AtomicLong hintsDelivered = new AtomicLong(); private final AtomicLong hintsFailed = new AtomicLong(); private ConcurrentMap<Destination,Client> mapping; public HintReplayer(Server server) { super(server); } @Override public String getName() { return MY_NAME; } @Override public void init() { mapping = new ConcurrentHashMap<>(); hintCf = Coordinator.getHintCf(server); runThread = new Thread(this); runThread.start(); } @Override public void shutdown() { goOn = false; } //this is copied from eventual coordinator private Client clientForDestination(Destination destination){ Client client = mapping.get(destination); if (client != null) { return client; } for (ClusterMember cm : server.getClusterMembership().getLiveMembers()){ if (cm.getId().equals(destination.getDestinationId())){ Client cc = new Client(cm.getHost(), server.getConfiguration().getTransportPort(),10000,10000); mapping.putIfAbsent(destination, cc); return cc; } } for (ClusterMember cm : server.getClusterMembership().getDeadMembers()){ if (cm.getId().equals(destination.getDestinationId())){ Client cc = new Client(cm.getHost(), server.getConfiguration().getTransportPort(),10000,10000); mapping.putIfAbsent(destination, cc); return cc; } } throw new RuntimeException(String.format( "destination %s does not exist. Live members %s. Dead members %s", destination.getDestinationId(), server.getClusterMembership().getLiveMembers(), server.getClusterMembership().getDeadMembers())); } @Override public void run() { while (goOn){ List<ClusterMember> live = server.getClusterMembership().getLiveMembers(); for (ClusterMember member : live){ SortedMap<AtomKey,AtomValue> results = hintCf.slice(member.getId(), "", "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"); if (results.size() > 0){ for (Entry<AtomKey, AtomValue> i : results.entrySet()){ if (i.getValue() instanceof ColumnValue){ ColumnValue v = (ColumnValue) i.getValue(); ColumnKey c = (ColumnKey) i.getKey(); writeAndDelete(member, c, v); } } } } try { Thread.sleep(1); } catch (InterruptedException e) { } } } private void writeAndDelete(ClusterMember m, ColumnKey c, ColumnValue v){ Destination d = new Destination(); d.setDestinationId(m.getId()); Client client = this.clientForDestination(d); try { client.post( om.readValue(v.getValue(), BaseMessage.class)); hintCf.delete(m.getId(), c.getColumn(), System.currentTimeMillis() * 1000); hintsDelivered.getAndIncrement(); } catch ( IOException | RuntimeException e) { try { Thread.sleep(10); } catch (InterruptedException e1) { } hintsFailed.getAndIncrement(); } } public long getHintsDelivered() { return hintsDelivered.get(); } public long getHintsFailed() { return hintsFailed.get(); } }