Skip to content

Commit 8705817

Browse files
client: add connection bookkeeping to Connector for waitAny robustness
Currently, all connection bookkeeping is done opaquely through the network providers which, in turn, also do this bookkeeping opaquely using system interfaces (e.g., libev, epoll). Because of this, we cannot handle cases when waitAny is called and there are no connections (gh-51) or when a connection has ready responses (gh-132). In order to improve `waitAny` robustness, we need to add connection bookkeeping to Connector. We should move the timer start to the beginning of the waiting loop, since the preceding checking overhead should not be accounted for the waiting time. Closes #51 Needed for #132
1 parent 1a5f36c commit 8705817

File tree

3 files changed

+32
-4
lines changed

3 files changed

+32
-4
lines changed

src/Client/Connection.hpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ struct ConnectionImpl
8383
const typename NetProvider::Stream_t &get_strm() const { return strm; }
8484

8585
void setError(const std::string &msg, int errno_ = 0);
86+
bool hasError() const;
8687

8788
BUFFER &getInBuf();
8889
BUFFER &getOutBuf();
@@ -153,6 +154,13 @@ ConnectionImpl<BUFFER, NetProvider>::setError(const std::string &msg, int errno_
153154
error.emplace(msg, errno_);
154155
}
155156

157+
template <class BUFFER, class NetProvider>
158+
bool
159+
ConnectionImpl<BUFFER, NetProvider>::hasError() const
160+
{
161+
return error.has_value();
162+
}
163+
156164
template <class BUFFER, class NetProvider>
157165
BUFFER &
158166
ConnectionImpl<BUFFER, NetProvider>::getInBuf()
@@ -465,7 +473,7 @@ template<class BUFFER, class NetProvider>
465473
bool
466474
Connection<BUFFER, NetProvider>::hasError() const
467475
{
468-
return impl->error.has_value();
476+
return impl->hasError();
469477
}
470478

471479
template<class BUFFER, class NetProvider>

src/Client/Connector.hpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,10 @@ class Connector
129129
* and `connectionDecodeResponses`.
130130
*/
131131
std::set<ConnectionImpl<BUFFER, NetProvider> *> m_ReadyToDecode;
132+
/**
133+
* Set of active connections owned by connector.
134+
*/
135+
std::set<ConnectionImpl<BUFFER, NetProvider> *> m_Connections;
132136
};
133137

134138
template<class BUFFER, class NetProvider>
@@ -161,6 +165,7 @@ Connector<BUFFER, NetProvider>::connect(Connection<BUFFER, NetProvider> &conn,
161165
}
162166
LOG_DEBUG("Connection to ", opts.address, ':', opts.service,
163167
" has been established");
168+
m_Connections.insert(conn.getImpl());
164169
return 0;
165170
}
166171

@@ -190,6 +195,7 @@ Connector<BUFFER, NetProvider>::close(ConnectionImpl<BUFFER, NetProvider> *conn)
190195
{
191196
if (conn->get_strm().get_fd() != -1) {
192197
m_NetProvider.close(conn->get_strm());
198+
m_Connections.erase(conn);
193199
}
194200
}
195201

@@ -354,9 +360,22 @@ template<class BUFFER, class NetProvider>
354360
std::optional<Connection<BUFFER, NetProvider>>
355361
Connector<BUFFER, NetProvider>::waitAny(int timeout)
356362
{
363+
if (m_Connections.empty()) {
364+
LOG_DEBUG("waitAny() called on connector without connections");
365+
return std::nullopt;
366+
}
357367
Timer timer{timeout};
358368
timer.start();
359369
while (m_ReadyToDecode.empty()) {
370+
bool any_conn_has_no_err = false;
371+
for (auto *conn : m_Connections) {
372+
if (!conn->hasError())
373+
any_conn_has_no_err = true;
374+
}
375+
if (!any_conn_has_no_err) {
376+
LOG_ERROR("All connections have an error");
377+
return std::nullopt;
378+
}
360379
if (m_NetProvider.wait(timer.timeLeft()) != 0) {
361380
LOG_ERROR("Failed to poll connections: ", strerror(errno));
362381
return std::nullopt;

test/ClientTest.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1101,11 +1101,9 @@ test_dead_connection_wait(void)
11011101
fail_if(client.waitCount(conn, 1) == 0);
11021102
fail_if(conn.futureIsReady(f));
11031103

1104-
/* FIXME(gh-51) */
1105-
#if 0
1104+
TEST_CASE("waitAny() correctly handles case when all connections have an error (gh-51");
11061105
fail_if(client.waitAny() != std::nullopt);
11071106
fail_if(conn.futureIsReady(f));
1108-
#endif
11091107
}
11101108

11111109
/**
@@ -1434,6 +1432,9 @@ test_wait(Connector<BUFFER, NetProvider> &client)
14341432
#endif /* __linux__ */
14351433

14361434
client.close(conn);
1435+
1436+
TEST_CASE("waitAny() correctly handles case when there are no connections (gh-51");
1437+
fail_if(client.waitAny() != std::nullopt);
14371438
}
14381439

14391440
int main()

0 commit comments

Comments
 (0)