}
template <typename I>
-void AbstractWriteLog<I>::schedule_append(GenericLogOperationsVector &ops)
+void AbstractWriteLog<I>::schedule_append(GenericLogOperationsVector &ops, C_BlockIORequestT *req)
{
GenericLogOperations to_append(ops.begin(), ops.end());
- schedule_append_ops(to_append);
+ schedule_append_ops(to_append, req);
}
template <typename I>
-void AbstractWriteLog<I>::schedule_append(GenericLogOperationSharedPtr op)
+void AbstractWriteLog<I>::schedule_append(GenericLogOperationSharedPtr op, C_BlockIORequestT *req)
{
GenericLogOperations to_append { op };
- schedule_append_ops(to_append);
+ schedule_append_ops(to_append, req);
}
/*
virtual void setup_schedule_append(
pwl::GenericLogOperationsVector &ops, bool do_early_flush,
C_BlockIORequestT *req) = 0;
- void schedule_append(pwl::GenericLogOperationsVector &ops);
- void schedule_append(pwl::GenericLogOperationSharedPtr op);
+ void schedule_append(pwl::GenericLogOperationsVector &ops, C_BlockIORequestT *req = nullptr);
+ void schedule_append(pwl::GenericLogOperationSharedPtr op, C_BlockIORequestT *req = nullptr);
void flush_new_sync_point(C_FlushRequestT *flush_req,
pwl::DeferredContexts &later);
virtual void process_work() = 0;
virtual void append_scheduled_ops(void) = 0;
- virtual void schedule_append_ops(pwl::GenericLogOperations &ops) = 0;
+ virtual void schedule_append_ops(pwl::GenericLogOperations &ops, C_BlockIORequestT *req) = 0;
virtual void remove_pool_file() = 0;
virtual bool initialize_pool(Context *on_finish,
pwl::DeferredContexts &later) = 0;
* get to the log message append step. */
if (ops.size()) {
flush_pmem_buffer(ops);
- schedule_append_ops(ops);
+ schedule_append_ops(ops, nullptr);
}
} while (ops_remain);
append_scheduled_ops();
* all prior log entries are persisted everywhere.
*/
template <typename I>
-void WriteLog<I>::schedule_append_ops(GenericLogOperations &ops)
+void WriteLog<I>::schedule_append_ops(GenericLogOperations &ops, C_BlockIORequestT *req)
{
bool need_finisher;
GenericLogOperationsVector appending;
using AbstractWriteLog<ImageCtxT>::m_first_valid_entry;
void process_work() override;
- void schedule_append_ops(pwl::GenericLogOperations &ops) override;
+ void schedule_append_ops(pwl::GenericLogOperations &ops, C_BlockIORequestT *req) override;
void append_scheduled_ops(void) override;
void reserve_cache(C_BlockIORequestT *req,
bool &alloc_succeeds, bool &no_space) override;
* all prior log entries are persisted everywhere.
*/
template<typename I>
-void WriteLog<I>::schedule_append_ops(GenericLogOperations &ops) {
+void WriteLog<I>::schedule_append_ops(GenericLogOperations &ops, C_BlockIORequestT *req) {
bool need_finisher = false;
GenericLogOperationsVector appending;
need_finisher = has_sync_point_logs(ops);
}
this->m_ops_to_append.splice(this->m_ops_to_append.end(), ops);
+
+ // To preserve the order of overlapping IOs, release_cell() may be
+ // called only after the ops are added to m_ops_to_append.
+ // As soon as m_lock is released, the appended ops can be picked up
+ // by append_scheduled_ops() in another thread and req can be freed.
+ if (req != nullptr) {
+ if (persist_on_flush) {
+ req->complete_user_request(0);
+ }
+ req->release_cell();
+ }
}
if (need_finisher) {
void WriteLog<I>::setup_schedule_append(pwl::GenericLogOperationsVector &ops,
bool do_early_flush,
C_BlockIORequestT *req) {
- this->schedule_append(ops);
- if (this->get_persist_on_flush()) {
- req->complete_user_request(0);
- }
- req->release_cell();
+ this->schedule_append(ops, req);
}
template <typename I>
pwl::DeferredContexts &later) override;
void process_work() override;
void append_scheduled_ops(void) override;
- void schedule_append_ops(pwl::GenericLogOperations &ops) override;
+ void schedule_append_ops(pwl::GenericLogOperations &ops, C_BlockIORequestT *req) override;
void remove_pool_file() override;
void release_ram(std::shared_ptr<GenericLogEntry> log_entry) override;