Skip to content

Commit bb2c729

Browse files
committed
Add independent HTTP session management and emergency mode settings
1 parent dd2c1b1 commit bb2c729

File tree

5 files changed

+106
-10
lines changed

5 files changed

+106
-10
lines changed

driver/connection.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,13 @@ class Connection
5757
const TypeInfo & getTypeInfo(const std::string & type_name, const std::string & type_name_without_parameters) const;
5858

5959
Poco::URI getUri() const;
60+
61+
// Getters for session configuration
62+
int getConnectionTimeout() const { return connection_timeout; }
63+
int getTimeout() const { return timeout; }
64+
const std::string& getProto() const { return proto; }
65+
const std::string& getServer() const { return server; }
66+
int getPort() const { return port; }
6067

6168
void connect(const std::string & connection_string);
6269

driver/statement.cpp

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
#include <Poco/Exception.h>
88
#include <Poco/Net/HTTPClientSession.h>
9+
#if !defined(WORKAROUND_DISABLE_SSL)
10+
#include <Poco/Net/HTTPSClientSession.h>
11+
#endif
912
#include <Poco/Net/HTTPRequest.h>
1013
#include <Poco/Timezone.h>
1114
#include <Poco/URI.h>
@@ -19,6 +22,29 @@ Statement::Statement(Connection & connection)
1922
: ChildType(connection)
2023
{
2124
allocateImplicitDescriptors();
25+
26+
// Create independent HTTP session for this statement to avoid concurrent access issues
27+
auto& conn = getParent();
28+
29+
#if !defined(WORKAROUND_DISABLE_SSL)
30+
const auto is_ssl = (Poco::UTF8::icompare(conn.getProto(), "https") == 0);
31+
statement_session = (
32+
is_ssl ? std::make_unique<Poco::Net::HTTPSClientSession>() :
33+
std::make_unique<Poco::Net::HTTPClientSession>()
34+
);
35+
#else
36+
statement_session = std::make_unique<Poco::Net::HTTPClientSession>();
37+
#endif
38+
39+
statement_session->setHost(conn.getServer());
40+
statement_session->setPort(conn.getPort());
41+
statement_session->setKeepAlive(true);
42+
statement_session->setTimeout(
43+
Poco::Timespan(conn.getConnectionTimeout(), 0),
44+
Poco::Timespan(conn.getTimeout(), 0),
45+
Poco::Timespan(conn.getTimeout(), 0)
46+
);
47+
statement_session->setKeepAliveTimeout(Poco::Timespan(86400, 0));
2248
}
2349

2450
Statement::~Statement() {
@@ -108,9 +134,9 @@ void Statement::requestNextPackOfResultSets(std::unique_ptr<ResultMutator> && mu
108134

109135
auto & connection = getParent();
110136

111-
if (connection.session && response && in)
137+
if (statement_session && response && in)
112138
if (in->fail() || !in->eof())
113-
connection.session->reset();
139+
statement_session->reset();
114140

115141
const auto [prepared_query, query_parameters] = prepareHttpRequest();
116142
Poco::URI uri = connection.getUri();
@@ -142,25 +168,25 @@ void Statement::requestNextPackOfResultSets(std::unique_ptr<ResultMutator> && mu
142168
for (int i = 1;; ++i) {
143169
try {
144170
for (; redirect_count < connection.redirect_limit; ++redirect_count) {
145-
connection.session->sendRequest(request) << prepared_query;
171+
statement_session->sendRequest(request) << prepared_query;
146172
response = std::make_unique<Poco::Net::HTTPResponse>();
147-
in = &connection.session->receiveResponse(*response);
173+
in = &statement_session->receiveResponse(*response);
148174
auto status = response->getStatus();
149175
if (status != Poco::Net::HTTPResponse::HTTP_PERMANENT_REDIRECT && status != Poco::Net::HTTPResponse::HTTP_TEMPORARY_REDIRECT) {
150176
break;
151177
}
152-
connection.session->reset(); // reset keepalived connection
178+
statement_session->reset(); // reset keepalived connection
153179
auto newLocation = response->get("Location");
154180
LOG("Redirected to " << newLocation << ", redirect index=" << redirect_count + 1 << "/" << connection.redirect_limit);
155181
uri = newLocation;
156-
connection.session->setHost(uri.getHost());
157-
connection.session->setPort(uri.getPort());
182+
statement_session->setHost(uri.getHost());
183+
statement_session->setPort(uri.getPort());
158184
request.setHost(uri.getHost());
159185
request.setURI(uri.getPathEtc());
160186
}
161187
break;
162188
} catch (const Poco::IOException & e) {
163-
connection.session->reset(); // reset keepalived connection
189+
statement_session->reset(); // reset keepalived connection
164190
LOG("Http request try=" << i << "/" << connection.retry_count << " failed: " << e.what() << ": " << e.message());
165191
if (i > connection.retry_count)
166192
throw;
@@ -376,9 +402,9 @@ bool Statement::advanceToNextResultSet() {
376402

377403
void Statement::closeCursor() {
378404
auto & connection = getParent();
379-
if (connection.session && response && in) {
405+
if (statement_session && response && in) {
380406
if (in->fail() || !in->eof())
381-
connection.session->reset();
407+
statement_session->reset();
382408
}
383409

384410
result_reader.reset();

driver/statement.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "driver/result_set.h"
77

88
#include <Poco/Net/HTTPResponse.h>
9+
#include <Poco/Net/HTTPClientSession.h>
910

1011
#include <memory>
1112
#include <sstream>
@@ -110,6 +111,9 @@ class Statement
110111
std::string query;
111112
std::vector<ParamInfo> parameters;
112113

114+
// Independent HTTP session for each statement to avoid concurrent access issues
115+
std::unique_ptr<Poco::Net::HTTPClientSession> statement_session;
116+
113117
std::unique_ptr<Poco::Net::HTTPResponse> response;
114118
std::istream* in = nullptr;
115119
std::unique_ptr<ResultReader> result_reader;

driver/utils/emergency_mode.h

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#pragma once
2+
3+
#include "driver/platform/platform.h"
4+
5+
#include <cstdlib>
6+
#include <string>
7+
8+
namespace emergency_mode {
9+
10+
// MS-ACCESS緊急モード:最小限のメモリ使用
11+
inline bool isEmergencyMode() {
12+
const char* env_val = std::getenv("CLICKHOUSE_ODBC_EMERGENCY_MODE");
13+
return (env_val != nullptr && std::string(env_val) == "1");
14+
}
15+
16+
// 緊急モード用の極小設定
17+
namespace emergency_settings {
18+
constexpr std::size_t MEMORY_POOL_SIZE = 500; // 500個のみ
19+
constexpr std::size_t PREFETCH_ROWS = 1; // 1行のみ
20+
constexpr std::size_t BUFFER_INCREMENT = 32; // 32バイトずつ
21+
constexpr std::size_t MAX_BUFFER_SIZE = 8192; // 8KB制限
22+
constexpr std::size_t MAX_INPUT_SIZE = 4096; // 4KB制限
23+
constexpr std::size_t MAX_ITERATIONS = 20; // 20回制限
24+
}
25+
26+
// 緊急モード用の安全な値を取得
27+
inline std::size_t getSafeMemoryPoolSize() {
28+
return isEmergencyMode() ? emergency_settings::MEMORY_POOL_SIZE : 1000;
29+
}
30+
31+
inline std::size_t getSafePrefetchRows() {
32+
return isEmergencyMode() ? emergency_settings::PREFETCH_ROWS : 1;
33+
}
34+
35+
inline std::size_t getSafeBufferIncrement() {
36+
return isEmergencyMode() ? emergency_settings::BUFFER_INCREMENT : 64;
37+
}
38+
39+
inline std::size_t getSafeMaxBufferSize() {
40+
return isEmergencyMode() ? emergency_settings::MAX_BUFFER_SIZE : 32768;
41+
}
42+
43+
inline std::size_t getSafeMaxInputSize() {
44+
return isEmergencyMode() ? emergency_settings::MAX_INPUT_SIZE : 16384;
45+
}
46+
47+
inline std::size_t getSafeMaxIterations() {
48+
return isEmergencyMode() ? emergency_settings::MAX_ITERATIONS : 50;
49+
}
50+
51+
} // namespace emergency_mode

driver/utils/object_pool.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@ class ObjectPool {
3333
}
3434
}
3535

36+
std::size_t getSize() const {
37+
return cache_.size();
38+
}
39+
40+
void clear() {
41+
cache_.clear();
42+
}
43+
3644
private:
3745
const std::size_t max_size_;
3846
std::deque<T> cache_;

0 commit comments

Comments
 (0)