[io_generator] Rename offset_generator classes, and fix bugs

- Rename the classes for general-purpose usage
- Fix duplicated sequential number generation while wrap around
- Enable unaligned random number generation
This commit is contained in:
Ming-Hung Tsai 2020-07-24 15:50:43 +08:00
parent d1fed5f5ec
commit 7ed013fcab

View File

@ -26,80 +26,86 @@ namespace {
//-------------------------------- //--------------------------------
class offset_generator { class sequence_generator {
public: public:
typedef std::shared_ptr<offset_generator> ptr; typedef std::shared_ptr<sequence_generator> ptr;
virtual base::sector_t next_offset() = 0; virtual uint64_t next() = 0;
}; };
class sequential_offset_generator: public offset_generator { // - The maximum generated value is not greater than (begin+size)
// - The generated values are not aligned to the step, if the begin
// value is not aligned.
class forward_sequence_generator: public sequence_generator {
public: public:
sequential_offset_generator(base::sector_t offset, forward_sequence_generator(uint64_t begin,
base::sector_t size, uint64_t size,
base::sector_t block_size) uint64_t step)
: block_size_(block_size), : begin_(begin),
begin_(offset), end_(begin + (size / step) * step),
end_(offset + size), step_(step),
current_(offset) { current_(begin) {
if (size < block_size) if (size < step)
throw std::runtime_error("size must be greater than block_size"); throw std::runtime_error("size must be greater than the step");
} }
base::sector_t next_offset() { uint64_t next() {
sector_t r = current_; uint64_t r = current_;
current_ += block_size_; current_ += step_;
if (current_ > end_) { if (current_ >= end_) {
current_ = begin_; current_ = begin_;
return begin_;
} }
return r; return r;
} }
private: private:
unsigned block_size_; uint64_t begin_;
base::sector_t begin_; uint64_t end_;
base::sector_t end_; uint64_t step_;
base::sector_t current_; uint64_t current_;
}; };
class random_offset_generator: public offset_generator { // - The maximum generated value is not greater than (begin+size)
// - The generated values are not aligned to the step, if the begin
// value is not aligned.
class random_sequence_generator: public sequence_generator {
public: public:
random_offset_generator(sector_t offset, // TODO: load random seeds
sector_t size, random_sequence_generator(uint64_t begin,
sector_t block_size) uint64_t size,
: block_begin_(offset / block_size), uint64_t step)
nr_blocks_(size / block_size), : begin_(begin),
block_size_(block_size), nr_steps_(size / step),
step_(step),
nr_generated_(0) { nr_generated_(0) {
} }
sector_t next_offset() { uint64_t next() {
uint64_t blocknr; uint64_t step_idx;
bool found = true; bool found = true;
while (found) { while (found) {
blocknr = (std::rand() % nr_blocks_) + block_begin_; step_idx = std::rand() % nr_steps_;
found = io_map_.member(blocknr); found = rand_map_.member(step_idx);
} }
io_map_.add(blocknr); rand_map_.add(step_idx);
++nr_generated_; ++nr_generated_;
// wrap-around // wrap-around
if (nr_generated_ == nr_blocks_) { if (nr_generated_ == nr_steps_) {
io_map_.clear(); rand_map_.clear();
nr_generated_ = 0; nr_generated_ = 0;
} }
return blocknr * block_size_; return begin_ + step_idx * step_;
} }
private: private:
uint64_t block_begin_; uint64_t begin_;
uint64_t nr_blocks_; uint64_t nr_steps_;
unsigned block_size_; uint64_t step_;
base::run_set<uint64_t> io_map_; base::run_set<uint64_t> rand_map_;
uint64_t nr_generated_; uint64_t nr_generated_;
}; };
@ -141,13 +147,13 @@ namespace {
virtual bool next(base::io &next_io); virtual bool next(base::io &next_io);
private: private:
offset_generator::ptr sequence_generator::ptr
create_offset_generator(io_generator_options const &opts); create_offset_generator(io_generator_options const &opts);
op_generator::ptr op_generator::ptr
create_op_generator(io_generator_options const &opts); create_op_generator(io_generator_options const &opts);
offset_generator::ptr offset_gen_; sequence_generator::ptr offset_gen_;
op_generator::ptr op_gen_; op_generator::ptr op_gen_;
sector_t block_size_; sector_t block_size_;
size_t io_size_finished_; size_t io_size_finished_;
@ -167,7 +173,7 @@ namespace {
return false; return false;
next_io.op_ = op_gen_->next_op(); next_io.op_ = op_gen_->next_op();
next_io.sector_ = offset_gen_->next_offset(); next_io.sector_ = offset_gen_->next();
next_io.size_ = block_size_; next_io.size_ = block_size_;
io_size_finished_ += block_size_; io_size_finished_ += block_size_;
@ -175,18 +181,18 @@ namespace {
return true; return true;
} }
offset_generator::ptr sequence_generator::ptr
base_io_generator::create_offset_generator(io_generator_options const &opts) { base_io_generator::create_offset_generator(io_generator_options const &opts) {
if (opts.pattern_.is_random()) sequence_generator *gen;
return offset_generator::ptr(
new random_offset_generator(opts.offset_,
opts.size_,
opts.block_size_));
return offset_generator::ptr( if (opts.pattern_.is_random())
new sequential_offset_generator(opts.offset_, gen = new random_sequence_generator(opts.offset_,
opts.size_, opts.size_, opts.block_size_);
opts.block_size_)); else
gen = new forward_sequence_generator(opts.offset_,
opts.size_, opts.block_size_);
return sequence_generator::ptr(gen);
} }
op_generator::ptr op_generator::ptr