blob: f78e1ff7769e2518e84ae6a6e9ef7a0ec8d58ed5 [file]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#include "SessionConnection.h"
#include "Session.h"
#include "common_types.h"
#include <thrift/protocol/TCompactProtocol.h>
#include <utility>
using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;
SessionConnection::SessionConnection(Session* session_ptr, const TEndPoint& endpoint,
const std::string& zoneId,
std::shared_ptr<INodesSupplier> nodeSupplier,
int maxRetries,
int64_t retryInterval,
std::string dialect,
std::string db)
: session(session_ptr),
zoneId(zoneId),
endPoint(endpoint),
availableNodes(std::move(nodeSupplier)),
maxRetryCount(maxRetries),
retryIntervalMs(retryInterval),
sqlDialect(std::move(dialect)),
database(std::move(db)) {
this->zoneId = zoneId.empty() ? getSystemDefaultZoneId() : zoneId;
endPointList.push_back(endpoint);
init(endPoint);
}
void SessionConnection::close() {
bool needThrowException = false;
string errMsg;
session = nullptr;
try {
TSCloseSessionReq req;
req.__set_sessionId(sessionId);
TSStatus tsStatus;
client->closeSession(tsStatus, req);
} catch (const TTransportException &e) {
log_debug(e.what());
throw IoTDBConnectionException(e.what());
} catch (const exception &e) {
log_debug(e.what());
errMsg = errMsg + "Session::close() client->closeSession() error, maybe remote server is down. " + e.what() + "\n" ;
needThrowException = true;
}
try {
if (transport->isOpen()) {
transport->close();
}
}
catch (const exception &e) {
log_debug(e.what());
errMsg = errMsg + "Session::close() transport->close() error. " + e.what() + "\n" ;
needThrowException = true;
}
if (needThrowException) {
throw IoTDBException(errMsg);
}
}
SessionConnection::~SessionConnection() {
try {
close();
} catch (const exception &e) {
log_debug(e.what());
}
}
void SessionConnection::init(const TEndPoint& endpoint) {
shared_ptr<TSocket> socket(new TSocket(endpoint.ip, endpoint.port));
transport = std::make_shared<TFramedTransport>(socket);
socket->setConnTimeout(connectionTimeoutInMs);
if (!transport->isOpen()) {
try {
transport->open();
}
catch (TTransportException &e) {
log_debug(e.what());
throw IoTDBConnectionException(e.what());
}
}
if (enableRPCCompression) {
shared_ptr<TCompactProtocol> protocol(new TCompactProtocol(transport));
client = std::make_shared<IClientRPCServiceClient>(protocol);
} else {
shared_ptr<TBinaryProtocol> protocol(new TBinaryProtocol(transport));
client = std::make_shared<IClientRPCServiceClient>(protocol);
}
std::map<std::string, std::string> configuration;
configuration["version"] = session->getVersionString(session->version);
configuration["sql_dialect"] = sqlDialect;
if (database != "") {
configuration["db"] = database;
}
TSOpenSessionReq openReq;
openReq.__set_username(session->username);
openReq.__set_password(session->password);
openReq.__set_zoneId(zoneId);
openReq.__set_configuration(configuration);
try {
TSOpenSessionResp openResp;
client->openSession(openResp, openReq);
RpcUtils::verifySuccess(openResp.status);
if (session->protocolVersion != openResp.serverProtocolVersion) {
if (openResp.serverProtocolVersion == 0) {// less than 0.10
throw logic_error(string("Protocol not supported, Client version is ") +
to_string(session->protocolVersion) +
", but Server version is " + to_string(openResp.serverProtocolVersion));
}
}
sessionId = openResp.sessionId;
statementId = client->requestStatementId(sessionId);
if (!zoneId.empty()) {
setTimeZone(zoneId);
}
} catch (const TTransportException &e) {
log_debug(e.what());
transport->close();
throw IoTDBConnectionException(e.what());
} catch (const IoTDBException &e) {
log_debug(e.what());
transport->close();
throw;
} catch (const exception &e) {
log_debug(e.what());
transport->close();
throw;
}
}
std::unique_ptr<SessionDataSet> SessionConnection::executeQueryStatement(const std::string& sql, int64_t timeoutInMs) {
TSExecuteStatementReq req;
req.__set_sessionId(sessionId);
req.__set_statementId(statementId);
req.__set_statement(sql);
req.__set_timeout(timeoutInMs);
req.__set_enableRedirectQuery(true);
TSExecuteStatementResp resp;
try {
client->executeStatement(resp, req);
RpcUtils::verifySuccessWithRedirection(resp.status);
} catch (const TException &e) {
log_debug(e.what());
if (reconnect()) {
try {
req.__set_sessionId(sessionId);
req.__set_statementId(statementId);
client->executeStatement(resp, req);
} catch (TException &e) {
throw IoTDBConnectionException(e.what());
}
} else {
throw IoTDBConnectionException(e.what());
}
}
std::shared_ptr<TSQueryDataSet> queryDataSet(new TSQueryDataSet(resp.queryDataSet));
return std::unique_ptr<SessionDataSet>(new SessionDataSet(
sql, resp.columns, resp.dataTypeList, resp.columnNameIndexMap, resp.ignoreTimeStamp, resp.queryId,
statementId, client, sessionId, queryDataSet));
}
const TEndPoint& SessionConnection::getEndPoint() {
return endPoint;
}
void SessionConnection::setTimeZone(const std::string& newZoneId) {
TSSetTimeZoneReq req;
req.__set_sessionId(sessionId);
req.__set_timeZone(newZoneId);
try {
TSStatus tsStatus;
client->setTimeZone(tsStatus, req);
zoneId = newZoneId;
} catch (const TException& e) {
throw IoTDBConnectionException(e.what());
}
}
std::string SessionConnection::getSystemDefaultZoneId() {
time_t ts = 0;
struct tm tmv{};
#if defined(_WIN64) || defined (WIN32) || defined (_WIN32)
localtime_s(&tmv, &ts);
#else
localtime_r(&ts, &tmv);
#endif
char zoneStr[32];
strftime(zoneStr, sizeof(zoneStr), "%z", &tmv);
return zoneStr;
}
bool SessionConnection::reconnect() {
bool reconnect = false;
for (int i = 1; i <= 3; i++) {
if (transport != nullptr) {
transport->close();
endPointList = std::move(availableNodes->getEndPointList());
int currHostIndex = rand() % endPointList.size();
int tryHostNum = 0;
for (int j = currHostIndex; j < endPointList.size(); j++) {
if (tryHostNum == endPointList.size()) {
break;
}
this->endPoint = endPointList[j];
if (j == endPointList.size() - 1) {
j = -1;
}
tryHostNum++;
try {
init(this->endPoint);
reconnect = true;
} catch (const IoTDBConnectionException &e) {
log_warn("The current node may have been down, connection exception: %s", e.what());
continue;
} catch (exception &e) {
log_warn("login in failed, because %s", e.what());
}
break;
}
}
if (reconnect) {
session->removeBrokenSessionConnection(shared_from_this());
session->defaultEndPoint = this->endPoint;
session->defaultSessionConnection = shared_from_this();
session->endPointToSessionConnection.insert(make_pair(this->endPoint, shared_from_this()));
}
}
return reconnect;
}