All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.gitee.yanfanvip.replicate.AcrossClusterDispatch Maven / Gradle / Ivy

The newest version!
package com.gitee.yanfanvip.replicate;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
import org.jgroups.annotations.MBean;
import org.jgroups.stack.Protocol;
import org.jgroups.util.Util;
import org.rocksdb.RocksDBException;

import com.gitee.yanfanvip.cluster.ClusterDatabase;
import com.gitee.yanfanvip.cluster.ClusterDatabase.Notification;
import com.gitee.yanfanvip.model.Frame;
import com.gitee.yanfanvip.model.FrameEnum;
import com.gitee.yanfanvip.model.ReciveEnum;
import com.gitee.yanfanvip.model.Row;
import com.gitee.yanfanvip.single.SingleDatabase;

@MBean(description="Server side PULL Database protocol, STOMP clients can connect to it")
public class AcrossClusterDispatch extends Protocol implements Notification{

	protected List sites = new ArrayList();
	protected ClusterDatabase database;
	protected SingleDatabase SYSTEM;
	protected String cluster;
	
	public AcrossClusterDispatch(String cluster) {
		this.cluster = cluster;
	}
	
	@Override
	public void start() throws Exception {
		database = getProtocolStack().findProtocol(ClusterDatabase.class);
		SYSTEM = SingleDatabase.getSystem();
		database.setListener(this);
		sites.forEach(site->{
			Thread thread = getThreadFactory().newThread(site, "Across Cluster Producer connection");
            thread.setDaemon(true);
            thread.start();
		});
		 new Timer().schedule(new TimerTask() {
			@Override
			public void run() {
				sites.forEach(site->{ 
					try { site.send(new Frame(FrameEnum.PING)); } catch (Exception e) { } 
				});
			}
		 }, 30000);
	}
	
	public AcrossClusterDispatch addSite(String cluster, String nodes) {
		if(!cluster.equals(this.cluster)) { 
			sites.add(new Site(cluster, nodes)); 
		}
        return this;
	}
	
	private void handleFailMessage(String cluster, long sequence, Frame frame){
		if(frame.getType() == FrameEnum.PUT ||
				frame.getType() == FrameEnum.PUTALL ||
				frame.getType() == FrameEnum.REMOVE ||
				frame.getType() == FrameEnum.CLEAR){
			try {
				SYSTEM.put("MESSAGE:" + cluster, sequence + "", frame.getByte());
			} catch (RocksDBException e) {
				e.printStackTrace();
			}
		}
	}
	
	private void handleSequenceMessage(String cluster, Consumer consumer){
		try {
			SYSTEM.forEach("MESSAGE:" + cluster, (k, v)->{
				Frame frame = new Frame(v);
				try { SYSTEM.remove("MESSAGE:" + cluster, k); } catch (RocksDBException e) { e.printStackTrace(); }
				consumer.accept(frame);
			});
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public void put(String keyspaces, String key, byte[] value) {
		sites.forEach(site->{
			site.send(FrameEnum.PUT, new Row(keyspaces, key, value));
		});
	}

	@Override
	public void putAll(String keyspaces, Map datas) {
		sites.forEach(site->{
			site.send(FrameEnum.PUTALL, new Row(keyspaces, datas));
		});
	}

	@Override
	public void remove(String keyspaces, String key) {
		sites.forEach(site->{
			site.send(FrameEnum.REMOVE, new Row(keyspaces, key));
		});
	}

	@Override
	public void clear(String keyspaces) {
		sites.forEach(site->{
			site.send(FrameEnum.CLEAR, new Row(keyspaces));
		});
	}
	
	/**
	 * 负责发送响应消息给需要同步的服务器
	 * @author fy68
	 */
	public class Site implements Runnable, AutoCloseable{
		String cluster;
		Socket socket;
		DataInputStream input;
		DataOutputStream output;
		List server;
		boolean connected = false;
		protected Long sequence;
		Lock lock = new ReentrantLock();
		
		long getSequence(){
			try {
				if(sequence == null){
					Row row = SYSTEM.getLastData("MESSAGE:" + cluster);
					if(row == null){
						sequence = 0L;
					}else{
						sequence = Long.valueOf(row.getKey());
					}
				}
				sequence++;
			} catch (Exception e) {
				if(sequence == null){ sequence = 0L; }
				sequence++;
			}
			return sequence;
		}
		
		public Site(String cluster, String node) {
			this.cluster = cluster;
			String[] nodes = node.split(",");
			this.server = Arrays.asList(nodes);
		}

		@Override
		public void run() {
			while(true){
				connect();
				read();
			}
		}
		
		private void read() {
			try {
				while(connected){
					ReciveEnum enum1 = ReciveEnum.get(input);
	                if(enum1 != null) {
	                	switch (enum1) {
		                	case PING: break;
		                	case PULLDATA:{
		                		handleSequenceMessage(cluster, f->{ send(f.getType(), f.getData()); });
		                		send(new Frame(FrameEnum.PULL_MESSAGE_COMPLETE));
		                		break;
		                	}
		                	case SYNC:{
		                		send(new Frame(FrameEnum.SYNC_START));
		                		database.forEach(data->{
		                			try {
										send(new Frame(FrameEnum.PUT, data));
									} catch (Exception e) {
										throw new RuntimeException(e);
									}
		                		});
		                		send(new Frame(FrameEnum.SYNC_COMPLETE));
		                		break;
		                	}
							default:throw new RuntimeException("bad request");
						}
	                }
				}
            } catch (Exception e) {
            	System.out.println("dispatch close");
            	disconnect();
			}
		}
		
		void connect() {
			if(socket == null){ disconnect(); }
			while(!connected){
				for (String address : server) {
		        	int index = address.lastIndexOf(':');
			        String host = address.substring(0, index);
			        int port = Integer.parseInt(address.substring(index+1));
		            try {
		            	socket = new Socket(host, port);
		            	input = new DataInputStream(socket.getInputStream());
		    	        output =new DataOutputStream(socket.getOutputStream());
		    	        send(new Frame(FrameEnum.PING));
		    	        connected = true;
		                break;
		            } catch(Exception ex) {
		            	disconnect();
		            }
		        }
				if(!connected){ try { Thread.sleep(30000); } catch (InterruptedException e) { }}
			}
	    }
		
		public void send(FrameEnum type, Row row) {
			Frame frame = new Frame(type, row);
			if(!connected){
				handleFailMessage(cluster, getSequence(), frame);
				return;
			}
			try { send(frame); } catch (Exception e) { handleFailMessage(cluster, getSequence(), frame); }
		}
		
		private void send(Frame frame) throws Exception {
			lock.lock();
			try {
				output.write(frame.getByte());
				output.flush();
			} catch (Exception e) {
				disconnect();
				throw e;
			}finally {
				lock.unlock();
			}
		}
		
		private void disconnect() {
			connected = false;
			Util.close(input);
			Util.close(output);
			Util.close(socket);
		}
		
		@Override
		public void close() {
			disconnect();
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy