Skip to content

Commit c14af5a

Browse files
committed
implement new session constructor
1 parent 72a11f3 commit c14af5a

9 files changed

Lines changed: 310 additions & 7 deletions

File tree

iotdb-client/client-cpp/src/main/AbstractSessionBuilder.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class AbstractSessionBuilder {
3535
bool enableAutoFetch = true;
3636
bool enableRedirections = true;
3737
bool enableRPCCompression = false;
38+
std::vector<std::string> nodeUrls;
3839
};
3940

4041
#endif // IOTDB_ABSTRACTSESSIONBUILDER_H

iotdb-client/client-cpp/src/main/Common.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,3 +454,47 @@ const std::vector<char>& BitMap::getByteArray() const {
454454
size_t BitMap::getSize() const {
455455
return this->size;
456456
}
457+
458+
const std::string UrlUtils::PORT_SEPARATOR = ":";
459+
const std::string UrlUtils::ABB_COLON = "[";
460+
461+
TEndPoint UrlUtils::parseTEndPointIpv4AndIpv6Url(const std::string& endPointUrl) {
462+
TEndPoint endPoint;
463+
464+
// Return default TEndPoint if input is empty
465+
if (endPointUrl.empty()) {
466+
return endPoint;
467+
}
468+
469+
size_t portSeparatorPos = endPointUrl.find_last_of(PORT_SEPARATOR);
470+
471+
// If no port separator found, treat entire string as IP
472+
if (portSeparatorPos == std::string::npos) {
473+
endPoint.__set_ip(endPointUrl);
474+
return endPoint;
475+
}
476+
477+
// Extract port part
478+
std::string portStr = endPointUrl.substr(portSeparatorPos + 1);
479+
480+
// Extract IP part
481+
std::string ip = endPointUrl.substr(0, portSeparatorPos);
482+
483+
// Handle IPv6 addresses with brackets
484+
if (ip.find(ABB_COLON) != std::string::npos) {
485+
// Remove surrounding square brackets for IPv6
486+
if (ip.size() >= 2 && ip.front() == '[' && ip.back() == ']') {
487+
ip = ip.substr(1, ip.size() - 2);
488+
}
489+
}
490+
491+
try {
492+
int port = std::stoi(portStr);
493+
endPoint.__set_ip(ip);
494+
endPoint.__set_port(port);
495+
} catch (const std::exception& e) {
496+
endPoint.__set_ip(endPointUrl);
497+
}
498+
499+
return endPoint;
500+
}

iotdb-client/client-cpp/src/main/Common.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,5 +481,23 @@ class RpcUtils {
481481
static std::shared_ptr<TSFetchResultsResp> getTSFetchResultsResp(const TSStatus& status);
482482
};
483483

484+
class UrlUtils {
485+
private:
486+
static const std::string PORT_SEPARATOR;
487+
static const std::string ABB_COLON;
488+
489+
UrlUtils() = delete;
490+
~UrlUtils() = delete;
491+
492+
public:
493+
/**
494+
* Parse TEndPoint from a given TEndPointUrl
495+
* example:[D80:0000:0000:0000:ABAA:0000:00C2:0002]:22227
496+
*
497+
* @param endPointUrl ip:port
498+
* @return TEndPoint with default values if parse error
499+
*/
500+
static TEndPoint parseTEndPointIpv4AndIpv6Url(const std::string& endPointUrl);
501+
};
484502

485503
#endif

iotdb-client/client-cpp/src/main/Session.cpp

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -725,18 +725,36 @@ void Session::initZoneId() {
725725
zoneId_ = zoneStr;
726726
}
727727

728-
void Session::initNodesSupplier() {
728+
void Session::initNodesSupplier(const std::vector<std::string>& nodeUrls) {
729729
std::vector<TEndPoint> endPoints;
730-
TEndPoint endPoint;
731-
endPoint.__set_ip(host_);
732-
endPoint.__set_port(rpcPort_);
733-
endPoints.emplace_back(endPoint);
730+
731+
if (nodeUrls.empty() && host_.empty()) {
732+
throw IoTDBException("No available nodes: both nodeUrls and host are empty");
733+
}
734+
735+
// Add local endpoint if nodeUrls is empty or doesn't contain host_
736+
if (nodeUrls.empty()) {
737+
TEndPoint endPoint;
738+
endPoint.__set_ip(host_);
739+
endPoint.__set_port(rpcPort_);
740+
endPoints.emplace_back(std::move(endPoint));
741+
} else {
742+
for (auto& url : nodeUrls) {
743+
endPoints.emplace_back(UrlUtils::parseTEndPointIpv4AndIpv6Url(url));
744+
}
745+
}
746+
734747
if (enableAutoFetch_) {
735748
nodesSupplier_ = NodesSupplier::create(endPoints, username_, password_);
736749
}
737750
else {
738751
nodesSupplier_ = make_shared<StaticNodesSupplier>(endPoints);
739752
}
753+
if (host_.empty()) {
754+
auto queryNode = nodesSupplier_->getQueryEndPoint();
755+
host_ = queryNode.value().ip;
756+
rpcPort_ = queryNode.value().port;
757+
}
740758
}
741759

742760
void Session::initDefaultSessionConnection() {

iotdb-client/client-cpp/src/main/Session.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,7 @@ class Session {
535535
private:
536536
std::string host_;
537537
int rpcPort_;
538+
std::vector<string> nodeUrls_;
538539
std::string username_;
539540
std::string password_;
540541
const TSProtocolVersion::type protocolVersion_ = TSProtocolVersion::IOTDB_SERVICE_PROTOCOL_V3;
@@ -605,7 +606,7 @@ class Session {
605606

606607
void initZoneId();
607608

608-
void initNodesSupplier();
609+
void initNodesSupplier(const std::vector<std::string>& nodeUrls = std::vector<std::string>());
609610

610611
void initDefaultSessionConnection();
611612

@@ -664,6 +665,12 @@ class Session {
664665
initNodesSupplier();
665666
}
666667

668+
Session(const std::vector<string>& nodeUrls, const std::string& username, const std::string& password)
669+
: nodeUrls_(nodeUrls), username_(username), password_(password), version(Version::V_1_0) {
670+
initZoneId();
671+
initNodesSupplier(this->nodeUrls_);
672+
}
673+
667674
Session(const std::string& host, int rpcPort, const std::string& username, const std::string& password)
668675
: fetchSize_(DEFAULT_FETCH_SIZE) {
669676
this->host_ = host;
@@ -714,8 +721,9 @@ class Session {
714721
this->database_ = builder->database;
715722
this->enableAutoFetch_ = builder->enableAutoFetch;
716723
this->enableRedirection_ = builder->enableRedirections;
724+
this->nodeUrls_ = builder->nodeUrls;
717725
initZoneId();
718-
initNodesSupplier();
726+
initNodesSupplier(this->nodeUrls_);
719727
}
720728

721729
~Session();
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
#ifndef IOTDB_SESSION_BUILDER_H
21+
#define IOTDB_SESSION_BUILDER_H
22+
23+
#include "AbstractSessionBuilder.h"
24+
25+
class SessionBuilder : public AbstractSessionBuilder {
26+
public:
27+
SessionBuilder* host(const std::string &host) {
28+
AbstractSessionBuilder::host = host;
29+
return this;
30+
}
31+
32+
SessionBuilder* rpcPort(int rpcPort) {
33+
AbstractSessionBuilder::rpcPort = rpcPort;
34+
return this;
35+
}
36+
37+
SessionBuilder* username(const std::string &username) {
38+
AbstractSessionBuilder::username = username;
39+
return this;
40+
}
41+
42+
SessionBuilder* password(const std::string &password) {
43+
AbstractSessionBuilder::password = password;
44+
return this;
45+
}
46+
47+
SessionBuilder* zoneId(const std::string &zoneId) {
48+
AbstractSessionBuilder::zoneId = zoneId;
49+
return this;
50+
}
51+
52+
SessionBuilder* fetchSize(int fetchSize) {
53+
AbstractSessionBuilder::fetchSize = fetchSize;
54+
return this;
55+
}
56+
57+
SessionBuilder* database(const std::string &database) {
58+
AbstractSessionBuilder::database = database;
59+
return this;
60+
}
61+
62+
SessionBuilder* nodeUrls(const std::vector<std::string>& nodeUrls) {
63+
AbstractSessionBuilder::nodeUrls = nodeUrls;
64+
return this;
65+
}
66+
67+
SessionBuilder* enableAutoFetch(bool enableAutoFetch) {
68+
AbstractSessionBuilder::enableAutoFetch = enableAutoFetch;
69+
return this;
70+
}
71+
72+
SessionBuilder* enableRedirections(bool enableRedirections) {
73+
AbstractSessionBuilder::enableRedirections = enableRedirections;
74+
return this;
75+
}
76+
77+
SessionBuilder* enableRPCCompression(bool enableRPCCompression) {
78+
AbstractSessionBuilder::enableRPCCompression = enableRPCCompression;
79+
return this;
80+
}
81+
82+
Session* build() {
83+
sqlDialect = "tree";
84+
Session* newSession = new Session(this);
85+
newSession->open(false);
86+
return new Session(this);
87+
}
88+
};
89+
90+
#endif // IOTDB_SESSION_BUILDER_H

iotdb-client/client-cpp/src/main/TableSessionBuilder.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ class TableSessionBuilder : public AbstractSessionBuilder {
6565
AbstractSessionBuilder::database = database;
6666
return this;
6767
}
68+
TableSessionBuilder* nodeUrls(const std::vector<string>& nodeUrls) {
69+
AbstractSessionBuilder::nodeUrls = nodeUrls;
70+
return this;
71+
}
6872
TableSession* build() {
6973
sqlDialect = "table";
7074
Session* newSession = new Session(this);

iotdb-client/client-cpp/src/test/cpp/sessionIT.cpp

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include "catch.hpp"
2121
#include "Session.h"
22+
#include "SessionBuilder.h"
2223

2324
using namespace std;
2425

@@ -62,6 +63,42 @@ TEST_CASE("Create timeseries success", "[createTimeseries]") {
6263
session->deleteTimeseries("root.test.d1.s1");
6364
}
6465

66+
TEST_CASE("Test Session constructor with nodeUrls", "[SessionInitAndOperate]") {
67+
CaseReporter cr("SessionInitWithNodeUrls");
68+
69+
std::vector<std::string> nodeUrls = {"127.0.0.1:6667"};
70+
std::shared_ptr<Session> localSession = std::make_shared<Session>(nodeUrls, "root", "root");
71+
localSession->open();
72+
if (!localSession->checkTimeseriesExists("root.test.d1.s1")) {
73+
localSession->createTimeseries("root.test.d1.s1", TSDataType::INT64, TSEncoding::RLE, CompressionType::SNAPPY);
74+
}
75+
REQUIRE(localSession->checkTimeseriesExists("root.test.d1.s1") == true);
76+
localSession->deleteTimeseries("root.test.d1.s1");
77+
localSession->close();
78+
}
79+
80+
TEST_CASE("Test Session builder with nodeUrls", "[SessionBuilderInit]") {
81+
CaseReporter cr("SessionInitWithNodeUrls");
82+
83+
std::vector<std::string> nodeUrls = {"127.0.0.1:6667"};
84+
auto builder = std::unique_ptr<SessionBuilder>(new SessionBuilder());
85+
std::shared_ptr<Session> session =
86+
std::shared_ptr<Session>(
87+
builder
88+
->username("root")
89+
->password("root")
90+
->nodeUrls(nodeUrls)
91+
->build()
92+
);
93+
session->open();
94+
if (!session->checkTimeseriesExists("root.test.d1.s1")) {
95+
session->createTimeseries("root.test.d1.s1", TSDataType::INT64, TSEncoding::RLE, CompressionType::SNAPPY);
96+
}
97+
REQUIRE(session->checkTimeseriesExists("root.test.d1.s1") == true);
98+
session->deleteTimeseries("root.test.d1.s1");
99+
session->close();
100+
}
101+
65102
TEST_CASE("Delete timeseries success", "[deleteTimeseries]") {
66103
CaseReporter cr("deleteTimeseries");
67104
if (!session->checkTimeseriesExists("root.test.d1.s1")) {
@@ -715,3 +752,62 @@ TEST_CASE("Test executeLastDataQuery ", "[testExecuteLastDataQuery]") {
715752
sessionDataSet->setFetchSize(1024);
716753
REQUIRE(sessionDataSet->hasNext() == false);
717754
}
755+
756+
// Helper function for comparing TEndPoint with detailed error message
757+
void assertTEndPointEqual(const TEndPoint& actual,
758+
const std::string& expectedIp,
759+
int expectedPort,
760+
const char* file,
761+
int line) {
762+
if (actual.ip != expectedIp || actual.port != expectedPort) {
763+
std::stringstream ss;
764+
ss << "\nTEndPoint mismatch:\nExpected: " << expectedIp << ":" << expectedPort
765+
<< "\nActual: " << actual.ip << ":" << actual.port;
766+
Catch::SourceLineInfo location(file, line);
767+
Catch::AssertionHandler handler("TEndPoint comparison", location, ss.str(), Catch::ResultDisposition::Normal);
768+
handler.handleMessage(Catch::ResultWas::ExplicitFailure, ss.str());
769+
handler.complete();
770+
}
771+
}
772+
773+
// Macro to simplify test assertions
774+
#define REQUIRE_TENDPOINT(actual, expectedIp, expectedPort) \
775+
assertTEndPointEqual(actual, expectedIp, expectedPort, __FILE__, __LINE__)
776+
777+
TEST_CASE("UrlUtils - parseTEndPointIpv4AndIpv6Url", "[UrlUtils]") {
778+
// Test valid IPv4 addresses
779+
SECTION("Valid IPv4") {
780+
REQUIRE_TENDPOINT(UrlUtils::parseTEndPointIpv4AndIpv6Url("192.168.1.1:8080"), "192.168.1.1", 8080);
781+
REQUIRE_TENDPOINT(UrlUtils::parseTEndPointIpv4AndIpv6Url("10.0.0.1:80"), "10.0.0.1", 80);
782+
}
783+
784+
// Test valid IPv6 addresses
785+
SECTION("Valid IPv6") {
786+
REQUIRE_TENDPOINT(UrlUtils::parseTEndPointIpv4AndIpv6Url("[2001:db8::1]:8080"), "2001:db8::1", 8080);
787+
REQUIRE_TENDPOINT(UrlUtils::parseTEndPointIpv4AndIpv6Url("[::1]:80"), "::1", 80);
788+
}
789+
790+
// Test hostnames
791+
SECTION("Hostnames") {
792+
REQUIRE_TENDPOINT(UrlUtils::parseTEndPointIpv4AndIpv6Url("localhost:8080"), "localhost", 8080);
793+
REQUIRE_TENDPOINT(UrlUtils::parseTEndPointIpv4AndIpv6Url("example.com:443"), "example.com", 443);
794+
}
795+
796+
// Test edge cases
797+
SECTION("Edge cases") {
798+
REQUIRE_TENDPOINT(UrlUtils::parseTEndPointIpv4AndIpv6Url(""), "", 0);
799+
REQUIRE_TENDPOINT(UrlUtils::parseTEndPointIpv4AndIpv6Url("127.0.0.1"), "127.0.0.1", 0);
800+
}
801+
802+
// Test invalid inputs
803+
SECTION("Invalid inputs") {
804+
REQUIRE_TENDPOINT(UrlUtils::parseTEndPointIpv4AndIpv6Url("192.168.1.1:abc"), "192.168.1.1:abc", 0);
805+
REQUIRE_TENDPOINT(UrlUtils::parseTEndPointIpv4AndIpv6Url("]invalid[:80"), "]invalid[", 80);
806+
}
807+
808+
// Test port ranges
809+
SECTION("Port ranges") {
810+
REQUIRE_TENDPOINT(UrlUtils::parseTEndPointIpv4AndIpv6Url("localhost:0"), "localhost", 0);
811+
REQUIRE_TENDPOINT(UrlUtils::parseTEndPointIpv4AndIpv6Url("127.0.0.1:65535"), "127.0.0.1", 65535);
812+
}
813+
}

0 commit comments

Comments
 (0)