<< ")";
}
-void VarLenGenerator::get_ranges(const ContDesc &cont, interval_set<uint64_t> &out) {
+void AppendGenerator::get_ranges_map(
+ const ContDesc &cont, map<uint64_t, uint64_t> &out) {
+ RandWrap rand(cont.seqnum);
+ uint64_t pos = off;
+ uint64_t limit = off + get_append_size(cont);
+ while (pos < limit) {
+ uint64_t segment_length = (
+ rand() % (max_append_size - min_append_size)) + min_append_size;
+ assert(segment_length < max_append_size);
+ assert(segment_length >= min_append_size);
+ if (segment_length + pos > limit) {
+ segment_length = limit - pos;
+ }
+ out.insert(make_pair(pos, segment_length));
+ pos += segment_length;
+ }
+}
+
+void VarLenGenerator::get_ranges_map(
+ const ContDesc &cont, map<uint64_t, uint64_t> &out) {
RandWrap rand(cont.seqnum);
uint64_t pos = 0;
uint64_t limit = get_length(cont);
segment_length = limit - pos;
}
if (include) {
- out.insert(pos, segment_length);
+ out.insert(make_pair(pos, segment_length));
include = false;
} else {
include = true;
virtual uint64_t get_length(const ContDesc &in) = 0;
- virtual void get_ranges(const ContDesc &in, interval_set<uint64_t> &ranges) = 0;
+ virtual void get_ranges_map(
+ const ContDesc &cont, map<uint64_t, uint64_t> &out) = 0;
+ void get_ranges(const ContDesc &cont, interval_set<uint64_t> &out) {
+ map<uint64_t, uint64_t> ranges;
+ get_ranges_map(cont, ranges);
+ for (map<uint64_t, uint64_t>::iterator i = ranges.begin();
+ i != ranges.end();
+ ++i) {
+ out.insert(i->first, i->second);
+ }
+ }
+
virtual iterator_impl *get_iterator_impl(const ContDesc &in) = 0;
}
};
- virtual void get_ranges(const ContDesc &cont, interval_set<uint64_t> &out) = 0;
-
ContentsGenerator::iterator_impl *get_iterator_impl(const ContDesc &in) {
RandGenerator::iterator_impl *i = new iterator_impl(in, this);
return i;
max_length(length),
min_stride_size(min_stride_size),
max_stride_size(max_stride_size) {}
- void get_ranges(const ContDesc &cont, interval_set<uint64_t> &out);
+ void get_ranges_map(
+ const ContDesc &cont, map<uint64_t, uint64_t> &out);
uint64_t get_length(const ContDesc &in) {
RandWrap rand(in.seqnum);
return (rand() % max_length);
uint64_t max_len;
public:
AttrGenerator(uint64_t max_len) : max_len(max_len) {}
- void get_ranges(const ContDesc &cont, interval_set<uint64_t> &out) {
- out.insert(0, get_length(cont));
+ void get_ranges_map(
+ const ContDesc &cont, map<uint64_t, uint64_t> &out) {
+ out.insert(make_pair(0, get_length(cont)));
}
uint64_t get_length(const ContDesc &in) {
RandWrap rand(in.seqnum);
class AppendGenerator : public RandGenerator {
uint64_t off;
- uint64_t max_len;
- uint64_t max_intervals;
+ uint64_t min_append_size;
+ uint64_t max_append_size;
+ uint64_t max_append_total;
public:
- AppendGenerator(uint64_t off, uint64_t max_len, uint64_t max_intervals) :
- off(off), max_len(max_len), max_intervals(max_intervals) {}
- uint64_t get_length(const ContDesc &in) {
+ AppendGenerator(
+ uint64_t off,
+ uint64_t min_append_size,
+ uint64_t max_append_size,
+ uint64_t max_append_total) :
+ off(off), min_append_size(min_append_size),
+ max_append_size(max_append_size),
+ max_append_total(max_append_total) {}
+ uint64_t get_append_size(const ContDesc &in) {
RandWrap rand(in.seqnum);
- return off + (rand() % max_len);
+ return rand() % max_append_total;
}
- void get_ranges(const ContDesc &cont, interval_set<uint64_t> &out) {
- out.insert(off, get_length(cont));
+ uint64_t get_length(const ContDesc &in) {
+ return off + get_append_size(in);
}
+ void get_ranges_map(
+ const ContDesc &cont, map<uint64_t, uint64_t> &out);
};
class ObjectDesc {
TEST_OP_IS_DIRTY,
TEST_OP_CACHE_FLUSH,
TEST_OP_CACHE_TRY_FLUSH,
- TEST_OP_CACHE_EVICT
+ TEST_OP_CACHE_EVICT,
+ TEST_OP_APPEND
};
class TestWatchContext : public librados::WatchCtx {
librados::ObjectWriteOperation write_op;
bufferlist rbuffer;
+ bool do_append;
+
WriteOp(int n,
RadosTestContext *context,
const string &oid,
+ bool do_append,
TestOpStat *stat = 0)
: TestOp(n, context, stat),
- oid(oid), waiting_on(0), last_acked_tid(0)
+ oid(oid), waiting_on(0), last_acked_tid(0), do_append(do_append)
{}
void _begin()
cont = ContDesc(context->seq_num, context->current_snap, context->seq_num, prefix);
- ContentsGenerator *cont_gen = new VarLenGenerator(
- context->max_size, context->min_stride_size, context->max_stride_size);
+ ContentsGenerator *cont_gen;
+ if (do_append) {
+ ObjectDesc old_value;
+ bool found = context->find_object(oid, &old_value);
+ uint64_t prev_length = found && old_value.has_contents() ?
+ old_value.most_recent_gen()->get_length(old_value.most_recent()) :
+ 0;
+ cont_gen = new AppendGenerator(
+ prev_length,
+ context->min_stride_size,
+ context->max_stride_size,
+ 3 * context->max_stride_size);
+ } else {
+ cont_gen = new VarLenGenerator(
+ context->max_size, context->min_stride_size, context->max_stride_size);
+ }
context->update_object(cont_gen, oid, cont);
context->oid_in_use.insert(oid);
context->oid_not_in_use.erase(oid);
- interval_set<uint64_t> ranges;
+ map<uint64_t, uint64_t> ranges;
- cont_gen->get_ranges(cont, ranges);
+ cont_gen->get_ranges_map(cont, ranges);
std::cout << num << ": seq_num " << context->seq_num << " ranges " << ranges << std::endl;
context->seq_num++;
context->state_lock.Unlock();
- waiting_on = ranges.num_intervals();
+ waiting_on = ranges.size();
//cout << " waiting_on = " << waiting_on << std::endl;
ContentsGenerator::iterator gen_pos = cont_gen->get_iterator(cont);
uint64_t tid = 1;
- for (interval_set<uint64_t>::iterator i = ranges.begin();
+ for (map<uint64_t, uint64_t>::iterator i = ranges.begin();
i != ranges.end();
++i, ++tid) {
bufferlist to_write;
- gen_pos.seek(i.get_start());
- for (uint64_t k = 0; k != i.get_len(); ++k, ++gen_pos) {
+ gen_pos.seek(i->first);
+ for (uint64_t k = 0; k != i->second; ++k, ++gen_pos) {
to_write.append(*gen_pos);
}
- assert(to_write.length() == i.get_len());
+ assert(to_write.length() == i->second);
assert(to_write.length() > 0);
- std::cout << num << ": writing " << context->prefix+oid << " from " << i.get_start()
- << " to " << i.get_len() + i.get_start() << " tid " << tid << std::endl;
+ std::cout << num << ": writing " << context->prefix+oid
+ << " from " << i->first
+ << " to " << i->first + i->second << " tid " << tid << std::endl;
pair<TestOp*, TestOp::CallbackInfo*> *cb_arg =
new pair<TestOp*, TestOp::CallbackInfo*>(this,
new TestOp::CallbackInfo(tid));
librados::AioCompletion *completion =
context->rados.aio_create_completion((void*) cb_arg, &write_callback, NULL);
waiting.insert(completion);
- context->io_ctx.aio_write(context->prefix+oid, completion,
- to_write, i.get_len(), i.get_start());
+ librados::ObjectWriteOperation op;
+ if (do_append) {
+ op.append(to_write);
+ } else {
+ op.write(i->first, to_write);
+ }
+ context->io_ctx.aio_operate(
+ context->prefix+oid, completion,
+ &op);
}
bufferlist contbl;
waiting.insert(completion);
waiting_on++;
write_op.setxattr("_header", contbl);
- write_op.truncate(cont_gen->get_length(cont));
+ if (!do_append) {
+ write_op.truncate(cont_gen->get_length(cont));
+ }
context->io_ctx.aio_operate(
context->prefix+oid, completion, &write_op);
int objects,
map<TestOpType, unsigned int> op_weights,
TestOpStat *stats,
- int max_seconds) :
- m_nextop(NULL), m_op(0), m_ops(ops), m_seconds(max_seconds), m_objects(objects), m_stats(stats),
- m_total_weight(0)
+ int max_seconds,
+ bool ec_pool) :
+ m_nextop(NULL), m_op(0), m_ops(ops), m_seconds(max_seconds),
+ m_objects(objects), m_stats(stats),
+ m_total_weight(0),
+ m_ec_pool(ec_pool)
{
m_start = time(0);
for (map<TestOpType, unsigned int>::const_iterator it = op_weights.begin();
oid << m_op;
cout << m_op << ": write initial oid " << oid.str() << std::endl;
context.oid_not_flushing.insert(oid.str());
- return new WriteOp(m_op, &context, oid.str());
+ if (m_ec_pool) {
+ return new WriteOp(m_op, &context, oid.str(), true);
+ } else {
+ return new WriteOp(m_op, &context, oid.str(), false);
+ }
} else if (m_op >= m_ops) {
return NULL;
}
oid = *(rand_choose(context.oid_not_in_use));
cout << m_op << ": " << "write oid " << oid << " current snap is "
<< context.current_snap << std::endl;
- return new WriteOp(m_op, &context, oid, m_stats);
+ return new WriteOp(m_op, &context, oid, false, m_stats);
case TEST_OP_DELETE:
oid = *(rand_choose(context.oid_not_in_use));
return new CacheEvictOp(m_op, &context, oid, m_stats);
}
+ case TEST_OP_APPEND:
+ oid = *(rand_choose(context.oid_not_in_use));
+ cout << "append oid " << oid << " current snap is "
+ << context.current_snap << std::endl;
+ return new WriteOp(m_op, &context, oid, true, m_stats);
+
default:
cerr << m_op << ": Invalid op type " << type << std::endl;
assert(0);
TestOpStat *m_stats;
map<TestOpType, unsigned int> m_weight_sums;
unsigned int m_total_weight;
+ bool m_ec_pool;
};
int main(int argc, char **argv)
{ TEST_OP_CACHE_FLUSH, "cache_flush", true },
{ TEST_OP_CACHE_TRY_FLUSH, "cache_try_flush", true },
{ TEST_OP_CACHE_EVICT, "cache_evict", true },
+ { TEST_OP_APPEND, "append", true },
{ TEST_OP_READ /* grr */, NULL },
};
id);
TestOpStat stats;
- WeightedTestGenerator gen = WeightedTestGenerator(ops, objects,
- op_weights, &stats, max_seconds);
+ WeightedTestGenerator gen = WeightedTestGenerator(
+ ops, objects,
+ op_weights, &stats, max_seconds,
+ ec_pool);
int r = context.init();
if (r < 0) {
cerr << "Error initializing rados test context: "