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

com.xxdb.DBConnection Maven / Gradle / Ivy

There is a newer version: 3.00.2.2
Show newest version
package com.xxdb;

import java.io.*;
import java.net.*;
import java.security.PublicKey;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;
import java.util.regex.Pattern;
import com.xxdb.comm.SqlStdEnum;
import com.xxdb.data.*;
import com.xxdb.data.Void;
import com.xxdb.io.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

/**
 * Sets up a connection to DolphinDB server through TCP/IP protocol
 * Executes DolphinDB scripts
 * 

* Example: *

* import com.xxdb; * DBConnection conn = new DBConnection(); * boolean success = conn.connect("localhost", 8080); * conn.run("sum(1..100)"); */ public class DBConnection { private static final int MAX_FORM_VALUE = Entity.DATA_FORM.values().length - 1; private static final int MAX_TYPE_VALUE = Entity.DATA_TYPE.DT_DECIMAL128_ARRAY.getValue(); private static final int DEFAULT_PRIORITY = 4; private static final int DEFAULT_PARALLELISM = 64; private ReentrantLock mutex_; private DBConnectionImpl conn_; private String uid_; private String pwd_; private String initialScript_ = null; private boolean enableHighAvailability_; private List nodes_ = new ArrayList<>(); private Random nodeRandom_ = new Random(); private int connTimeout_ = 0; private int connectTimeout_ = 0; private int readTimeout_ = 0; private boolean closed_ = false; private boolean loadBalance_ = false; private String runClientId_ = null; private long runSeqNo_ = 0; private int[] serverVersion_; private boolean isReverseStreaming_ = false; private int tryReconnectNums = -1; private static final Logger log = LoggerFactory.getLogger(DBConnection.class); private enum ExceptionType{ ET_IGNORE(0), ET_UNKNOW(1), ET_NEWLEADER(2), ET_NODENOTAVAIL(3), ET_NOINITIALIZED(4), ET_NOTLEADER(5), ET_READTIMEDOUT(6), ET_NORESPONSEHEADER(7); public int value; ExceptionType(int value){ this.value = value; } } private static class Node { private String hostName; private int port; private double load = -1.0; public Node(){ this.load = -1.0; } public Node(String hostName, int port, double load){ this.hostName = hostName; this.port = port; this.load = load; } public Node(String hostName, int port){ this.hostName = hostName; this.port = port; this.load = -1.0; } public Node(String ipPort){ String[] v = ipPort.split(":"); if (v.length < 2){ throw new RuntimeException("The ipPort '" + ipPort + "' is invalid."); } this.hostName = v[0]; this.port = Integer.parseInt(v[1]); this.load = -1.0; } @Override public boolean equals(Object o){ if(o instanceof Node) { Node node = (Node) o; if(node.hostName==null||hostName==null) return false; int diff = hostName.compareTo(node.hostName); if (diff != 0) return false; return port == node.port; }else{ return false; } } } enum Property{ flag,//1 cancel,//2 priority,//3 parallelism,//4 jobId,//5 fetchSize,//6 offset,//7 clientId,//8 seqNo,//9 } private class DBConnectionImpl{ private Socket socket_; private String sessionID_; private String hostName_; private int port_; private String userId_; private String pwd_; private boolean encrypted_ = true; private boolean isConnected_; private boolean sslEnable_ = false; private boolean asynTask_ = false; private boolean compress_ = false; private boolean ifUrgent_ = false; private int connTimeout_ = 0; private int connectTimeout_ = 0; private int readTimeout_ = 0; private ExtendedDataInput in_; private ExtendedDataOutput out_; private boolean remoteLittleEndian_; private ReentrantLock lock_; private boolean isReverseStreaming_ = false; private boolean python_ = false; private SqlStdEnum sqlStd_; private DBConnectionImpl(boolean asynTask, boolean sslEnable, boolean compress, boolean python, boolean ifUrgent, boolean isReverseStreaming, SqlStdEnum sqlStd){ sessionID_ = ""; this.sslEnable_ = sslEnable; this.asynTask_ = asynTask; this.compress_ = compress; this.ifUrgent_ = ifUrgent; this.python_ = python; this.isReverseStreaming_ = isReverseStreaming; this.sqlStd_ = sqlStd; this.lock_ = new ReentrantLock(); } private boolean connect(String hostName, int port, String userId, String password, int connTimeout, int connectTimeout, int readTimeout) throws IOException{ this.hostName_ = hostName; this.port_ = port; this.userId_ = userId; this.pwd_ = password; this.connTimeout_ = connTimeout; this.connectTimeout_ = connectTimeout; this.readTimeout_ = readTimeout; return connect(); } private boolean connect() throws IOException { this.isConnected_ = false; try { if (sslEnable_) socket_ = getSSLSocketFactory().createSocket(); else socket_ = new Socket(); // set 'connectTimeout' param to connect() if (this.connTimeout_ > 0 && this.connectTimeout_ == 0) socket_.connect(new InetSocketAddress(hostName_, port_), connTimeout_); else if (this.connTimeout_ > 0 && this.connectTimeout_ > 0) socket_.connect(new InetSocketAddress(hostName_, port_), connectTimeout_); else if (this.connTimeout_ == 0 && this.connectTimeout_ > 0) socket_.connect(new InetSocketAddress(hostName_, port_), connectTimeout_); else if (this.connTimeout_ == 0 && this.connectTimeout_ == 0) socket_.connect(new InetSocketAddress(hostName_, port_), 3000); } catch (IOException ex) { log.error("Connect to " + this.hostName_ + ":" + this.port_ + " failed."); throw ex; } // set 'readTimeout' param to setSoTimeout if (this.connTimeout_ > 0 && this.readTimeout_ == 0) socket_.setSoTimeout(this.connTimeout_); else if (this.connTimeout_ > 0 && this.readTimeout_ > 0) socket_.setSoTimeout(this.readTimeout_); else if (this.connTimeout_ == 0 && this.readTimeout_ > 0) socket_.setSoTimeout(this.readTimeout_); socket_.setKeepAlive(true); socket_.setTcpNoDelay(true); out_ = new LittleEndianDataOutputStream(new BufferedOutputStream(socket_.getOutputStream())); in_ = new LittleEndianDataInputStream(new BufferedInputStream(socket_.getInputStream())); String body = "connect\n"; out_.writeBytes("API 0 "); out_.writeBytes(String.valueOf(body.length())); int flag = generateRequestFlag(false); out_.writeBytes(" / " + String.valueOf(flag) + "_1_" + String.valueOf(4) + "_" + String.valueOf(2)); out_.writeByte('\n'); out_.writeBytes(body); out_.flush(); String line = in_.readLine(); int endPos = line.indexOf(' '); if (endPos <= 0) { close(); return false; } sessionID_ = line.substring(0, endPos); int startPos = endPos + 1; endPos = line.indexOf(' ', startPos); if (endPos != line.length() - 2) { close(); return false; } String msg = in_.readLine(); isConnected_ = true; if (line.charAt(endPos + 1) == '0') { remoteLittleEndian_ = false; out_ = new BigEndianDataOutputStream(new BufferedOutputStream(socket_.getOutputStream())); } else remoteLittleEndian_ = true; if (!userId_.isEmpty() && !pwd_.isEmpty()) { if (asynTask_) { login(userId_, pwd_, false); } else { login(); } } log.info("Connect to " + this.hostName_ + ":" + this.port_ + " successfully."); return true; } private int generateRequestFlag(boolean clearSessionMemory){ int flag = 0; if (this.ifUrgent_) flag += 1; if(this.asynTask_) flag += 4; if(clearSessionMemory) flag += 16; if(this.compress_) flag += 64; if (this.python_) flag += 2048; if (this.isReverseStreaming_) flag += 131072; if (Objects.nonNull(this.sqlStd_)) { flag += sqlStd_.getCode()<<19; } return flag; } private void login(String userId, String password, boolean enableEncryption) throws IOException { lock_.lock(); try { this.userId_ = userId; this.pwd_ = password; this.encrypted_ = enableEncryption; login(); } finally { lock_.unlock(); } } private void login() throws IOException { List args = new ArrayList<>(); if (encrypted_) { BasicString keyCode = (BasicString) run("getDynamicPublicKey", new ArrayList(),0); PublicKey key = RSAUtils.getPublicKey(keyCode.getString()); byte[] usr = RSAUtils.encryptByPublicKey(userId_.getBytes(), key); byte[] pass = RSAUtils.encryptByPublicKey(pwd_.getBytes(), key); args.add(new BasicString(Base64.getMimeEncoder().encodeToString(usr))); args.add(new BasicString(Base64.getMimeEncoder().encodeToString(pass))); args.add(new BasicBoolean(true)); } else { args.add(new BasicString(userId_)); args.add(new BasicString(pwd_)); } run("login", args, 0); } private Entity run(String script,long seqNum) throws IOException { List args = new ArrayList<>(); return run(script, "script", (ProgressListener)null, args, DEFAULT_PRIORITY, DEFAULT_PARALLELISM, 0, false, seqNum); } private Entity run(String script, ProgressListener listener,int priority, int parallelism, int fetchSize, boolean clearMemory, String tableName, long seqNum) throws IOException{ List args = new ArrayList<>(); return run(script, "script", listener, args, priority, parallelism, fetchSize, clearMemory, tableName,seqNum); } private Entity run(String function, List arguments,long seqNum) throws IOException { return run(function,"function", (ProgressListener)null, arguments, DEFAULT_PRIORITY, DEFAULT_PARALLELISM, 0, false, seqNum); } private Entity run(String function, String scriptType, List arguments,long seqNum)throws IOException{ return run(function, scriptType, (ProgressListener)null, arguments, DEFAULT_PRIORITY, DEFAULT_PARALLELISM, 0, false, seqNum); } private Entity run(String function, ProgressListener listener,List args, int priority, int parallelism, int fetchSize, boolean clearMemory,long seqNum) throws IOException{ return run(function, "function", listener, args, priority, parallelism, fetchSize, clearMemory,seqNum); } private Entity run(String script, String scriptType, ProgressListener listener, List args, int priority, int parallelism, int fetchSize, boolean clearMemory,long seqNum) throws IOException{ return run(script, scriptType, listener, args, priority, parallelism, fetchSize, clearMemory, "", seqNum); } //flag) + "_1_" + String.valueOf(priority) + "_" + String.valueOf(parallelism)); // if (fetchSize > 0) // out_.writeBytes("__" + String.valueOf(fetchSize private Entity run(String script, String scriptType, ProgressListener listener, List args, int priority, int parallelism, int fetchSize, boolean clearMemory, String tableName, long seqNum) throws IOException{ if (!isConnected_) throw new IOException("Couldn't send script/function to the remote host because the connection has been closed"); if (fetchSize > 0 && fetchSize < 8192) throw new IOException("fetchSize must be greater than 8192"); if (socket_ == null || !socket_.isConnected() || socket_.isClosed()) { if (sessionID_.isEmpty()) throw new IOException("Database connection is not established yet."); else { socket_ = new Socket(hostName_, port_); socket_.setKeepAlive(true); socket_.setTcpNoDelay(true); out_ = new LittleEndianDataOutputStream(new BufferedOutputStream(socket_.getOutputStream())); } } if (!tableName.equals("")){ script = tableName + "=" + script; run(script,0); BasicDictionary schema = (BasicDictionary) run(tableName + ".schema()",0); BasicTable colDefs = (BasicTable)schema.get(new BasicString("colDefs")); BasicStringVector colDefsName = (BasicStringVector)colDefs.getColumn("name"); BasicIntVector colDefsTypeInt = (BasicIntVector)colDefs.getColumn("typeInt"); int cols = colDefs.rows(); int rows = ((BasicInt) run("rows(" + tableName + ")",0)).getInt(); Map types2Index = new HashMap<>(); Map name2Index = new HashMap<>(); for (int i = 0; i < cols; i++){ types2Index.put(types2Index.size(), Entity.DATA_TYPE.valueOf(colDefsTypeInt.getInt(i))); name2Index.put(name2Index.size(), colDefsName.getString(i)); } return new BasicTableSchema(types2Index, name2Index, rows, cols, tableName,DBConnection.this); } StringBuilder body = new StringBuilder(); int argCount = args.size(); if (scriptType == "script") body.append("script\n" + script) ; else { body.append(scriptType + "\n" + script); body.append("\n" + String.valueOf(argCount)); body.append("\n"); body.append(remoteLittleEndian_ ? "1" : "0"); } try { out_.writeBytes((listener != null ? "API2 " : "API ") + sessionID_ + " "); out_.writeBytes(String.valueOf(AbstractExtendedDataOutputStream.getUTFlength(body.toString(), 0, 0))); int flag = generateRequestFlag(clearMemory); Map properties=new HashMap<>(); properties.put(Property.flag, flag); properties.put(Property.cancel,1); properties.put(Property.priority, priority); properties.put(Property.parallelism, parallelism); //String propInfo=" / " + String.valueOf(flag) + "_1_" + String.valueOf(priority) + "_" + String.valueOf(parallelism); //out_.writeBytes(" / " + String.valueOf(flag) + "_1_" + String.valueOf(priority) + "_" + String.valueOf(parallelism)); //if (fetchSize > 0) // out_.writeBytes("__" + String.valueOf(fetchSize)); //out_.writeByte('\n'); if (fetchSize > 0) properties.put(Property.fetchSize, fetchSize); if(enableHighAvailability_ && runClientId_ != null && seqNum != 0){ properties.put(Property.clientId, runClientId_); properties.put(Property.seqNo, seqNum); } {//write properties int lastNotNullValue = -1; StringBuilder sbProp = new StringBuilder(" / "); for (Property key : Property.values()) { Object value = properties.get(key); if (value != null) { sbProp.append(value); lastNotNullValue = sbProp.length(); } sbProp.append("_"); } sbProp.delete(lastNotNullValue, sbProp.length()); sbProp.append('\n'); out_.writeBytes(sbProp.toString()); } out_.writeBytes(body.toString()); if (argCount > 0){ for (int i = 0; i < args.size(); ++i) { if (compress_ && args.get(i).isTable()) { args.get(i).writeCompressed(out_); //TODO: which compress method to use } else args.get(i).write(out_); } out_.flush(); }else { out_.flush(); } }catch (IOException ex){ isConnected_ = false; socket_ = null; throw new IOException("Couldn't send script/function to the remote host because the connection has been closed"); } if (asynTask_) return null; String header = null; try { header = in_.readLine(); while (header.equals("MSG")) { //read intermediate message to indicate the progress String msg = in_.readString(); if (listener != null) listener.progress(msg); header = in_.readLine(); } }catch (IOException ex){ if (ex instanceof SocketTimeoutException) { // isConnected_ = true; throw ex; } else { isConnected_ = false; socket_ = null; throw new IOException("Failed to read response header from the socket with IO error " + ex.getMessage()); } } String[] headers = header.split(" "); if (headers.length != 3){ isConnected_ = false; socket_ = null; throw new IOException("Received invalid header"); } int numObject = Integer.parseInt(headers[1]); try { header = in_.readLine(); }catch (IOException ex){ isConnected_ = false; socket_ = null; throw new IOException("Failed to read response header from the socket with IO error " + ex.getMessage()); } if (!header.equals("OK")){ if (scriptType == "script") throw new IOException(hostName_+":"+port_+" Server response: " + header + ". script: " + script + ""); else throw new IOException(hostName_+":"+port_+" Server response: " + header + ". " + scriptType + ": " + script + ""); } if (numObject == 0){ return new Void(); } short flag; try { flag = in_.readShort(); int form = flag >> 8; int type = flag & 0xff; boolean extended = type >= 128; if(type >= 128) type -= 128; if (form < 0 || form > MAX_FORM_VALUE) throw new IOException("Invalid form value: " + form); if (type < 0 || type > MAX_TYPE_VALUE) throw new IOException("Invalid type value: " + type); Entity.DATA_FORM df = Entity.DATA_FORM.values()[form]; Entity.DATA_TYPE dt = Entity.DATA_TYPE.valueOf(type); if(fetchSize>0 && df == Entity.DATA_FORM.DF_VECTOR && dt == Entity.DATA_TYPE.DT_ANY){ return new EntityBlockReader(in_); } EntityFactory factory = BasicEntityFactory.instance(); return factory.createEntity(df, dt, in_, extended); }catch (IOException ex){ isConnected_ = false; socket_ = null; throw new IOException("Failed to read object flag from the socket with IO error type " + ex.getMessage()); } } public void upload(String name, Entity obj,long seqNum) throws IOException{ if (!Utils.isVariableCandidate(name)) throw new RuntimeException(name + " is not a qualified variable name."); List args = new ArrayList<>(); args.add(obj); run(name, "variable", args, seqNum); } public void upload(List names, List objs,long seqNum) throws IOException{ if (names.size() != objs.size()) throw new RuntimeException("the size of variable names doesn't match the size of objects."); if (names.isEmpty()) return; StringBuilder varNames = new StringBuilder(); for (int i = 0; i < names.size(); ++i){ if (!Utils.isVariableCandidate(names.get(i))) throw new RuntimeException(names.get(i) + " is not a qualified variable name."); if (i > 0) varNames.append(","); varNames.append(names.get(i)); } run(varNames.toString(), "variable", objs, seqNum); } public void close(){ lock_.lock(); try { if (socket_ != null){ socket_.close(); socket_ = null; sessionID_ = ""; } }catch (IOException ex){ ex.printStackTrace(); }finally { lock_.unlock(); } isConnected_ = false; } public boolean isConnected(){ return isConnected_; } public void getNode(Node node){ node.hostName = hostName_; node.port = port_; } public boolean getRemoteLittleEndian(){ return this.remoteLittleEndian_; } public ExtendedDataInput getDataInputStream() { return in_; } } private DBConnectionImpl createEnableReverseStreamingDBConnectionImpl(boolean asynTask, boolean sslEnable, boolean compress, boolean python, boolean ifUrgent, SqlStdEnum sqlStd) { return new DBConnectionImpl(asynTask, sslEnable, compress, python, ifUrgent, true, sqlStd); } public DBConnection() { this(false, false, false); } public DBConnection(SqlStdEnum sqlStd) { this(false, false, false, false, false, sqlStd); } public DBConnection(boolean asynchronousTask) { this(asynchronousTask, false, false); } public DBConnection(boolean asynchronousTask, boolean useSSL) { this(asynchronousTask, useSSL, false); } public DBConnection(boolean asynchronousTask, boolean useSSL, boolean compress) { this(asynchronousTask, useSSL, compress, false); } public DBConnection(boolean asynchronousTask, boolean useSSL, boolean compress, boolean usePython){ this.conn_ = new DBConnectionImpl(asynchronousTask, useSSL, compress, usePython, false, false, SqlStdEnum.DolphinDB); this.mutex_ = new ReentrantLock(); } public DBConnection(boolean asynchronousTask, boolean useSSL, boolean compress, boolean usePython, SqlStdEnum sqlStd){ this.conn_ = new DBConnectionImpl(asynchronousTask, useSSL, compress, usePython, false, false, sqlStd); this.mutex_ = new ReentrantLock(); } public DBConnection(boolean asynchronousTask, boolean useSSL, boolean compress, boolean usePython, boolean isUrgent){ this.conn_ = new DBConnectionImpl(asynchronousTask, useSSL, compress, usePython, isUrgent, false, SqlStdEnum.DolphinDB); this.mutex_ = new ReentrantLock(); } public DBConnection(boolean asynchronousTask, boolean useSSL, boolean compress, boolean usePython, boolean isUrgent, SqlStdEnum sqlStd){ this.conn_ = new DBConnectionImpl(asynchronousTask, useSSL, compress, usePython, isUrgent, false, sqlStd); this.mutex_ = new ReentrantLock(); } /** * This method has been deprecated since 'Java API 1.30.22.4'. * @param asynchronousTask * @param useSSL * @param compress * @param usePython * @param isUrgent * @param isReverseStreaming * @param sqlStd */ @Deprecated private DBConnection(boolean asynchronousTask, boolean useSSL, boolean compress, boolean usePython, boolean isUrgent, boolean isReverseStreaming, SqlStdEnum sqlStd){ this.conn_ = new DBConnectionImpl(asynchronousTask, useSSL, compress, usePython, isUrgent, isReverseStreaming, sqlStd); this.mutex_ = new ReentrantLock(); } public static DBConnection internalCreateEnableReverseStreamingDBConnection(boolean asynchronousTask, boolean useSSL, boolean compress, boolean usePython, boolean isUrgent, SqlStdEnum sqlStd) { return new DBConnection(asynchronousTask, useSSL, compress, usePython, isUrgent, true, sqlStd); } public boolean isBusy() { if (!mutex_.tryLock()) return true; else { mutex_.unlock(); return false; } } private int getVersionNumber(String ver) { try { String[] s = ver.split(" "); if (s.length >= 2) { String vernum = s[0].replace(".", ""); return Integer.parseInt(vernum); } } catch (Exception ex) {} return 0; } public void setLoadBalance(boolean loadBalance){ this.loadBalance_ = loadBalance; } public boolean connect(String hostName, int port) throws IOException { return connect(hostName, port, "", "", null, false, null); } public boolean connect(String hostName, int port, int timeout) throws IOException { this.connTimeout_ = timeout; return connect(hostName, port, "", "", null, false, null); } public boolean connect(String hostName, int port, int connectTimeout, int readTimeout) throws IOException { if (connectTimeout < 0 || readTimeout < 0) { log.error("The param connectTimeout or readTimeout cannot less than zero."); return false; } this.connectTimeout_ = connectTimeout; this.readTimeout_ = readTimeout; return connect(hostName, port, "", "", null, false, null); } public boolean connect(String hostName, int port, int timeout, boolean reconnect) throws IOException { this.connTimeout_ = timeout; return connect(hostName, port, "", "", null, false, null, reconnect); } public boolean connect(String hostName, int port, int connectTimeout, int readTimeout, boolean reconnect) throws IOException { if (connectTimeout < 0 || readTimeout < 0) { log.error("The param connectTimeout or readTimeout cannot less than zero."); return false; } this.connectTimeout_ = connectTimeout; this.readTimeout_ = readTimeout; return connect(hostName, port, "", "", null, false, null, reconnect); } public boolean connect(String hostName, int port, int timeout, boolean reconnect, int tryReconnectNums) throws IOException { this.connTimeout_ = timeout; return connect(hostName, port, "", "", null, false, null, reconnect, tryReconnectNums); } public boolean connect(String hostName, int port, int connectTimeout, int readTimeout, boolean reconnect, int tryReconnectNums) throws IOException { if (connectTimeout < 0 || readTimeout < 0) { log.error("The param connectTimeout or readTimeout cannot less than zero."); return false; } this.connectTimeout_ = connectTimeout; this.readTimeout_ = readTimeout; return connect(hostName, port, "", "", null, false, null, reconnect, tryReconnectNums); } public boolean connect(String hostName, int port, String initialScript) throws IOException { return connect(hostName, port, "", "", initialScript, false, null); } public boolean connect(String hostName, int port, String initialScript, boolean enableHighAvailability) throws IOException { return connect(hostName, port, "", "", initialScript, enableHighAvailability, null); } public boolean connect(String hostName, int port, boolean enableHighAvailability) throws IOException { return connect(hostName, port, "", "", null, enableHighAvailability, null); } public boolean connect(String hostName, int port, String[] highAvailabilitySites) throws IOException { return connect(hostName, port, "", "", null, true, highAvailabilitySites); } public boolean connect(String hostName, int port, String initialScript, String[] highAvailabilitySites) throws IOException { return connect(hostName, port, "", "", initialScript, true, highAvailabilitySites); } public boolean connect(String hostName, int port, String userId, String password) throws IOException { return connect(hostName, port, userId, password, null, false, null); } public boolean connect(String hostName, int port, String userId, String password, boolean enableHighAvailability) throws IOException { return connect(hostName, port, userId, password, null, enableHighAvailability, null); } public boolean connect(String hostName, int port, String userId, String password, String[] highAvailabilitySites) throws IOException { return connect(hostName, port, userId, password, null, true, highAvailabilitySites); } public boolean connect(String hostName, int port, String userId, String password, String initialScript) throws IOException { return connect(hostName, port, userId, password, initialScript, false, null); } public boolean connect(String hostName, int port, String userId, String password, String initialScript, boolean enableHighAvailability) throws IOException { return connect(hostName, port, userId, password, initialScript, enableHighAvailability, null); } public boolean connect(String hostName, int port, String userId, String password, String initialScript, String[] highAvailabilitySites) throws IOException { return connect(hostName, port, userId, password, initialScript, true, highAvailabilitySites); } public boolean connect(String hostName, int port, String userId, String password, String initialScript, boolean enableHighAvailability, String[] highAvailabilitySites) throws IOException { return connect(hostName, port, userId, password, initialScript, enableHighAvailability, highAvailabilitySites, false); } public boolean connect(String hostName, int port, String userId, String password, String initialScript, boolean enableHighAvailability, String[] highAvailabilitySites, boolean reconnect) throws IOException { if (enableHighAvailability) return connect(hostName, port, userId, password, initialScript, enableHighAvailability, highAvailabilitySites, reconnect, true); else return connect(hostName, port, userId, password, initialScript, enableHighAvailability, highAvailabilitySites, reconnect, false); } public boolean connect(String hostName, int port, String userId, String password, String initialScript, boolean enableHighAvailability, String[] highAvailabilitySites, boolean reconnect, int tryReconnectNums) throws IOException { if (enableHighAvailability) return connect(hostName, port, userId, password, initialScript, enableHighAvailability, highAvailabilitySites, reconnect, true, tryReconnectNums); else return connect(hostName, port, userId, password, initialScript, enableHighAvailability, highAvailabilitySites, reconnect, false, tryReconnectNums); } public boolean connect(String hostName, int port, String userId, String password, String initialScript, boolean enableHighAvailability, String[] highAvailabilitySites, boolean reconnect, boolean enableLoadBalance) throws IOException { return connect(hostName, port, userId, password, initialScript, enableHighAvailability, highAvailabilitySites, reconnect, enableLoadBalance, -1); } public boolean connect(String hostName, int port, String userId, String password, String initialScript, boolean enableHighAvailability, String[] highAvailabilitySites, boolean reconnect, boolean enableLoadBalance, int tryReconnectNums) throws IOException { mutex_.lock(); try { this.uid_ = userId; this.pwd_ = password; this.initialScript_ = initialScript; this.enableHighAvailability_ = enableHighAvailability; this.loadBalance_ = enableLoadBalance; if (tryReconnectNums <= 0) this.tryReconnectNums = -1; else this.tryReconnectNums = tryReconnectNums; if (this.loadBalance_ && !this.enableHighAvailability_) throw new RuntimeException("Cannot only enable loadbalance but not enable highAvailablity."); if (enableHighAvailability) { nodes_.add(new Node(hostName, port)); if (highAvailabilitySites != null) { for (String site : highAvailabilitySites) { Node node = new Node(site); if (!nodes_.contains(node)) nodes_.add(node); } } Node connectedNode = new Node(); BasicTable bt = null; while (!closed_) { int totalConnectAttemptNums = this.tryReconnectNums * nodes_.size(); int attempt = 0; while (!conn_.isConnected() && !closed_) { if (this.tryReconnectNums > 0) { // finite try to connect. for (Node one : nodes_) { attempt ++; // System.out.println("Current init connect node: " + one.hostName + ":" + one.port); if (connectNode(one)) { connectedNode = one; break; } try { Thread.sleep(100); } catch (Exception e){ e.printStackTrace(); return false; } } if (attempt == totalConnectAttemptNums) { log.error("Connect failed after " + tryReconnectNums + " reconnect attemps for every node in high availability sites."); return false; } } else { // infinite try to connect. for (Node one : nodes_) { if (connectNode(one)) { connectedNode = one; break; } try { Thread.sleep(100); } catch (Exception e){ e.printStackTrace(); return false; } } } } try { bt = (BasicTable) conn_.run("select host,port,(memoryUsed/1024.0/1024.0/1024.0)/maxMemSize as memLoad,ratio(connectionNum,maxConnections) as connLoad,avgLoad from rpc(getControllerAlias(),getClusterPerf) where mode=0",0); break; } catch (Exception e) { log.error("ERROR getting other data nodes, exception: " + e.getMessage()); Node node1 = new Node(); if (isConnected()) { ExceptionType type = parseException(e.getMessage(), node1); if (type == ExceptionType.ET_IGNORE){ continue; } else if (type == ExceptionType.ET_NEWLEADER || type == ExceptionType.ET_NODENOTAVAIL){ switchDataNode(node1); } } else { switchDataNode(node1); } } } if (closed_) return false; if ( bt!=null && bt.getDataForm() != Entity.DATA_FORM.DF_TABLE) throw new IOException("Run getClusterPerf() failed."); if (bt!=null) { if (!loadBalance_) { if (highAvailabilitySites == null) { BasicStringVector colHost = (BasicStringVector) bt.getColumn("host"); BasicIntVector colPort = (BasicIntVector) bt.getColumn("port"); for (int i = 0; i < colHost.rows(); i++) { Node curNode = new Node(colHost.getString(i), colPort.getInt(i)); if (!(curNode.hostName.equals(hostName) && curNode.port == port)) nodes_.add(curNode); } } } else { // enable loadBalance //ignore very high load nodes, rand one in low load nodes List lowLoadNodes=new ArrayList<>(); BasicStringVector colHost = (BasicStringVector) bt.getColumn("host"); BasicIntVector colPort = (BasicIntVector) bt.getColumn("port"); BasicDoubleVector memLoad = (BasicDoubleVector) bt.getColumn("memLoad"); BasicDoubleVector connLoad = (BasicDoubleVector) bt.getColumn("connLoad"); BasicDoubleVector avgLoad = (BasicDoubleVector) bt.getColumn("avgLoad"); for (int i = 0; i < colHost.rows(); i++) { Node nodex = new Node(colHost.getString(i), colPort.getInt(i)); Node pexistNode = null; if (highAvailabilitySites != null) { for (Node node : nodes_) { if ((node.hostName.equals(nodex.hostName) || nodex.hostName.equals("localhost")) && node.port == nodex.port){ pexistNode = node; break; } } //node is out of highAvailabilitySites if (pexistNode == null) continue; } double load=(memLoad.getDouble(i)+connLoad.getDouble(i)+avgLoad.getDouble(i))/3.0; if (pexistNode != null) { pexistNode.load = load; } else { pexistNode=new Node(colHost.getString(i), colPort.getInt(i), load); nodes_.add(pexistNode); } // low load if (memLoad.getDouble(i)<0.8 && connLoad.getDouble(i)<0.9 && avgLoad.getDouble(i)<0.8) lowLoadNodes.add(pexistNode); } Node pMinNode; if (!lowLoadNodes.isEmpty()) { pMinNode=lowLoadNodes.get(nodeRandom_.nextInt(lowLoadNodes.size())); } else { pMinNode=nodes_.get(nodeRandom_.nextInt(nodes_.size())); } if (pMinNode != null && !pMinNode.equals(connectedNode)){ log.info("Switch to node: " + pMinNode.hostName + ":" + pMinNode.port); conn_.close(); switchDataNode(pMinNode); } } } } else { if (reconnect) { nodes_.clear(); nodes_.add(new Node(hostName, port)); switchDataNode(new Node(hostName, port)); } else { if (!connectNode(new Node(hostName, port))) return false; } } initConnection(); return true; } finally { mutex_.unlock(); } } private void initConnection() throws IOException{ runClientId_ = null; if(enableHighAvailability_){ if(getServerVersion()) { if (checkClientIdValid()) { runClientId_ = BasicUuid.random().getString(); runSeqNo_ = 0; } } } if (initialScript_!=null && initialScript_.length() > 0){ run(initialScript_); } } public void switchDataNode(Node node) throws IOException{ int attempt = 0; boolean isConnected = false; do { attempt ++; if (node.hostName != null && node.hostName.length() > 0) { if (connectNode(node)) { if (nodes_.size() > 1) log.info("Switch to node: " + node.hostName + ":" + node.port + " successfully."); isConnected = true; break; } } if (nodes_.isEmpty()){ log.error("Connect to " + node.hostName + ":" + node.port + " failed."); throw new RuntimeException("Connect to " + node.hostName + ":" + node.port + " failed."); } if (nodes_.size() > 1) { int index = nodeRandom_.nextInt(nodes_.size()); if (connectNode(nodes_.get(index))){ log.info("Switch to node: " + nodes_.get(index).hostName + ":" + nodes_.get(index).port + " successfully."); isConnected = true; break; } } try { Thread.sleep(1000); } catch (Exception e){ e.printStackTrace(); return; } } while (!closed_ && (tryReconnectNums == -1 || attempt < tryReconnectNums)); if (!closed_ && !isConnected) throw new RuntimeException("Connect to " + node.hostName + ":" + node.port + " failed after " + attempt + " reconnect attemps."); if (initialScript_!=null && initialScript_.length() > 0){ run(initialScript_); } } public boolean connectNode(Node node) throws IOException { log.info("Connect to " + node.hostName + ":" + node.port + "."); while (!closed_){ try { return conn_.connect(node.hostName, node.port, uid_, pwd_, connTimeout_, connectTimeout_, readTimeout_); } catch (Exception e) { if (isConnected()){ Node tmpNode = new Node(); tmpNode.hostName = node.hostName; tmpNode.port = node.port; ExceptionType type = parseException(e.getMessage(), tmpNode); if (type != ExceptionType.ET_NEWLEADER){ if (type == ExceptionType.ET_IGNORE) return true; else if (type == ExceptionType.ET_NODENOTAVAIL) return false; else throw e; } } else { if (Objects.nonNull(e.getMessage())) log.error(e.getMessage()); return false; } } try { Thread.sleep(100); }catch (Exception e){ e.printStackTrace(); return false; } } return false; } public ExceptionType parseException(String msg, Node node) { if(msg==null){ node.hostName = ""; node.port = 0; return ExceptionType.ET_UNKNOW; } int index = msg.indexOf(""); if (index != -1){ index = msg.indexOf(">"); String ipport = msg.substring(index + 1); if (!Pattern.matches("\\d+", ipport)) { log.error("The control node you are accessing is not the leader node of the highly available (raft) cluster."); return ExceptionType.ET_NOTLEADER; } else { parseIpPort(ipport, node); log.info("New leader is " + node.hostName + ":" + node.port); return ExceptionType.ET_NEWLEADER; } }else if ((index = msg.indexOf("")) != -1){ index = msg.indexOf(">"); String ipport = msg.substring(index + 1); Node newNode = new Node(); parseIpPort(ipport, newNode); Node lastNode = new Node(); conn_.getNode(lastNode); node.hostName = ""; node.port = 0; log.info(msg); return ExceptionType.ET_NODENOTAVAIL; }else if ((index = msg.indexOf("The datanode isn't initialized yet. Please try again later")) != -1){ node.hostName = ""; node.port = 0; return ExceptionType.ET_NOINITIALIZED; } else if (msg.contains("Read timed out")) { conn_.getNode(node); return ExceptionType.ET_READTIMEDOUT; } else if (msg.contains("Failed to read response header from the socket with IO error null")) { conn_.getNode(node); return ExceptionType.ET_NORESPONSEHEADER; } else { node.hostName = ""; node.port = 0; return ExceptionType.ET_UNKNOW; } } public void parseIpPort(String ipport, Node node){ String[] v = ipport.split(":"); if (v.length < 2){ throw new RuntimeException("The ipPort '" + ipport + "' is invalid."); } node.hostName = v[0]; node.port = Integer.parseInt(v[1]); } public boolean connected(){ try { BasicInt ret= (BasicInt) conn_.run("1+1",0); return !ret.isNull() && (ret.getInt() == 2); }catch (Exception e){ return false; } } public void login(String userId, String password, boolean enableEncryption)throws IOException{ conn_.login(userId, password, enableEncryption); uid_ = userId; pwd_ = password; } public boolean getRemoteLittleEndian() { return this.conn_.getRemoteLittleEndian(); } public Entity tryRun(String script) throws IOException { return tryRun(script, DEFAULT_PRIORITY, DEFAULT_PARALLELISM); } public Entity tryRun(String script, int priority, int parallelism) throws IOException { return tryRun(script, priority, parallelism, 0, false); } public Entity tryRun(String script, int priority, int parallelism, boolean clearSessionMemory) throws IOException { return tryRun(script, priority, parallelism, 0, clearSessionMemory); } public Entity tryRun(String script, int priority, int parallelism,int fetchSize, boolean clearSessionMemory) throws IOException { if (!mutex_.tryLock()) return null; try { return run(script, (ProgressListener) null, priority, parallelism, fetchSize, clearSessionMemory); } finally { mutex_.unlock(); } } public Entity run(String script, String tableName) throws IOException{ return run(script, (ProgressListener) null, DEFAULT_PRIORITY, DEFAULT_PARALLELISM, 0, false, tableName); } public Entity run(String script) throws IOException { return run(script, (ProgressListener) null, DEFAULT_PRIORITY, DEFAULT_PARALLELISM); } public Entity run(String script, int priority) throws IOException { return run(script, (ProgressListener) null, priority, DEFAULT_PARALLELISM); } public Entity run(String script, int priority, int parallelism) throws IOException { return run(script, (ProgressListener) null, priority, parallelism); } public Entity run(String script, ProgressListener listener) throws IOException { return run(script, listener, DEFAULT_PRIORITY, DEFAULT_PARALLELISM); } public Entity run(String script, ProgressListener listener, boolean clearSessionMemory) throws IOException { return run(script, listener, DEFAULT_PRIORITY, DEFAULT_PARALLELISM, 0, clearSessionMemory); } public Entity run(String script, int priority, boolean clearSessionMemory) throws IOException { return run( script, (ProgressListener)null, priority, DEFAULT_PARALLELISM, 0, clearSessionMemory); } public Entity run(String script, ProgressListener listener, int priority, int parallelism) throws IOException { return run( script, listener, priority, parallelism, 0,false); } public Entity run(String script, ProgressListener listener, int priority, int parallelism, boolean clearSessionMemory) throws IOException { return run( script, listener, priority, parallelism, 0,clearSessionMemory); } public Entity run(String script, int priority, int parallelism, boolean clearSessionMemory) throws IOException { return run(script, (ProgressListener)null, priority, parallelism, 0,clearSessionMemory); } public Entity run(String script, ProgressListener listener, int priority, int parallelism, int fetchSize) throws IOException { return run( script, listener, priority, parallelism, fetchSize,false); } public Entity tryRun(String script, boolean clearSessionMemory) throws IOException { if (!mutex_.tryLock()) return null; try { return run(script, (ProgressListener) null, DEFAULT_PRIORITY, DEFAULT_PARALLELISM, 0, clearSessionMemory); } finally { mutex_.unlock(); } } public Entity run(String script, boolean clearSessionMemory) throws IOException { return run(script, (ProgressListener) null, DEFAULT_PRIORITY, DEFAULT_PARALLELISM,0, clearSessionMemory); } public Entity run(String script, ProgressListener listener, int priority, int parallelism, int fetchSize, boolean clearSessionMemory) throws IOException{ return run(script, listener, priority, parallelism, fetchSize, clearSessionMemory, ""); } public Entity run(String script, ProgressListener listener, int priority, int parallelism, int fetchSize, boolean clearSessionMemory, String tableName, boolean enableSeqNo) throws IOException{ mutex_.lock(); try { if (!nodes_.isEmpty()) { long currentSeqNo; if (enableSeqNo) currentSeqNo = newSeqNo(); else currentSeqNo = 0; while (!closed_) { try { return conn_.run(script, listener, priority, parallelism, fetchSize, clearSessionMemory, tableName, currentSeqNo); } catch (IOException e) { if (currentSeqNo > 0) currentSeqNo = -currentSeqNo; Node node = new Node(); if (connected()) { ExceptionType type = parseException(e.getMessage(), node); if (type == ExceptionType.ET_IGNORE) return new Void(); else if (type == ExceptionType.ET_UNKNOW) throw e; else if (type == ExceptionType.ET_READTIMEDOUT) cancelConsoleJob(enableSeqNo, currentSeqNo, e); } else { ExceptionType type = parseException(e.getMessage(), node); if (type == ExceptionType.ET_READTIMEDOUT) cancelConsoleJob(enableSeqNo, currentSeqNo, e); } switchDataNode(node); } } return null; } else { return conn_.run(script, listener, priority, parallelism, fetchSize, clearSessionMemory, tableName, 0); } } finally { mutex_.unlock(); } } private void cancelConsoleJob(boolean enableSeqNo, long currentSeqNo, IOException e) throws IOException { String cancelConsoleJobScript = "jobs = exec rootJobId from getConsoleJobs() where sessionId = " + conn_.sessionID_ + "\n" + (conn_.python_ ? "if size(jobs):\n" : "if (size(jobs))\n") + " cancelConsoleJob(jobs)\n"; conn_.ifUrgent_ = true; // conn_.asynTask_ = true; if (enableSeqNo) currentSeqNo = newSeqNo(); try { conn_.run(cancelConsoleJobScript, currentSeqNo); conn_.ifUrgent_ = false; } catch (IOException ioe) { conn_.ifUrgent_ = false; throw new RuntimeException("Execute cancelConsoleJob failed after current connnection read timed out. "); } log.error(e.getMessage()); throw e; } public Entity run(String script, ProgressListener listener, int priority, int parallelism, int fetchSize, boolean clearSessionMemory, String tableName) throws IOException{ return run(script, listener, priority, parallelism, fetchSize, clearSessionMemory, tableName, true); } public Entity tryRun(String function, List arguments) throws IOException { return tryRun(function, arguments, DEFAULT_PRIORITY, DEFAULT_PARALLELISM); } public Entity tryRun(String function, List arguments, int priority, int parallelism) throws IOException { return tryRun(function, arguments, priority, parallelism,0); } public Entity tryRun(String function, List arguments, int priority, int parallelism, int fetchSize) throws IOException { if (!mutex_.tryLock()) return null; try { return run(function, arguments, priority, parallelism, fetchSize); } finally { mutex_.unlock(); } } public Entity run(String function, List arguments) throws IOException { return run(function, arguments, DEFAULT_PRIORITY, DEFAULT_PARALLELISM); } public Entity run(String function, List arguments, int priority) throws IOException { return run(function, arguments, priority, DEFAULT_PARALLELISM); } public Entity run(String function, List arguments, int priority, int parallelism) throws IOException { return run(function, arguments, priority, parallelism, 0); } private long newSeqNo(){ mutex_.lock(); runSeqNo_++; if(runSeqNo_ <= 0){ runSeqNo_ = 1; } long res=runSeqNo_; mutex_.unlock(); return res; } public Entity run(String function, List arguments, int priority, int parallelism, int fetchSize, boolean enableSeqNo) throws IOException { mutex_.lock(); try { if (!nodes_.isEmpty()) { long currentSeqNo; if (enableSeqNo) currentSeqNo = newSeqNo(); else currentSeqNo = 0; while (!closed_) { try { return conn_.run(function, (ProgressListener)null, arguments, priority, parallelism, fetchSize, false, currentSeqNo); } catch (IOException e) { if (currentSeqNo > 0) currentSeqNo = -currentSeqNo; Node node = new Node(); if (connected()){ ExceptionType type = parseException(e.getMessage(), node); if (type == ExceptionType.ET_IGNORE) return new Void(); else if (type == ExceptionType.ET_UNKNOW) throw e; }else { parseException(e.getMessage(), node); } switchDataNode(node); } } return null; } else { return conn_.run(function, (ProgressListener)null, arguments, priority, parallelism, fetchSize, false, 0); } } finally { mutex_.unlock(); } } public Entity run(String function, List arguments, int priority, int parallelism, int fetchSize) throws IOException { return run(function, arguments, priority, parallelism, fetchSize, true); } public void tryUpload(final Map variableObjectMap) throws IOException { if (!mutex_.tryLock()) throw new IOException("The connection is in use."); try { upload(variableObjectMap); } finally { mutex_.unlock(); } } public void upload(final Map variableObjectMap) throws IOException { mutex_.lock(); try { List keys = new ArrayList<>(); List objs = new ArrayList<>(); if (!nodes_.isEmpty()){ while (!closed_){ try { for (String key : variableObjectMap.keySet()){ if (variableObjectMap.size() == 1){ Entity obj = variableObjectMap.get(key); conn_.upload(key, obj,0); }else { keys.add(key); objs.add(variableObjectMap.get(key)); } } if (variableObjectMap.size() > 1) conn_.upload(keys, objs,0); break; }catch (Exception e){ Node node = new Node(); if (connected()){ ExceptionType type = parseException(e.getMessage(), node); if (type == ExceptionType.ET_IGNORE) continue; else if (type == ExceptionType.ET_UNKNOW) throw e; }else { parseException(e.getMessage(), node); } switchDataNode(node); } } }else { for (String key : variableObjectMap.keySet()){ if (variableObjectMap.size() == 1){ Entity obj = variableObjectMap.get(key); conn_.upload(key, obj, 0); }else { keys.add(key); objs.add(variableObjectMap.get(key)); } } if (variableObjectMap.size() > 1) conn_.upload(keys, objs, 0); } }finally { mutex_.unlock(); } } public void close() { mutex_.lock(); try { closed_ = true; conn_.close(); } catch (Exception ex) { ex.printStackTrace(); } finally { mutex_.unlock(); } } public String getHostName() { return this.conn_.hostName_; } public int getPort() { return this.conn_.port_; } public String getUserId(){ return this.conn_.userId_; } public String getPwd(){ return this.conn_.pwd_; } public String getSessionID() { return this.conn_.sessionID_; } public InetAddress getLocalAddress() { return this.conn_.socket_.getLocalAddress(); } public Socket getSocket(){return this.conn_.socket_;} public ExtendedDataInput getDataInputStream() { return conn_.getDataInputStream(); } public boolean isConnected() { return this.conn_.socket_ != null && this.conn_.socket_.isConnected(); } private SSLSocketFactory getSSLSocketFactory(){ try { SSLContext context = SSLContext.getInstance("SSL"); context.init(null, new TrustManager[]{new X509TrustManager() { public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { } public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { } public X509Certificate[] getAcceptedIssuers() { return null; } } }, new java.security.SecureRandom()); return context.getSocketFactory(); }catch (Exception ex){ ex.printStackTrace(); return null; } } private boolean getServerVersion() throws IOException { try { Entity ret = conn_.run("version()",0); if(ret==null){ throw new IOException("run version failed"); } String version = ret.getString(); String[] verList=version.split(" "); if(verList.length > 1){ version=verList[0]; } verList = version.split("\\."); serverVersion_=new int[4]; int size=verList.length; if(size>4) size=4; else if(size<3) return false; for(int i=0;i version[i]; } } return true; } private boolean checkClientIdValid(){ if(serverVersion_[0]==1){//1.30.20.5 return compareVersionGE(new int[]{1,30,20,5}); }else if(serverVersion_[0]==2){//2.00.9 return compareVersionGE(new int[]{2,0,9,0}); }else return true; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy