[cache_writeback] Coded, needs testing
This commit is contained in:
parent
4573ebb218
commit
c8fec7ec40
@ -36,6 +36,9 @@ SOURCE=\
|
|||||||
base/rolling_hash.cc \
|
base/rolling_hash.cc \
|
||||||
base/xml_utils.cc \
|
base/xml_utils.cc \
|
||||||
block-cache/block_cache.cc \
|
block-cache/block_cache.cc \
|
||||||
|
block-cache/copier.cc \
|
||||||
|
block-cache/io_engine.cc \
|
||||||
|
block-cache/mem_pool.cc \
|
||||||
caching/cache_check.cc \
|
caching/cache_check.cc \
|
||||||
caching/cache_dump.cc \
|
caching/cache_dump.cc \
|
||||||
caching/cache_metadata_size.cc \
|
caching/cache_metadata_size.cc \
|
||||||
|
67
base/unique_handle.h
Normal file
67
base/unique_handle.h
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#ifndef BASE_UNIQUE_HANDLE_H
|
||||||
|
#define BASE_UNIQUE_HANDLE_H
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <memory>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace base {
|
||||||
|
template <typename T, T TNul = T()>
|
||||||
|
class unique_handle
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
unique_handle(std::nullptr_t = nullptr)
|
||||||
|
: id_(TNul) {
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_handle(T x)
|
||||||
|
: id_(x) {
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit operator bool() const {
|
||||||
|
return id_ != TNul;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator T&() {
|
||||||
|
return id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator T() const {
|
||||||
|
return id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
T *operator&() {
|
||||||
|
return &id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const T *operator&() const {
|
||||||
|
return &id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator == (unique_handle a, unique_handle b) { return a.id_ == b.id_; }
|
||||||
|
friend bool operator != (unique_handle a, unique_handle b) { return a.id_ != b.id_; }
|
||||||
|
friend bool operator == (unique_handle a, std::nullptr_t) { return a.id_ == TNul; }
|
||||||
|
friend bool operator != (unique_handle a, std::nullptr_t) { return a.id_ != TNul; }
|
||||||
|
friend bool operator == (std::nullptr_t, unique_handle b) { return TNul == b.id_; }
|
||||||
|
friend bool operator != (std::nullptr_t, unique_handle b) { return TNul != b.id_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
T id_;
|
||||||
|
};
|
||||||
|
|
||||||
|
//--------------------------------
|
||||||
|
|
||||||
|
struct fd_deleter {
|
||||||
|
typedef unique_handle<int, -1> pointer;
|
||||||
|
void operator()(pointer p) {
|
||||||
|
::close(p);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
typedef std::unique_ptr<int, fd_deleter> unique_fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
#endif
|
@ -1,7 +1,123 @@
|
|||||||
#include "block-cache/copier.h"
|
#include "block-cache/copier.h"
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
#include <stdexcept>
|
||||||
|
|
||||||
|
|
||||||
|
using namespace bcache;
|
||||||
|
using namespace boost;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
copier::copier(string const &src, string const &dest,
|
||||||
|
sector_t block_size, size_t mem)
|
||||||
|
: pool_(block_size, mem),
|
||||||
|
block_size_(block_size),
|
||||||
|
nr_blocks_(mem / block_size),
|
||||||
|
engine_(nr_blocks_),
|
||||||
|
src_handle_(engine_.open_file(src, io_engine::READ_ONLY)),
|
||||||
|
dest_handle_(engine_.open_file(dest, io_engine::READ_WRITE)),
|
||||||
|
genkey_count_(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
copier::issue(copy_op const &op)
|
||||||
|
{
|
||||||
|
auto data = pool_.alloc();
|
||||||
|
if (!data) {
|
||||||
|
wait_();
|
||||||
|
data = pool_.alloc();
|
||||||
|
|
||||||
|
if (!data)
|
||||||
|
// Shouldn't get here
|
||||||
|
throw runtime_error("couldn't allocate buffer");
|
||||||
|
}
|
||||||
|
|
||||||
|
copy_job job(op, *data);
|
||||||
|
job.op.read_complete = job.op.write_complete = false;
|
||||||
|
unsigned key = genkey(); // used as context for the io_engine
|
||||||
|
|
||||||
|
engine_.issue_io(src_handle_,
|
||||||
|
io_engine::READ,
|
||||||
|
to_sector(op.src_b),
|
||||||
|
to_sector(op.src_e),
|
||||||
|
*data,
|
||||||
|
key);
|
||||||
|
jobs_.insert(make_pair(key, job));
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
copier::nr_pending() const
|
||||||
|
{
|
||||||
|
return jobs_.size() + complete_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::optional<copy_op>
|
||||||
|
copier::wait()
|
||||||
|
{
|
||||||
|
while (complete_.empty() && !jobs_.empty())
|
||||||
|
wait_();
|
||||||
|
|
||||||
|
if (complete_.empty())
|
||||||
|
return optional<copy_op>();
|
||||||
|
|
||||||
|
else {
|
||||||
|
auto op = complete_.front();
|
||||||
|
complete_.pop_front();
|
||||||
|
return optional<copy_op>(op);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
copier::wait_()
|
||||||
|
{
|
||||||
|
auto p = engine_.wait();
|
||||||
|
auto it = jobs_.find(p.second);
|
||||||
|
if (it == jobs_.end())
|
||||||
|
throw runtime_error("Internal error. Lost track of copy job.");
|
||||||
|
|
||||||
|
copy_job j = it->second;
|
||||||
|
if (!p.first) {
|
||||||
|
// IO was unsuccessful
|
||||||
|
jobs_.erase(it);
|
||||||
|
complete(j);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// IO was successful
|
||||||
|
if (!j.op.read_complete) {
|
||||||
|
j.op.read_complete = true;
|
||||||
|
engine_.issue_io(dest_handle_,
|
||||||
|
io_engine::WRITE,
|
||||||
|
to_sector(j.op.dest_b),
|
||||||
|
to_sector(j.op.dest_b + (j.op.src_e - j.op.src_b)),
|
||||||
|
j.data,
|
||||||
|
it->first);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
j.op.write_complete = true;
|
||||||
|
jobs_.erase(it);
|
||||||
|
complete(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
copier::complete(copy_job const &j)
|
||||||
|
{
|
||||||
|
pool_.free(j.data);
|
||||||
|
complete_.push_back(j.op);
|
||||||
|
}
|
||||||
|
|
||||||
|
sector_t
|
||||||
|
copier::to_sector(block_address b) const
|
||||||
|
{
|
||||||
|
return b * block_size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
copier::genkey()
|
||||||
|
{
|
||||||
|
return genkey_count_++;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
@ -1,27 +1,75 @@
|
|||||||
#ifndef BLOCK_CACHE_COPIER_H
|
#ifndef BLOCK_CACHE_COPIER_H
|
||||||
#define BLOCK_CACHE_COPIER_H
|
#define BLOCK_CACHE_COPIER_H
|
||||||
|
|
||||||
#include "block_cache.h"
|
#include "block-cache/io_engine.h"
|
||||||
|
#include "block-cache/mem_pool.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <list>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
namespace bcache {
|
namespace bcache {
|
||||||
|
using block_address = uint64_t;
|
||||||
|
|
||||||
|
struct copy_op {
|
||||||
|
copy_op()
|
||||||
|
: read_complete(false),
|
||||||
|
write_complete(false) {
|
||||||
|
}
|
||||||
|
|
||||||
|
block_address src_b, src_e;
|
||||||
|
block_address dest_b;
|
||||||
|
|
||||||
|
bool read_complete;
|
||||||
|
bool write_complete;
|
||||||
|
};
|
||||||
|
|
||||||
|
class copy_job {
|
||||||
|
public:
|
||||||
|
copy_job(copy_op const &op_, void *data_)
|
||||||
|
: op(op_), data(data_) {
|
||||||
|
}
|
||||||
|
|
||||||
|
copy_op op;
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
|
||||||
class copier {
|
class copier {
|
||||||
public:
|
public:
|
||||||
// block size in sectors
|
|
||||||
copier(std::string const &src, std::string const &dest,
|
copier(std::string const &src, std::string const &dest,
|
||||||
unsigned block_size);
|
sector_t block_size, size_t mem);
|
||||||
~copier();
|
|
||||||
|
|
||||||
// Returns the number of sectors copied
|
sector_t get_block_size() const {
|
||||||
unsigned copy(block_address from, block_address to);
|
return block_size_;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned get_block_size() const;
|
// Blocks if out of memory.
|
||||||
|
void issue(copy_op const &op);
|
||||||
|
|
||||||
|
unsigned nr_pending() const;
|
||||||
|
boost::optional<copy_op> wait();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned block_size_;
|
void wait_();
|
||||||
|
void complete(copy_job const &j);
|
||||||
|
|
||||||
|
sector_t to_sector(block_address b) const;
|
||||||
|
unsigned genkey();
|
||||||
|
|
||||||
|
mempool pool_;
|
||||||
|
sector_t block_size_;
|
||||||
|
unsigned nr_blocks_;
|
||||||
|
io_engine engine_;
|
||||||
|
io_engine::handle src_handle_;
|
||||||
|
io_engine::handle dest_handle_;
|
||||||
|
unsigned genkey_count_;
|
||||||
|
|
||||||
|
using job_map = std::map<unsigned, copy_job>;
|
||||||
|
using op_list = std::list<copy_op>;
|
||||||
|
job_map jobs_;
|
||||||
|
op_list complete_;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
175
block-cache/io_engine.cc
Normal file
175
block-cache/io_engine.cc
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
#include "base/container_of.h"
|
||||||
|
#include "block-cache/io_engine.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
using namespace bcache;
|
||||||
|
using namespace boost;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#define SECTOR_SHIFT 9
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
control_block_set::control_block_set(unsigned nr)
|
||||||
|
: cbs_(nr)
|
||||||
|
{
|
||||||
|
for (auto i = 0u; i < nr; i++)
|
||||||
|
free_cbs_.insert(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
iocb *
|
||||||
|
control_block_set::alloc(unsigned context)
|
||||||
|
{
|
||||||
|
if (free_cbs_.empty())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
auto it = free_cbs_.begin();
|
||||||
|
|
||||||
|
cblock &cb = cbs_[*it];
|
||||||
|
cb.context = context;
|
||||||
|
free_cbs_.erase(it);
|
||||||
|
|
||||||
|
return &cb.cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
control_block_set::free(iocb *cb)
|
||||||
|
{
|
||||||
|
cblock *b = base::container_of(cb, &cblock::cb);
|
||||||
|
unsigned index = b - &cbs_[0];
|
||||||
|
free_cbs_.insert(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
control_block_set::context(iocb *cb) const
|
||||||
|
{
|
||||||
|
cblock *b = base::container_of(cb, &cblock::cb);
|
||||||
|
return b->context;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
io_engine::io_engine(unsigned max_io)
|
||||||
|
: aio_context_(0),
|
||||||
|
cbs_(max_io),
|
||||||
|
events_(max_io)
|
||||||
|
{
|
||||||
|
int r = io_setup(max_io, &aio_context_);
|
||||||
|
if (r < 0)
|
||||||
|
throw runtime_error("io_setup failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
io_engine::~io_engine()
|
||||||
|
{
|
||||||
|
io_destroy(aio_context_);
|
||||||
|
}
|
||||||
|
|
||||||
|
io_engine::handle
|
||||||
|
io_engine:: open_file(std::string const &path, mode m)
|
||||||
|
{
|
||||||
|
int flags = (m == READ_ONLY) ? O_RDONLY : O_RDWR;
|
||||||
|
int fd = ::open(path.c_str(), O_DIRECT | flags);
|
||||||
|
if (fd < 0) {
|
||||||
|
ostringstream out;
|
||||||
|
out << "unable to open '" << path << "'";
|
||||||
|
throw runtime_error(out.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
descriptors_.push_back(base::unique_fd(fd));
|
||||||
|
|
||||||
|
return static_cast<handle>(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
io_engine::close_file(handle h)
|
||||||
|
{
|
||||||
|
for (auto it = descriptors_.begin(); it != descriptors_.end(); ++it) {
|
||||||
|
unsigned it_h = it->get();
|
||||||
|
if (it_h == h) {
|
||||||
|
descriptors_.erase(it);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ostringstream out;
|
||||||
|
out << "unknown descriptor (" << h << ")";
|
||||||
|
throw runtime_error(out.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
io_engine::issue_io(handle h, dir d, sector_t b, sector_t e, void *data, unsigned context)
|
||||||
|
{
|
||||||
|
auto cb = cbs_.alloc(context);
|
||||||
|
if (!cb)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
memset(cb, 0, sizeof(*cb));
|
||||||
|
cb->aio_fildes = static_cast<int>(h);
|
||||||
|
cb->u.c.buf = data;
|
||||||
|
cb->u.c.offset = b << SECTOR_SHIFT;
|
||||||
|
cb->u.c.nbytes = (e - b) << SECTOR_SHIFT;
|
||||||
|
|
||||||
|
cb->aio_lio_opcode = (d == READ) ? IO_CMD_PREAD : IO_CMD_PWRITE;
|
||||||
|
|
||||||
|
int r = io_submit(aio_context_, 1, &cb);
|
||||||
|
if (r != 1) {
|
||||||
|
std::ostringstream out;
|
||||||
|
out << "couldn't issue "
|
||||||
|
<< ((d == READ) ? "READ" : "WRITE")
|
||||||
|
<< " io: io_submit ";
|
||||||
|
if (r < 0)
|
||||||
|
out << "failed with " << r;
|
||||||
|
else
|
||||||
|
out << "succeeded, but queued no io";
|
||||||
|
|
||||||
|
throw std::runtime_error(out.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<bool, io_engine::handle>
|
||||||
|
io_engine::wait()
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
r = io_getevents(aio_context_, 1, events_.size(), &events_[0], NULL);
|
||||||
|
if (r < 0) {
|
||||||
|
std::ostringstream out;
|
||||||
|
out << "io_getevents failed: " << r;
|
||||||
|
throw std::runtime_error(out.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < static_cast<unsigned>(r); i++) {
|
||||||
|
io_event const &e = events_[i];
|
||||||
|
iocb *cb = reinterpret_cast<iocb *>(e.obj);
|
||||||
|
unsigned context = cbs_.context(cb);
|
||||||
|
cbs_.free(cb);
|
||||||
|
|
||||||
|
if (e.res == cb->u.c.nbytes)
|
||||||
|
return make_pair(true, context);
|
||||||
|
|
||||||
|
else {
|
||||||
|
std::ostringstream out;
|
||||||
|
out << "io failed"
|
||||||
|
<< ", e.res = " << e.res
|
||||||
|
<< ", e.res2 = " << e.res2
|
||||||
|
<< ", offset = " << cb->u.c.offset
|
||||||
|
<< ", nbytes = " << cb->u.c.nbytes;
|
||||||
|
return make_pair(false, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// shouldn't get here
|
||||||
|
return make_pair(false, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
82
block-cache/io_engine.h
Normal file
82
block-cache/io_engine.h
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
#ifndef BLOCK_CACHE_IO_ENGINE_H
|
||||||
|
#define BLOCK_CACHE_IO_ENGINE_H
|
||||||
|
|
||||||
|
#include "base/unique_handle.h"
|
||||||
|
|
||||||
|
#include <boost/optional.hpp>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <libaio.h>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace bcache {
|
||||||
|
using sector_t = uint64_t;
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
class control_block_set {
|
||||||
|
public:
|
||||||
|
control_block_set(unsigned nr);
|
||||||
|
|
||||||
|
iocb *alloc(unsigned context);
|
||||||
|
void free(iocb *);
|
||||||
|
|
||||||
|
unsigned context(iocb *) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct cblock {
|
||||||
|
unsigned context;
|
||||||
|
struct iocb cb;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::set<unsigned> free_cbs_;
|
||||||
|
std::vector<cblock> cbs_;
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
class io_engine {
|
||||||
|
public:
|
||||||
|
enum mode {
|
||||||
|
READ_ONLY,
|
||||||
|
READ_WRITE
|
||||||
|
};
|
||||||
|
|
||||||
|
enum dir {
|
||||||
|
READ,
|
||||||
|
WRITE
|
||||||
|
};
|
||||||
|
|
||||||
|
// max_io is the maximum nr of concurrent ios expected
|
||||||
|
io_engine(unsigned max_io);
|
||||||
|
~io_engine();
|
||||||
|
|
||||||
|
using handle = unsigned;
|
||||||
|
|
||||||
|
handle open_file(std::string const &path, mode m);
|
||||||
|
void close_file(handle h);
|
||||||
|
|
||||||
|
// returns false if there are insufficient resources to
|
||||||
|
// queue the IO
|
||||||
|
bool issue_io(handle h, dir d, sector_t b, sector_t e, void *data, unsigned context);
|
||||||
|
|
||||||
|
// returns (success, context)
|
||||||
|
std::pair<bool, unsigned> wait();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::list<base::unique_fd> descriptors_;
|
||||||
|
|
||||||
|
io_context_t aio_context_;
|
||||||
|
control_block_set cbs_;
|
||||||
|
std::vector<io_event> events_;
|
||||||
|
|
||||||
|
io_engine(io_engine const &) = delete;
|
||||||
|
io_engine &operator =(io_engine const &) = delete;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
#endif
|
57
block-cache/mem_pool.cc
Normal file
57
block-cache/mem_pool.cc
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#include "block-cache/mem_pool.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
using namespace bcache;
|
||||||
|
using namespace boost;
|
||||||
|
using namespace mempool_detail;
|
||||||
|
|
||||||
|
#define PAGE_SIZE 4096
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
mempool::mempool(size_t block_size, size_t total_mem)
|
||||||
|
{
|
||||||
|
mem_ = alloc_aligned(total_mem, PAGE_SIZE);
|
||||||
|
|
||||||
|
unsigned nr_blocks = total_mem / block_size;
|
||||||
|
for (auto i = 0u; i < nr_blocks; i++)
|
||||||
|
free(static_cast<unsigned char *>(mem_) + (block_size * i));
|
||||||
|
}
|
||||||
|
|
||||||
|
mempool::~mempool()
|
||||||
|
{
|
||||||
|
::free(mem_);
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::optional<void *>
|
||||||
|
mempool::alloc()
|
||||||
|
{
|
||||||
|
if (free_.empty())
|
||||||
|
return optional<void *>();
|
||||||
|
|
||||||
|
mempool_detail::alloc_block &b = free_.front();
|
||||||
|
free_.pop_front();
|
||||||
|
return optional<void *>(reinterpret_cast<void *>(&b));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mempool::free(void *data)
|
||||||
|
{
|
||||||
|
mempool_detail::alloc_block *b = reinterpret_cast<mempool_detail::alloc_block *>(data);
|
||||||
|
free_.push_front(*b);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
mempool::alloc_aligned(size_t len, size_t alignment)
|
||||||
|
{
|
||||||
|
void *result = NULL;
|
||||||
|
int r = posix_memalign(&result, alignment, len);
|
||||||
|
if (r)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
45
block-cache/mem_pool.h
Normal file
45
block-cache/mem_pool.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#ifndef BLOCK_CACHE_MEM_POOL_H
|
||||||
|
#define BLOCK_CACHE_MEM_POOL_H
|
||||||
|
|
||||||
|
#include <boost/intrusive/list.hpp>
|
||||||
|
#include <boost/optional.hpp>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
namespace bi = boost::intrusive;
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace bcache {
|
||||||
|
// FIXME: move to base?
|
||||||
|
|
||||||
|
namespace mempool_detail {
|
||||||
|
struct alloc_block : public bi::list_base_hook<> {
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class mempool {
|
||||||
|
public:
|
||||||
|
mempool(size_t block_size, size_t total_mem);
|
||||||
|
~mempool();
|
||||||
|
|
||||||
|
boost::optional<void *> alloc();
|
||||||
|
void free(void *data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void *alloc_aligned(size_t len, size_t alignment);
|
||||||
|
|
||||||
|
using block_list = bi::list<mempool_detail::alloc_block>;
|
||||||
|
|
||||||
|
void *mem_;
|
||||||
|
block_list free_;
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
mempool(mempool const &) = delete;
|
||||||
|
mempool &operator =(mempool const &) = delete;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
#endif
|
@ -19,8 +19,13 @@ using namespace std;
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
struct flags {
|
struct flags {
|
||||||
|
flags()
|
||||||
|
: cache_size(1024 * 1024 * 128) {
|
||||||
|
}
|
||||||
|
|
||||||
using maybe_string = boost::optional<string>;
|
using maybe_string = boost::optional<string>;
|
||||||
|
|
||||||
|
size_t cache_size;
|
||||||
maybe_string metadata_dev;
|
maybe_string metadata_dev;
|
||||||
maybe_string origin_dev;
|
maybe_string origin_dev;
|
||||||
maybe_string fast_dev;
|
maybe_string fast_dev;
|
||||||
@ -41,13 +46,22 @@ namespace {
|
|||||||
if (only_dirty_ && !(m.flags_ & M_DIRTY))
|
if (only_dirty_ && !(m.flags_ & M_DIRTY))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto sectors_copied = copier_.copy(cblock, m.oblock_);
|
copy_op cop;
|
||||||
|
cop.src_b = cblock;
|
||||||
|
cop.src_e = cblock + 1ull;
|
||||||
|
cop.dest_b = m.oblock_;
|
||||||
|
|
||||||
|
// blocks
|
||||||
|
copier_.issue(cop);
|
||||||
|
|
||||||
stats_.blocks_issued++;
|
stats_.blocks_issued++;
|
||||||
|
|
||||||
|
#if 0
|
||||||
if (sectors_copied < block_size_) {
|
if (sectors_copied < block_size_) {
|
||||||
stats_.blocks_failed++;
|
stats_.blocks_failed++;
|
||||||
stats_.sectors_failed += block_size_ - sectors_copied;
|
stats_.sectors_failed += block_size_ - sectors_copied;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
struct copy_stats {
|
struct copy_stats {
|
||||||
@ -107,7 +121,8 @@ namespace {
|
|||||||
block_manager<>::ptr bm = open_bm(*f.metadata_dev, block_manager<>::READ_ONLY);
|
block_manager<>::ptr bm = open_bm(*f.metadata_dev, block_manager<>::READ_ONLY);
|
||||||
metadata md(bm, metadata::OPEN);
|
metadata md(bm, metadata::OPEN);
|
||||||
|
|
||||||
copier c(*f.fast_dev, *f.origin_dev, md.sb_.data_block_size);
|
copier c(*f.fast_dev, *f.origin_dev,
|
||||||
|
md.sb_.data_block_size, f.cache_size);
|
||||||
copy_visitor cv(c, clean_shutdown(md));
|
copy_visitor cv(c, clean_shutdown(md));
|
||||||
ignore_damage_visitor dv;
|
ignore_damage_visitor dv;
|
||||||
walk_mapping_array(*md.mappings_, cv, dv);
|
walk_mapping_array(*md.mappings_, cv, dv);
|
||||||
|
Loading…
Reference in New Issue
Block a user