Skip to content

Commit b4fe02f

Browse files
committed
Fixed issue ClickHouse#335 by making at least one connection attempt
1 parent 911ce93 commit b4fe02f

File tree

4 files changed

+89
-9
lines changed

4 files changed

+89
-9
lines changed

clickhouse/client.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -385,14 +385,15 @@ void Client::Impl::ResetConnectionEndpoint() {
385385
}
386386

387387
void Client::Impl::CreateConnection() {
388-
for (size_t i = 0; i < options_.send_retries;)
388+
// i <= 1 to try at least once
389+
for (size_t i = 0; i <= 1 || i < options_.send_retries;)
389390
{
390391
try
391392
{
392393
ResetConnectionEndpoint();
393394
return;
394395
} catch (const std::system_error&) {
395-
if (++i == options_.send_retries)
396+
if (++i >= options_.send_retries)
396397
{
397398
throw;
398399
}

clickhouse/columns/string.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ ColumnString::ColumnString(const std::vector<std::string>& data)
173173
for (const auto & s : data) {
174174
AppendUnsafe(s);
175175
}
176-
};
176+
}
177177

178178
ColumnString::ColumnString(std::vector<std::string>&& data)
179179
: ColumnString()

ut/client_ut.cpp

Lines changed: 78 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,36 @@
11
#include <clickhouse/client.h>
22

3+
#include "clickhouse/base/socket.h"
34
#include "readonly_client_test.h"
45
#include "connection_failed_client_test.h"
6+
#include "ut/utils_comparison.h"
57
#include "utils.h"
8+
#include "ut/roundtrip_column.h"
9+
#include "ut/value_generators.h"
610

711
#include <gtest/gtest.h>
812

13+
#include <memory>
914
#include <optional>
15+
#include <string_view>
1016
#include <thread>
1117
#include <chrono>
1218

1319
using namespace clickhouse;
1420

21+
22+
template <typename T>
23+
std::shared_ptr<T> createTableWithOneColumn(Client & client, const std::string & table_name, const std::string & column_name)
24+
{
25+
auto col = std::make_shared<T>();
26+
const auto type_name = col->GetType().GetName();
27+
28+
client.Execute("DROP TEMPORARY TABLE IF EXISTS " + table_name + ";");
29+
client.Execute("CREATE TEMPORARY TABLE IF NOT EXISTS " + table_name + "( " + column_name + " " + type_name + " )");
30+
31+
return col;
32+
}
33+
1534
// Use value-parameterized tests to run same tests with different client
1635
// options.
1736
class ClientCase : public testing::TestWithParam<ClientOptions> {
@@ -27,13 +46,9 @@ class ClientCase : public testing::TestWithParam<ClientOptions> {
2746
template <typename T>
2847
std::shared_ptr<T> createTableWithOneColumn(Block & block)
2948
{
30-
auto col = std::make_shared<T>();
31-
const auto type_name = col->GetType().GetName();
32-
33-
client_->Execute("DROP TEMPORARY TABLE IF EXISTS " + table_name + ";");
34-
client_->Execute("CREATE TEMPORARY TABLE IF NOT EXISTS " + table_name + "( " + column_name + " " + type_name + " )");
49+
auto col = ::createTableWithOneColumn<T>(*client_, table_name, column_name);
3550

36-
block.AppendColumn("test_column", col);
51+
block.AppendColumn(column_name, col);
3752

3853
return col;
3954
}
@@ -1352,3 +1367,60 @@ INSTANTIATE_TEST_SUITE_P(ResetConnectionClientTest, ResetConnectionTestCase,
13521367
.SetRetryTimeout(std::chrono::seconds(1))
13531368
}
13541369
));
1370+
1371+
struct CountingSocketFactoryAdapter : public SocketFactory {
1372+
struct Counters
1373+
{
1374+
size_t connect_count = 0;
1375+
1376+
void Reset() {
1377+
*this = Counters();
1378+
}
1379+
};
1380+
1381+
SocketFactory & socket_factory;
1382+
Counters& counters;
1383+
1384+
CountingSocketFactoryAdapter(SocketFactory & socket_factory, Counters& counters)
1385+
: socket_factory(socket_factory)
1386+
, counters(counters)
1387+
{}
1388+
1389+
std::unique_ptr<SocketBase> connect(const ClientOptions& opts, const Endpoint& endpoint) {
1390+
++counters.connect_count;
1391+
return socket_factory.connect(opts, endpoint);
1392+
}
1393+
1394+
void sleepFor(const std::chrono::milliseconds& duration) {
1395+
return socket_factory.sleepFor(duration);
1396+
}
1397+
1398+
};
1399+
1400+
TEST(SimpleClientTest, issue_335) {
1401+
auto vals = MakeStrings();
1402+
auto col = std::make_shared<ColumnString>(vals);
1403+
1404+
CountingSocketFactoryAdapter::Counters counters;
1405+
std::unique_ptr<SocketFactory> wrapped_socket_factory = std::make_unique<NonSecureSocketFactory>();
1406+
std::unique_ptr<SocketFactory> socket_factory = std::make_unique<CountingSocketFactoryAdapter>(*wrapped_socket_factory, counters);
1407+
1408+
Client client(ClientOptions(LocalHostEndpoint)
1409+
.SetSendRetries(0), // <<=== crucial for reproducing https://github.com/ClickHouse/clickhouse-cpp/issues/335
1410+
std::move(socket_factory));
1411+
1412+
EXPECT_EQ(1u, counters.connect_count);
1413+
EXPECT_TRUE(CompareRecursive(vals, *RoundtripColumnValuesTyped(client, col)));
1414+
1415+
counters.Reset();
1416+
1417+
client.ResetConnection();
1418+
EXPECT_EQ(1u, counters.connect_count);
1419+
EXPECT_TRUE(CompareRecursive(vals, *RoundtripColumnValuesTyped(client, col)));
1420+
1421+
counters.Reset();
1422+
1423+
client.ResetConnectionEndpoint();
1424+
EXPECT_EQ(1u, counters.connect_count);
1425+
EXPECT_TRUE(CompareRecursive(vals, *RoundtripColumnValuesTyped(client, col)));
1426+
}

ut/roundtrip_column.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
#pragma once
22

33
#include <clickhouse/columns/column.h>
4+
#include <memory>
45

56
namespace clickhouse {
67
class Client;
78
}
89

910
clickhouse::ColumnRef RoundtripColumnValues(clickhouse::Client& client, clickhouse::ColumnRef expected);
11+
12+
template <typename T>
13+
auto RoundtripColumnValuesTyped(clickhouse::Client& client, std::shared_ptr<T> expected_col)
14+
{
15+
return RoundtripColumnValues(client, expected_col)->template As<T>();
16+
}

0 commit comments

Comments
 (0)