use of org.voltcore.utils.VersionChecker in project voltdb by VoltDB.
the class SocketJoiner method processSSC.
/*
* Pull all ready to accept sockets
*/
private void processSSC(ServerSocketChannel ssc) throws Exception {
SocketChannel sc = null;
while ((sc = ssc.accept()) != null) {
try {
sc.socket().setTcpNoDelay(true);
sc.socket().setPerformancePreferences(0, 2, 1);
final String remoteAddress = sc.socket().getRemoteSocketAddress().toString();
/*
* Send the current time over the new connection for a clock skew check
*/
ByteBuffer currentTimeBuf = ByteBuffer.allocate(8);
currentTimeBuf.putLong(System.currentTimeMillis());
currentTimeBuf.flip();
while (currentTimeBuf.hasRemaining()) {
sc.write(currentTimeBuf);
}
/*
* Read a length prefixed JSON message
*/
JSONObject jsObj = readJSONObjFromWire(sc, remoteAddress);
LOG.info(jsObj.toString(2));
// get the connecting node's version string
String remoteBuildString = jsObj.getString(VERSION_STRING);
VersionChecker versionChecker = m_acceptor.getVersionChecker();
// send a response with version/build data of this node
JSONObject returnJs = new JSONObject();
returnJs.put(VERSION_STRING, versionChecker.getVersionString());
returnJs.put(BUILD_STRING, versionChecker.getBuildString());
returnJs.put(VERSION_COMPATIBLE, versionChecker.isCompatibleVersionString(remoteBuildString));
// inject acceptor fields
m_acceptor.decorate(returnJs, Optional.of(m_paused.get()));
byte[] jsBytes = returnJs.toString(4).getBytes(StandardCharsets.UTF_8);
ByteBuffer returnJsBuffer = ByteBuffer.allocate(4 + jsBytes.length);
returnJsBuffer.putInt(jsBytes.length);
returnJsBuffer.put(jsBytes).flip();
while (returnJsBuffer.hasRemaining()) {
sc.write(returnJsBuffer);
}
/*
* The type of connection, it can be a new request to join the cluster
* or a node that is connecting to the rest of the cluster and publishing its
* host id or a request to add a new connection to the request node.
*/
String type = jsObj.getString(TYPE);
/*
* The new connection may specify the address it is listening on,
* or it can be derived from the connection itself
*/
InetSocketAddress listeningAddress;
if (jsObj.has(ADDRESS)) {
listeningAddress = new InetSocketAddress(InetAddress.getByName(jsObj.getString(ADDRESS)), jsObj.getInt(PORT));
} else {
listeningAddress = new InetSocketAddress(((InetSocketAddress) sc.socket().getRemoteSocketAddress()).getAddress().getHostAddress(), jsObj.getInt(PORT));
}
hostLog.info("Received request type " + type);
if (type.equals(ConnectionType.REQUEST_HOSTID.name())) {
m_joinHandler.requestJoin(sc, listeningAddress, jsObj);
} else if (type.equals(ConnectionType.PUBLISH_HOSTID.name())) {
m_joinHandler.notifyOfJoin(jsObj.getInt(HOST_ID), sc, listeningAddress, jsObj);
} else if (type.equals(ConnectionType.REQUEST_CONNECTION.name())) {
m_joinHandler.notifyOfConnection(jsObj.getInt(HOST_ID), sc, listeningAddress);
} else {
throw new RuntimeException("Unexpected message type " + type + " from " + remoteAddress);
}
} catch (Exception ex) {
// do not leak sockets when exception happens
try {
sc.close();
} catch (IOException ioex) {
// ignore the close exception on purpose
}
// re-throw the exception, it will be handled by the caller
throw ex;
}
}
}
use of org.voltcore.utils.VersionChecker in project voltdb by VoltDB.
the class SocketJoiner method processJSONResponse.
/**
* Read version info from a socket and check compatibility.
* After verifying versions return if "paused" start is indicated. True if paused start otherwise normal start.
*/
private JSONObject processJSONResponse(SocketChannel sc, String remoteAddress, Set<String> activeVersions, boolean checkVersion) throws IOException, JSONException {
// read the json response from socketjoiner with version info
JSONObject jsonResponse = readJSONObjFromWire(sc, remoteAddress);
if (!checkVersion) {
return jsonResponse;
}
VersionChecker versionChecker = m_acceptor.getVersionChecker();
String remoteVersionString = jsonResponse.getString(VERSION_STRING);
String remoteBuildString = jsonResponse.getString(BUILD_STRING);
boolean remoteAcceptsLocalVersion = jsonResponse.getBoolean(VERSION_COMPATIBLE);
if (remoteVersionString.equals(versionChecker.getVersionString())) {
if (!versionChecker.getBuildString().equals(remoteBuildString)) {
// ignore test/eclipse build string so tests still work
if (!versionChecker.getBuildString().equals("VoltDB") && !remoteBuildString.equals("VoltDB")) {
org.voltdb.VoltDB.crashLocalVoltDB("For VoltDB version " + versionChecker.getVersionString() + " git tag/hash is not identical across the cluster. Node join failed.\n" + " joining build string: " + versionChecker.getBuildString() + "\n" + " existing build string: " + remoteBuildString, false, null);
return null;
}
}
} else if (!remoteAcceptsLocalVersion) {
if (!versionChecker.isCompatibleVersionString(remoteVersionString)) {
org.voltdb.VoltDB.crashLocalVoltDB("Cluster contains nodes running VoltDB version " + remoteVersionString + " which is incompatibile with local version " + versionChecker.getVersionString() + ".\n", false, null);
return null;
}
}
//Do this only after we think we are compatible.
activeVersions.add(remoteVersionString);
return jsonResponse;
}
use of org.voltcore.utils.VersionChecker in project voltdb by VoltDB.
the class SocketJoiner method requestHostId.
/**
* Connection handshake to the leader, ask the leader to assign a host Id
* for current node.
* @param
* @return array of two JSON objects, first is leader info, second is
* the response to our request
* @throws Exception
*/
private RequestHostIdResponse requestHostId(SocketChannel socket, List<Long> skews, Set<String> activeVersions) throws Exception {
// Read the timestamp off the wire and calculate skew for this connection
ByteBuffer currentTimeBuf = ByteBuffer.allocate(8);
while (currentTimeBuf.hasRemaining()) {
socket.read(currentTimeBuf);
}
currentTimeBuf.flip();
long skew = System.currentTimeMillis() - currentTimeBuf.getLong();
skews.add(skew);
VersionChecker versionChecker = m_acceptor.getVersionChecker();
activeVersions.add(versionChecker.getVersionString());
JSONObject jsObj = new JSONObject();
jsObj.put(TYPE, ConnectionType.REQUEST_HOSTID.name());
// put the version compatibility status in the json
jsObj.put(VERSION_STRING, versionChecker.getVersionString());
// Advertise the port we are going to listen on based on config
jsObj.put(PORT, m_internalPort);
// Otherwise the leader will echo back what we connected on
if (!m_internalInterface.isEmpty()) {
jsObj.put(ADDRESS, m_internalInterface);
}
// communicate configuration and node state
m_acceptor.decorate(jsObj, Optional.empty());
jsObj.put(MAY_EXCHANGE_TS, true);
byte[] jsBytes = jsObj.toString(4).getBytes(StandardCharsets.UTF_8);
ByteBuffer requestHostIdBuffer = ByteBuffer.allocate(4 + jsBytes.length);
requestHostIdBuffer.putInt(jsBytes.length);
requestHostIdBuffer.put(jsBytes).flip();
while (requestHostIdBuffer.hasRemaining()) {
socket.write(requestHostIdBuffer);
}
final String primaryAddress = socket.socket().getRemoteSocketAddress().toString();
// read the json response from socketjoiner with version info and validate it
JSONObject leaderInfo = processJSONResponse(socket, primaryAddress, activeVersions, true);
// read the json response sent by HostMessenger with HostID
JSONObject jsonObj = readJSONObjFromWire(socket, primaryAddress);
return new RequestHostIdResponse(leaderInfo, jsonObj);
}
Aggregations