1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab ft=cpp
10 #include "include/rados/librados.hpp"
11 #include "include/Context.h"
12 #include "common/async/completion.h"
15 #include "common/error_code.h"
16 #include "common/errno.h"
19 #include "rgw_cache.h"
22 struct D3nGetObjData
{
26 struct D3nL1CacheRequest
{
27 ~D3nL1CacheRequest() {
28 lsubdout(g_ceph_context
, rgw_datacache
, 30) << "D3nDataCache: " << __func__
<< "(): Read From Cache, complete" << dendl
;
31 // unique_ptr with custom deleter for struct aiocb
32 struct libaio_aiocb_deleter
{
33 void operator()(struct aiocb
* c
) {
34 if(c
->aio_fildes
> 0) {
35 if( ::close(c
->aio_fildes
) != 0) {
36 lsubdout(g_ceph_context
, rgw_datacache
, 2) << "D3nDataCache: " << __func__
<< "(): Error - can't close file, errno=" << -errno
<< dendl
;
43 using unique_aio_cb_ptr
= std::unique_ptr
<struct aiocb
, libaio_aiocb_deleter
>;
45 struct AsyncFileReadOp
{
47 unique_aio_cb_ptr aio_cb
;
48 using Signature
= void(boost::system::error_code
, bufferlist
);
49 using Completion
= ceph::async::Completion
<Signature
, AsyncFileReadOp
>;
51 int init(const DoutPrefixProvider
*dpp
, const std::string
& file_path
, off_t read_ofs
, off_t read_len
, void* arg
) {
52 ldpp_dout(dpp
, 20) << "D3nDataCache: " << __func__
<< "(): file_path=" << file_path
<< dendl
;
53 aio_cb
.reset(new struct aiocb
);
54 memset(aio_cb
.get(), 0, sizeof(struct aiocb
));
55 aio_cb
->aio_fildes
= TEMP_FAILURE_RETRY(::open(file_path
.c_str(), O_RDONLY
|O_CLOEXEC
|O_BINARY
));
56 if(aio_cb
->aio_fildes
< 0) {
58 ldpp_dout(dpp
, 1) << "ERROR: D3nDataCache: " << __func__
<< "(): can't open " << file_path
<< " : " << cpp_strerror(err
) << dendl
;
61 if (g_conf()->rgw_d3n_l1_fadvise
!= POSIX_FADV_NORMAL
)
62 posix_fadvise(aio_cb
->aio_fildes
, 0, 0, g_conf()->rgw_d3n_l1_fadvise
);
64 bufferptr
bp(read_len
);
65 aio_cb
->aio_buf
= bp
.c_str();
66 result
.append(std::move(bp
));
68 aio_cb
->aio_nbytes
= read_len
;
69 aio_cb
->aio_offset
= read_ofs
;
70 aio_cb
->aio_sigevent
.sigev_notify
= SIGEV_THREAD
;
71 aio_cb
->aio_sigevent
.sigev_notify_function
= libaio_cb_aio_dispatch
;
72 aio_cb
->aio_sigevent
.sigev_notify_attributes
= nullptr;
73 aio_cb
->aio_sigevent
.sigev_value
.sival_ptr
= arg
;
78 static void libaio_cb_aio_dispatch(sigval sigval
) {
79 lsubdout(g_ceph_context
, rgw_datacache
, 20) << "D3nDataCache: " << __func__
<< "()" << dendl
;
80 auto p
= std::unique_ptr
<Completion
>{static_cast<Completion
*>(sigval
.sival_ptr
)};
81 auto op
= std::move(p
->user_data
);
82 const int ret
= -aio_error(op
.aio_cb
.get());
83 boost::system::error_code ec
;
85 ec
.assign(-ret
, boost::system::system_category());
88 ceph::async::dispatch(std::move(p
), ec
, std::move(op
.result
));
91 template <typename Executor1
, typename CompletionHandler
>
92 static auto create(const Executor1
& ex1
, CompletionHandler
&& handler
) {
93 auto p
= Completion::create(ex1
, std::move(handler
));
98 template <typename ExecutionContext
, typename CompletionToken
>
99 auto async_read(const DoutPrefixProvider
*dpp
, ExecutionContext
& ctx
, const std::string
& file_path
,
100 off_t read_ofs
, off_t read_len
, CompletionToken
&& token
) {
101 using Op
= AsyncFileReadOp
;
102 using Signature
= typename
Op::Signature
;
103 boost::asio::async_completion
<CompletionToken
, Signature
> init(token
);
104 auto p
= Op::create(ctx
.get_executor(), init
.completion_handler
);
105 auto& op
= p
->user_data
;
107 ldpp_dout(dpp
, 20) << "D3nDataCache: " << __func__
<< "(): file_path=" << file_path
<< dendl
;
108 int ret
= op
.init(dpp
, file_path
, read_ofs
, read_len
, p
.get());
110 ret
= ::aio_read(op
.aio_cb
.get());
112 ldpp_dout(dpp
, 20) << "D3nDataCache: " << __func__
<< "(): ::aio_read(), ret=" << ret
<< dendl
;
114 auto ec
= boost::system::error_code
{-ret
, boost::system::system_category()};
115 ceph::async::post(std::move(p
), ec
, bufferlist
{});
119 return init
.result
.get();
122 struct d3n_libaio_handler
{
123 rgw::Aio
* throttle
= nullptr;
126 void operator()(boost::system::error_code ec
, bufferlist bl
) const {
127 r
.result
= -ec
.value();
128 r
.data
= std::move(bl
);
133 void file_aio_read_abstract(const DoutPrefixProvider
*dpp
, boost::asio::io_context
& context
, yield_context yield
,
134 std::string
& file_path
, off_t read_ofs
, off_t read_len
,
135 rgw::Aio
* aio
, rgw::AioResult
& r
) {
136 using namespace boost::asio
;
137 async_completion
<yield_context
, void()> init(yield
);
138 auto ex
= get_associated_executor(init
.completion_handler
);
140 auto& ref
= r
.obj
.get_ref();
141 ldpp_dout(dpp
, 20) << "D3nDataCache: " << __func__
<< "(): oid=" << ref
.obj
.oid
<< dendl
;
142 async_read(dpp
, context
, file_path
+"/"+ref
.obj
.oid
, read_ofs
, read_len
, bind_executor(ex
, d3n_libaio_handler
{aio
, r
}));