Skip to content

Commit c8b73c2

Browse files
committed
Removes coalesce property of the requests.
It doesn't make any sense after the implementation of full-duplex communication.
1 parent 8b02268 commit c8b73c2

File tree

10 files changed

+212
-268
lines changed

10 files changed

+212
-268
lines changed

CMakeLists.txt

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -224,14 +224,6 @@ if (MSVC)
224224
target_compile_definitions(test_conn_quit PRIVATE _WIN32_WINNT=0x0601)
225225
endif()
226226

227-
add_executable(test_conn_quit_coalesce tests/conn_quit_coalesce.cpp)
228-
add_test(test_conn_quit_coalesce test_conn_quit_coalesce)
229-
target_compile_features(test_conn_quit_coalesce PUBLIC cxx_std_17)
230-
if (MSVC)
231-
target_compile_options(test_conn_quit_coalesce PRIVATE /bigobj)
232-
target_compile_definitions(test_conn_quit_coalesce PRIVATE _WIN32_WINNT=0x0601)
233-
endif()
234-
235227
add_executable(test_conn_reconnect tests/conn_reconnect.cpp)
236228
target_compile_features(test_conn_reconnect PUBLIC cxx_std_20)
237229
target_link_libraries(test_conn_reconnect common)

README.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -261,10 +261,8 @@ co_await (conn.async_exec(...) || time.async_wait(...))
261261
co_await (conn.async_exec(...) || conn.async_exec(...) || ... || conn.async_exec(...))
262262
```
263263

264-
* This works but is unnecessary. Unless the user has set
265-
`boost::redis::request::config::coalesce` to `false`, and he
266-
usually shouldn't, the connection will automatically merge the
267-
individual requests into a single payload.
264+
* This works but is unnecessary, the connection will automatically
265+
merge the individual requests into a single payload.
268266

269267
<a name="requests"></a>
270268
## Requests
@@ -874,11 +872,16 @@ Acknowledgement to people that helped shape Boost.Redis
874872
including possible resp3 errors without losing the error diagnostic
875873
part. Basicaly instead of accessing values as `std::get<N>(resp)`
876874
users have to type `std::get<N>(resp).value()`
875+
* Implements full-duplex communication. Before these changes the
876+
connection would wait for a response to arrive before sending the
877+
next. Now requests are continuously coalesced and written to the
878+
socket. This made the request::coalesce unnecessary and threfore it
879+
was removed.
877880

878881
### v1.4.0-1
879882

880883
* Renames `retry_on_connection_lost` to `cancel_if_unresponded`. (v1.4.1)
881-
* Removes dependency on Boost.Hana, boost::string_view, Boost.Variant2 and Boost.Spirit.
884+
* Removes dependency on Boost.Hana, `boost::string_view`, Boost.Variant2 and Boost.Spirit.
882885
* Fixes build and setup CI on windows.
883886

884887
### v1.3.0-1

include/boost/redis/detail/connection_base.hpp

Lines changed: 10 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ class connection_base {
193193
// There is small optimization possible here: traverse only the
194194
// partition of unwritten requests instead of them all.
195195
std::for_each(std::begin(reqs_), std::end(reqs_), [](auto const& ptr) {
196+
BOOST_ASSERT_MSG(ptr != nullptr, "Expects non-null pointer.");
196197
if (ptr->is_staged())
197198
ptr->mark_written();
198199
});
@@ -364,35 +365,21 @@ class connection_base {
364365
>(detail::exec_read_op<Derived, Adapter>{&derived(), adapter, cmds}, token, writer_timer_);
365366
}
366367

367-
void stage_request(req_info& ri)
368-
{
369-
write_buffer_ += ri.get_request().payload();
370-
ri.mark_staged();
371-
}
372-
373368
[[nodiscard]] bool coalesce_requests()
374369
{
375370
// Coalesces the requests and marks them staged. After a
376371
// successful write staged requests will be marked as written.
377-
std::size_t pos = 0;
378-
for (; pos < std::size(reqs_); ++pos)
379-
if (reqs_.at(pos)->is_waiting_write())
380-
break;
381-
382-
if (pos == std::size(reqs_))
383-
return false;
384-
385-
stage_request(*reqs_.at(pos));
372+
auto const point = std::partition_point(std::cbegin(reqs_), std::cend(reqs_), [](auto const& ri) {
373+
return !ri->is_waiting_write();
374+
});
386375

387-
for (std::size_t i = pos + 1; i < std::size(reqs_); ++i) {
388-
if (!reqs_.at(i - 1)->get_request().get_config().coalesce ||
389-
!reqs_.at(i - 0)->get_request().get_config().coalesce) {
390-
break;
391-
}
392-
stage_request(*reqs_.at(i));
393-
}
376+
std::for_each(point, std::cend(reqs_), [this](auto const& ri) {
377+
// Stage the request.
378+
write_buffer_ += ri->get_request().payload();
379+
ri->mark_staged();
380+
});
394381

395-
return true;
382+
return point != std::cend(reqs_);
396383
}
397384

398385
bool is_waiting_response() const noexcept

include/boost/redis/request.hpp

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,6 @@ class request {
5555
*/
5656
bool cancel_on_connection_lost = true;
5757

58-
/** \brief If `true` the request will be coalesced with other
59-
* requests, see https://redis.io/topics/pipelining. Otherwise
60-
* the request is sent individually.
61-
*/
62-
bool coalesce = true;
63-
6458
/** \brief If `true` the request will complete with
6559
* boost::redis::error::not_connected if `async_exec` is called before
6660
* the connection with Redis was established.
@@ -88,7 +82,7 @@ class request {
8882
* \param cfg Configuration options.
8983
*/
9084
explicit
91-
request(config cfg = config{true, true, false, true, true})
85+
request(config cfg = config{true, false, true, true})
9286
: cfg_{cfg} {}
9387

9488
//// Returns the number of commands contained in this request.

tests/conn_exec.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,15 @@ using boost::redis::ignore_t;
3030
BOOST_AUTO_TEST_CASE(hello_priority)
3131
{
3232
request req1;
33-
req1.get_config().coalesce = false;
3433
req1.push("PING", "req1");
3534

3635
request req2;
37-
req2.get_config().coalesce = false;
3836
req2.get_config().hello_with_priority = false;
3937
req2.push("HELLO", 3);
4038
req2.push("PING", "req2");
4139
req2.push("QUIT");
4240

4341
request req3;
44-
req3.get_config().coalesce = false;
4542
req3.get_config().hello_with_priority = true;
4643
req3.push("HELLO", 3);
4744
req3.push("PING", "req3");

tests/conn_exec_cancel.cpp

Lines changed: 42 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,10 @@ auto async_ignore_explicit_cancel_of_req_written() -> net::awaitable<void>
4949

5050
// See NOTE1.
5151
request req0;
52-
req0.get_config().coalesce = false;
5352
req0.push("HELLO", 3);
5453
co_await conn->async_exec(req0, gresp, net::use_awaitable);
5554

5655
request req1;
57-
req1.get_config().coalesce = false;
5856
req1.push("BLPOP", "any", 3);
5957

6058
// Should not be canceled.
@@ -97,82 +95,79 @@ auto ignore_implicit_cancel_of_req_written() -> net::awaitable<void>
9795

9896
// See NOTE1.
9997
request req0;
100-
req0.get_config().coalesce = false;
10198
req0.push("HELLO", 3);
102-
std::ignore = co_await conn->async_exec(req0, ignore, net::use_awaitable);
99+
co_await conn->async_exec(req0, ignore, net::use_awaitable);
103100

104101
// Will be cancelled after it has been written but before the
105102
// response arrives.
106103
request req1;
107-
req1.get_config().coalesce = false;
108104
req1.push("BLPOP", "any", 3);
109105

110-
// Will be cancelled before it is written.
111-
request req2;
112-
req2.get_config().coalesce = false;
113-
req2.get_config().cancel_on_connection_lost = true;
114-
req2.push("PING");
115-
116106
net::steady_timer st{ex};
117107
st.expires_after(std::chrono::seconds{1});
118108

119-
boost::system::error_code ec1, ec2, ec3;
109+
boost::system::error_code ec1, ec2;
120110
co_await (
121111
conn->async_exec(req1, ignore, redir(ec1)) ||
122-
conn->async_exec(req2, ignore, redir(ec2)) ||
123-
st.async_wait(redir(ec3))
112+
st.async_wait(redir(ec2))
124113
);
125114

126115
BOOST_CHECK_EQUAL(ec1, net::error::basic_errors::operation_aborted);
127-
BOOST_CHECK_EQUAL(ec2, net::error::basic_errors::operation_aborted);
128-
BOOST_TEST(!ec3);
116+
BOOST_TEST(!ec2);
117+
}
118+
119+
BOOST_AUTO_TEST_CASE(test_ignore_explicit_cancel_of_req_written)
120+
{
121+
run(async_ignore_explicit_cancel_of_req_written());
122+
}
123+
124+
BOOST_AUTO_TEST_CASE(test_ignore_implicit_cancel_of_req_written)
125+
{
126+
run(ignore_implicit_cancel_of_req_written());
129127
}
130128

131-
auto cancel_of_req_written_on_run_canceled() -> net::awaitable<void>
129+
BOOST_AUTO_TEST_CASE(test_cancel_of_req_written_on_run_canceled)
132130
{
131+
net::io_context ioc;
132+
auto const endpoints = resolve();
133+
connection conn{ioc};
134+
net::connect(conn.next_layer(), endpoints);
135+
133136
request req0;
134-
req0.get_config().coalesce = false;
135137
req0.push("HELLO", 3);
136138

139+
// Sends a request that will be blocked forever, so we can test
140+
// canceling it while waiting for a response.
137141
request req1;
138142
req1.get_config().cancel_on_connection_lost = true;
139143
req1.get_config().cancel_if_unresponded = true;
140144
req1.push("BLPOP", "any", 0);
141145

142-
auto ex = co_await net::this_coro::executor;
143-
auto conn = std::make_shared<connection>(ex);
144-
co_await connect(conn, "127.0.0.1", "6379");
145-
146-
net::steady_timer st{ex};
147-
st.expires_after(std::chrono::seconds{1});
146+
auto c1 = [&](auto ec, auto)
147+
{
148+
BOOST_CHECK_EQUAL(ec, net::error::basic_errors::operation_aborted);
149+
};
148150

149-
boost::system::error_code ec0, ec1, ec2, ec3;
150-
co_await (
151-
conn->async_exec(req0, ignore, redir(ec0)) &&
152-
(conn->async_exec(req1, ignore, redir(ec1)) ||
153-
conn->async_run(redir(ec2)) ||
154-
st.async_wait(redir(ec3)))
155-
);
151+
auto c0 = [&](auto ec, auto)
152+
{
153+
BOOST_TEST(!ec);
154+
conn.async_exec(req1, ignore, c1);
155+
};
156156

157-
BOOST_TEST(!ec0);
158-
BOOST_CHECK_EQUAL(ec1, net::error::basic_errors::operation_aborted);
159-
BOOST_CHECK_EQUAL(ec2, net::error::basic_errors::operation_aborted);
160-
BOOST_TEST(!ec3);
161-
}
157+
conn.async_exec(req0, ignore, c0);
162158

163-
BOOST_AUTO_TEST_CASE(test_ignore_explicit_cancel_of_req_written)
164-
{
165-
run(async_ignore_explicit_cancel_of_req_written());
166-
}
159+
conn.async_run([](auto ec){
160+
BOOST_CHECK_EQUAL(ec, net::error::basic_errors::operation_aborted);
161+
});
167162

168-
BOOST_AUTO_TEST_CASE(test_ignore_implicit_cancel_of_req_written)
169-
{
170-
run(ignore_implicit_cancel_of_req_written());
171-
}
163+
net::steady_timer st{ioc};
164+
st.expires_after(std::chrono::seconds{1});
165+
st.async_wait([&](auto ec){
166+
BOOST_TEST(!ec);
167+
conn.cancel(operation::run);
168+
});
172169

173-
BOOST_AUTO_TEST_CASE(test_cancel_of_req_written_on_run_canceled)
174-
{
175-
run(cancel_of_req_written_on_run_canceled());
170+
ioc.run();
176171
}
177172

178173
#else

0 commit comments

Comments
 (0)