if (r) {
dout(20) << __func__ << " returned an error: " << r << dendl;
- close_op_ctx(ctx);
if (op->may_write() &&
get_osdmap()->require_osd_release >= ceph_release_t::kraken) {
- record_write_error(op, oid, nullptr, r);
+ record_write_error(op, oid, nullptr, r,
+ ctx->op->allows_returnvec() ? ctx : nullptr);
} else {
osd->reply_op_error(op, r);
}
+ close_op_ctx(ctx);
return;
}
}
void PrimaryLogPG::record_write_error(OpRequestRef op, const hobject_t &soid,
- MOSDOpReply *orig_reply, int r)
+ MOSDOpReply *orig_reply, int r,
+ OpContext *ctx_for_op_returns)
{
dout(20) << __func__ << " r=" << r << dendl;
ceph_assert(op->may_write());
entries.push_back(pg_log_entry_t(pg_log_entry_t::ERROR, soid,
get_next_version(), eversion_t(), 0,
reqid, utime_t(), r));
+ if (ctx_for_op_returns) {
+ entries.back().set_op_returns(*ctx_for_op_returns->ops);
+ dout(20) << __func__ << " op_returns=" << entries.back().op_returns << dendl;
+ }
struct OnComplete {
PrimaryLogPG *pg;
return;
}
- bool successful_write = !ctx->op_t->empty() && op->may_write() && result >= 0;
- // prepare the reply
- ctx->reply = new MOSDOpReply(m, 0, get_osdmap_epoch(), 0,
- successful_write);
- dout(20) << __func__ << " alloc reply " << ctx->reply << dendl;
-
- // Write operations aren't allowed to return a data payload because
- // we can't do so reliably. If the client has to resend the request
- // and it has already been applied, we will return 0 with no
- // payload. Non-deterministic behavior is no good. However, it is
- // possible to construct an operation that does a read, does a guard
- // check (e.g., CMPXATTR), and then a write. Then we either succeed
- // with the write, or return a CMPXATTR and the read value.
- if (successful_write) {
- // WIP: we will soon support a >=0 result code here.
- if (result) {
- derr << " non-zero write result code " << result << dendl;
- ceph_assert(result == 0);
+ bool ignore_out_data = false;
+ if (!ctx->op_t->empty() &&
+ op->may_write() &&
+ result >= 0) {
+ // successful update
+ if (ctx->op->allows_returnvec()) {
+ // enforce reasonable bound on the return buffer sizes
+#warning write me
+ } else {
+ // legacy behavior -- zero result and return data etc.
+ ignore_out_data = true;
+ result = 0;
}
}
- ctx->reply->set_result(result);
+
+ // prepare the reply
+ ctx->reply = new MOSDOpReply(m, result, get_osdmap_epoch(), 0,
+ ignore_out_data);
+ dout(20) << __func__ << " alloc reply " << ctx->reply << dendl;
// read or error?
if ((ctx->op_t->empty() || result < 0) && !ctx->update_log_only) {
MOSDOpReply *reply = ctx->reply;
ctx->reply = nullptr;
reply->get_header().data_off = (ctx->data_off ? *ctx->data_off : 0);
- close_op_ctx(ctx);
if (result == -ENOENT) {
reply->set_enoent_reply_versions(info.last_update,
}
reply->add_flags(CEPH_OSD_FLAG_ACK | CEPH_OSD_FLAG_ONDISK);
// append to pg log for dup detection - don't save buffers for now
- record_write_error(op, soid, reply, result);
+ record_write_error(op, soid, reply, result,
+ ctx->op->allows_returnvec() ? ctx : nullptr);
+ close_op_ctx(ctx);
return;
}
finish_ctx(ctx,
ctx->new_obs.exists ? pg_log_entry_t::MODIFY :
- pg_log_entry_t::DELETE);
+ pg_log_entry_t::DELETE,
+ result);
return result;
}
-void PrimaryLogPG::finish_ctx(OpContext *ctx, int log_op_type)
+void PrimaryLogPG::finish_ctx(OpContext *ctx, int log_op_type, int result)
{
const hobject_t& soid = ctx->obs->oi.soid;
dout(20) << __func__ << " " << soid << " " << ctx
}
// append to log
- ctx->log.push_back(pg_log_entry_t(log_op_type, soid, ctx->at_version,
- ctx->obs->oi.version,
- ctx->user_at_version, ctx->reqid,
- ctx->mtime, 0));
+ ctx->log.push_back(
+ pg_log_entry_t(log_op_type, soid, ctx->at_version,
+ ctx->obs->oi.version,
+ ctx->user_at_version, ctx->reqid,
+ ctx->mtime,
+ (ctx->op && ctx->op->allows_returnvec()) ? result : 0));
+ if (ctx->op && ctx->op->allows_returnvec()) {
+ // also the per-op values
+ ctx->log.back().set_op_returns(*ctx->ops);
+ dout(20) << __func__ << " op_returns " << ctx->log.back().op_returns
+ << dendl;
+ }
+
ctx->log.back().clean_regions = ctx->clean_regions;
dout(20) << __func__ << " object " << soid << " marks clean_regions " << ctx->log.back().clean_regions << dendl;
const hobject_t& head, const hobject_t& coid,
object_info_t *poi);
void execute_ctx(OpContext *ctx);
- void finish_ctx(OpContext *ctx, int log_op_type);
+ void finish_ctx(OpContext *ctx, int log_op_type, int result=0);
void reply_ctx(OpContext *ctx, int err);
void reply_ctx(OpContext *ctx, int err, eversion_t v, version_t uv);
void make_writeable(OpContext *ctx);
ThreadPool::TPHandle &handle) override;
void do_op(OpRequestRef& op);
void record_write_error(OpRequestRef op, const hobject_t &soid,
- MOSDOpReply *orig_reply, int r);
+ MOSDOpReply *orig_reply, int r,
+ OpContext *ctx_for_op_returns=nullptr);
void do_pg_op(OpRequestRef op);
void do_scan(
OpRequestRef op,