diff --git a/include/dwarfs/zstd_context_manager.h b/include/dwarfs/zstd_context_manager.h new file mode 100644 index 00000000..943d2b6f --- /dev/null +++ b/include/dwarfs/zstd_context_manager.h @@ -0,0 +1,91 @@ +/* vim:set ts=2 sw=2 sts=2 et: */ +/** + * \author Marcus Holland-Moritz (github@mhxnet.de) + * \copyright Copyright (c) Marcus Holland-Moritz + * + * This file is part of dwarfs. + * + * dwarfs is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * dwarfs is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with dwarfs. If not, see . + */ + +#pragma once + +#include +#include + +#include + +namespace dwarfs { + +class zstd_context_manager; + +class zstd_scoped_context { + friend class zstd_context_manager; + + public: + ~zstd_scoped_context(); + + zstd_scoped_context(zstd_scoped_context&&) = default; + zstd_scoped_context& operator=(zstd_scoped_context&&) = default; + + ZSTD_CCtx* get() const { return ctx_; } + + private: + explicit zstd_scoped_context(zstd_context_manager* mgr); + + zstd_context_manager* mgr_; + ZSTD_CCtx* ctx_; +}; + +class zstd_context_manager { + friend class zstd_scoped_context; + + public: + zstd_context_manager() = default; + + ~zstd_context_manager() { + for (auto ctx : ctx_) { + ZSTD_freeCCtx(ctx); + } + } + + zstd_scoped_context make_context() { return zstd_scoped_context(this); } + + private: + ZSTD_CCtx* acquire() { + std::lock_guard lock(mx_); + if (ctx_.empty()) { + return ZSTD_createCCtx(); + } + auto ctx = ctx_.back(); + ctx_.pop_back(); + return ctx; + } + + void release(ZSTD_CCtx* ctx) { + std::lock_guard lock(mx_); + ctx_.push_back(ctx); + } + + std::mutex mx_; + std::vector ctx_; +}; + +inline zstd_scoped_context::zstd_scoped_context(zstd_context_manager* mgr) + : mgr_{mgr} + , ctx_{mgr_->acquire()} {} + +inline zstd_scoped_context::~zstd_scoped_context() { mgr_->release(ctx_); } + +} // namespace dwarfs diff --git a/src/dwarfs/compression/zstd.cpp b/src/dwarfs/compression/zstd.cpp index a6634e5b..89220319 100644 --- a/src/dwarfs/compression/zstd.cpp +++ b/src/dwarfs/compression/zstd.cpp @@ -29,6 +29,7 @@ #include "dwarfs/error.h" #include "dwarfs/fstypes.h" #include "dwarfs/option_map.h" +#include "dwarfs/zstd_context_manager.h" #if ZSTD_VERSION_MAJOR > 1 || \ (ZSTD_VERSION_MAJOR == 1 && ZSTD_VERSION_MINOR >= 4) @@ -75,85 +76,28 @@ class zstd_block_compressor final : public block_compressor::impl { } private: - class scoped_context; - - class context_manager { - public: - context_manager() = default; - - ~context_manager() { - for (auto ctx : ctx_) { - ZSTD_freeCCtx(ctx); - } - } - - private: - friend class scoped_context; - - ZSTD_CCtx* acquire() { - std::lock_guard lock(mx_); - if (ctx_.empty()) { - return ZSTD_createCCtx(); - } - auto ctx = ctx_.back(); - ctx_.pop_back(); - return ctx; - } - - void release(ZSTD_CCtx* ctx) { - std::lock_guard lock(mx_); - ctx_.push_back(ctx); - } - - std::mutex mx_; - std::vector ctx_; - }; - - class scoped_context { - public: - explicit scoped_context(context_manager& mgr) - : mgr_{&mgr} - , ctx_{mgr_->acquire()} {} - ~scoped_context() { mgr_->release(ctx_); } - - scoped_context(scoped_context const&) = delete; - scoped_context(scoped_context&&) = default; - scoped_context& operator=(scoped_context const&) = delete; - scoped_context& operator=(scoped_context&&) = default; - - ZSTD_CCtx* get() const { return ctx_; } - - private: - context_manager* mgr_; - ZSTD_CCtx* ctx_; - }; - - static std::shared_ptr get_context_manager() { + static std::shared_ptr get_context_manager() { std::lock_guard lock(s_mx); if (auto mgr = s_ctxmgr.lock()) { return mgr; } - auto mgr = std::make_shared(); + auto mgr = std::make_shared(); s_ctxmgr = mgr; return mgr; } - static std::mutex s_mx; - static std::weak_ptr s_ctxmgr; + static inline std::mutex s_mx; + static inline std::weak_ptr s_ctxmgr; - std::shared_ptr ctxmgr_; + std::shared_ptr ctxmgr_; const int level_; }; -std::mutex zstd_block_compressor::s_mx; -std::weak_ptr - zstd_block_compressor::s_ctxmgr; - std::vector zstd_block_compressor::compress(const std::vector& data, std::string const* /*metadata*/) const { std::vector compressed(ZSTD_compressBound(data.size())); - scoped_context ctx(*ctxmgr_); + auto ctx = ctxmgr_->make_context(); auto size = ZSTD_compressCCtx(ctx.get(), compressed.data(), compressed.size(), data.data(), data.size(), level_); if (ZSTD_isError(size)) {