Factor out zstd context manager

This commit is contained in:
Marcus Holland-Moritz 2023-09-05 10:11:30 +02:00
parent 9ac06fe40d
commit bad2c5e057
2 changed files with 98 additions and 63 deletions

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <mutex>
#include <vector>
#include <zstd.h>
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<ZSTD_CCtx*> 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

View File

@ -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<ZSTD_CCtx*> 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<context_manager> get_context_manager() {
static std::shared_ptr<zstd_context_manager> get_context_manager() {
std::lock_guard lock(s_mx);
if (auto mgr = s_ctxmgr.lock()) {
return mgr;
}
auto mgr = std::make_shared<context_manager>();
auto mgr = std::make_shared<zstd_context_manager>();
s_ctxmgr = mgr;
return mgr;
}
static std::mutex s_mx;
static std::weak_ptr<context_manager> s_ctxmgr;
static inline std::mutex s_mx;
static inline std::weak_ptr<zstd_context_manager> s_ctxmgr;
std::shared_ptr<context_manager> ctxmgr_;
std::shared_ptr<zstd_context_manager> ctxmgr_;
const int level_;
};
std::mutex zstd_block_compressor::s_mx;
std::weak_ptr<zstd_block_compressor::context_manager>
zstd_block_compressor::s_ctxmgr;
std::vector<uint8_t>
zstd_block_compressor::compress(const std::vector<uint8_t>& data,
std::string const* /*metadata*/) const {
std::vector<uint8_t> 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)) {