Skip to content

Anti-pattern free functions on ConnectionImpl and Connection #152

@CuriousGeorgiy

Description

@CuriousGeorgiy

Currently, we have a bunch of free functions on ConnectionImpl and
Connection, such as hasSentBytes, hasNotRecvBytes, hasDataToSend,
hasDataToDecode, etc:

template<class BUFFER, class NetProvider>
void
hasSentBytes(Connection<BUFFER, NetProvider> &conn, size_t bytes)
{
//dropBack()/dropFront() interfaces require number of bytes be greater
//than zero so let's check it first.
if (bytes > 0)
conn.impl->outBuf.dropFront(bytes);
}
template<class BUFFER, class NetProvider>
void
hasNotRecvBytes(Connection<BUFFER, NetProvider> &conn, size_t bytes)
{
if (bytes > 0)
conn.impl->inBuf.dropBack(bytes);
}
template<class BUFFER, class NetProvider>
bool
hasDataToSend(Connection<BUFFER, NetProvider> &conn)
{
//We drop content of input buffer once it has been sent. So to detect
//if there's any data to send it's enough to check buffer's emptiness.
return !conn.impl->outBuf.empty();
}
template<class BUFFER, class NetProvider>
bool
hasDataToDecode(Connection<BUFFER, NetProvider> &conn)
{
assert(conn.impl->endDecoded < conn.impl->inBuf.end() ||
conn.impl->endDecoded == conn.impl->inBuf.end());
return conn.impl->endDecoded != conn.impl->inBuf.end();
}
template<class BUFFER, class NetProvider>
static void
inputBufGC(Connection<BUFFER, NetProvider> &conn)
{
if ((conn.gc_step++ % Connection<BUFFER, NetProvider>::GC_STEP_CNT) == 0) {
TNT_LOG_DEBUG("Flushed input buffer of the connection %p", &conn);
conn.impl->inBuf.flush();
}
}
template<class BUFFER, class NetProvider>
DecodeStatus
processResponse(Connection<BUFFER, NetProvider> &conn, int req_sync, Response<BUFFER> *result)
{
//Decode response. In case of success - fill in feature map
//and adjust end-of-decoded data pointer. Call GC if needed.
if (! conn.impl->inBuf.has(conn.impl->endDecoded, MP_RESPONSE_SIZE))
return DECODE_NEEDMORE;
Response<BUFFER> response;
response.size = conn.impl->dec.decodeResponseSize();
if (response.size < 0) {
TNT_LOG_ERROR("Failed to decode response size");
//In case of corrupted response size all other data in the buffer
//is likely to be decoded in the wrong way (since we don't
// know how much bytes should be skipped). So let's simply
//terminate here.
std::abort();
}
response.size += MP_RESPONSE_SIZE;
if (! conn.impl->inBuf.has(conn.impl->endDecoded, response.size)) {
//Response was received only partially. Reset decoder position
//to the start of response to make this function re-entered.
conn.impl->dec.reset(conn.impl->endDecoded);
return DECODE_NEEDMORE;
}
if (conn.impl->dec.decodeResponse(response) != 0) {
conn.setError("Failed to decode response, skipping bytes..");
conn.impl->endDecoded += response.size;
return DECODE_ERR;
}
TNT_LOG_DEBUG("Header: sync=", response.header.sync, ", code=", response.header.code,
", schema=", response.header.schema_id);
if (result != nullptr && response.header.sync == req_sync) {
*result = std::move(response);
} else {
conn.impl->futures.insert({response.header.sync,
std::move(response)});
}
conn.impl->endDecoded += response.size;
inputBufGC(conn);
return DECODE_SUCC;
}
template<class BUFFER, class NetProvider>
int
decodeGreeting(Connection<BUFFER, NetProvider> &conn)
{
//TODO: that's not zero-copy, should be rewritten in that pattern.
assert(conn.getInBuf().has(conn.impl->endDecoded, Iproto::GREETING_SIZE));
char greeting_buf[Iproto::GREETING_SIZE];
conn.impl->endDecoded.read({greeting_buf, sizeof(greeting_buf)});
conn.impl->dec.reset(conn.impl->endDecoded);
if (parseGreeting(std::string_view{greeting_buf, Iproto::GREETING_SIZE},
conn.impl->greeting) != 0)
return -1;
conn.impl->is_greeting_received = true;
TNT_LOG_DEBUG("Version: ", conn.impl->greeting.version_id);
#ifndef NDEBUG
//print salt in hex format.
char hex_salt[Iproto::MAX_SALT_SIZE * 2 + 1];
const char *hex = "0123456789abcdef";
for (size_t i = 0; i < conn.impl->greeting.salt_size; i++) {
uint8_t u = conn.impl->greeting.salt[i];
hex_salt[i * 2] = hex[u / 16];
hex_salt[i * 2 + 1] = hex[u % 16];
}
hex_salt[conn.impl->greeting.salt_size * 2] = 0;
TNT_LOG_DEBUG("Salt: ", hex_salt);
#endif
return 0;
}

All of them have a ConnectionImpl or Connection
as an argument. This is an anti-pattern, and these functions need to be
encapsulated in the corresponding classes.

Metadata

Metadata

Labels

code healthImprove code readability, simplify maintenance and so onrefactoringCode refactoring

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions