Skip to content

Commit

Permalink
Optimize Copier by reducing memory allocations
Browse files Browse the repository at this point in the history
  • Loading branch information
dmitigr committed Mar 16, 2022
1 parent c3a2e1b commit 0557f4a
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 12 deletions.
14 changes: 8 additions & 6 deletions src/pgfe/copier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,21 +109,23 @@ DMITIGR_PGFE_INLINE bool Copier::end(const std::string& error_message) const
DMITIGR_ASSERT(false);
}

DMITIGR_PGFE_INLINE std::unique_ptr<Data> Copier::receive(const bool wait) const
DMITIGR_PGFE_INLINE Data_view Copier::receive(const bool wait) const
{
check_receive();

buffer_ = decltype(buffer_){nullptr, &dummy_free};
char* buffer{};
const int size{PQgetCopyData(connection().conn(), &buffer, !wait)};
DMITIGR_ASSERT(!buffer || size > 0);
if (buffer)
buffer_ = decltype(buffer_){buffer, &::PQfreemem};
DMITIGR_ASSERT(!buffer_ || size > 0);

if (size == -1)
return nullptr;
return Data_view{};
else if (size == 0)
return Data::make(std::string_view{"", 0}, data_format(0));
return Data_view{"", 0, data_format(0)};
else if (size > 0)
return Data::make(std::unique_ptr<char, void(*)(void*)>{buffer, &::PQfreemem},
static_cast<std::size_t>(size), data_format(0));
return Data_view{buffer_.get(), static_cast<std::size_t>(size), data_format(0)};
else if (size == -2)
throw Client_exception{PQerrorMessage(connection().conn())};

Expand Down
14 changes: 9 additions & 5 deletions src/pgfe/copier.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
#include "dll.hpp"
#include "response.hpp"

#include <memory>

namespace dmitigr::pgfe {

/**
Expand Down Expand Up @@ -124,14 +126,14 @@ class Copier final : public Response {
* `data_direction() == Data_direction::from_server`.
*
* @returns Returns:
* -# `nullptr` if the `COPY` command is done;
* -# the empty data to indicate that the COPY is undone, but no row is yet
* available (this is only possible when `wait` is `false`);
* -# the non-empty data received from the server.
* -# invalid instance if the `COPY` command is done;
* -# the empty instance to indicate that the COPY is undone, but no row is
* yet available (this is only possible when `wait` is `false`);
* -# the non-empty instance received from the server.
*
* @remarks The format of returned data is equals to `data_format(0)`.
*/
DMITIGR_PGFE_API std::unique_ptr<Data> receive(bool wait = true) const;
DMITIGR_PGFE_API Data_view receive(bool wait = true) const;

/**
* @returns The underlying connection instance.
Expand All @@ -149,11 +151,13 @@ class Copier final : public Response {

Connection* connection_{};
detail::pq::Result pq_result_;
mutable std::unique_ptr<char, void(*)(void*)> buffer_{nullptr, &dummy_free};

/// The constructor.
explicit DMITIGR_PGFE_API Copier(Connection& connection,
detail::pq::Result&& pq_result) noexcept;

static inline void dummy_free(void*)noexcept{};
void check_send() const;
void check_receive() const;
};
Expand Down
2 changes: 1 addition & 1 deletion test/pgfe/pgfe-unit-copier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ try {
ASSERT(copier.data_direction() == pgfe::Data_direction::from_server);
int i{};
while (const auto data = copier.receive()) {
const char* const bytes = static_cast<const char*>(data->bytes()); // with '\n'
const char* const bytes = static_cast<const char*>(data.bytes()); // with '\n'
ASSERT(expected[i++] == bytes);
std::cout << bytes;
}
Expand Down

0 comments on commit 0557f4a

Please sign in to comment.