From 0557f4a9fd8249d7d2604fe6093a76966bf7877d Mon Sep 17 00:00:00 2001 From: Dmitry Igrishin Date: Wed, 16 Mar 2022 19:37:21 +0300 Subject: [PATCH] Optimize Copier by reducing memory allocations --- src/pgfe/copier.cpp | 14 ++++++++------ src/pgfe/copier.hpp | 14 +++++++++----- test/pgfe/pgfe-unit-copier.cpp | 2 +- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/pgfe/copier.cpp b/src/pgfe/copier.cpp index b4da528..a53630b 100644 --- a/src/pgfe/copier.cpp +++ b/src/pgfe/copier.cpp @@ -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 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{buffer, &::PQfreemem}, - static_cast(size), data_format(0)); + return Data_view{buffer_.get(), static_cast(size), data_format(0)}; else if (size == -2) throw Client_exception{PQerrorMessage(connection().conn())}; diff --git a/src/pgfe/copier.hpp b/src/pgfe/copier.hpp index 6fe17e7..e8f049d 100644 --- a/src/pgfe/copier.hpp +++ b/src/pgfe/copier.hpp @@ -27,6 +27,8 @@ #include "dll.hpp" #include "response.hpp" +#include + namespace dmitigr::pgfe { /** @@ -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 receive(bool wait = true) const; + DMITIGR_PGFE_API Data_view receive(bool wait = true) const; /** * @returns The underlying connection instance. @@ -149,11 +151,13 @@ class Copier final : public Response { Connection* connection_{}; detail::pq::Result pq_result_; + mutable std::unique_ptr 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; }; diff --git a/test/pgfe/pgfe-unit-copier.cpp b/test/pgfe/pgfe-unit-copier.cpp index 475b1b3..57c2888 100644 --- a/test/pgfe/pgfe-unit-copier.cpp +++ b/test/pgfe/pgfe-unit-copier.cpp @@ -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(data->bytes()); // with '\n' + const char* const bytes = static_cast(data.bytes()); // with '\n' ASSERT(expected[i++] == bytes); std::cout << bytes; }