1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab ft=cpp
4 #ifndef CEPH_RGWD3NDATACACHE_H
5 #define CEPH_RGWD3NDATACACHE_H
10 #include "rgw_common.h"
14 #include "include/Context.h"
15 #include "include/lru.h"
16 #include "rgw_d3n_cacherequest.h"
23 struct D3nChunkDataInfo
: public LRUObject
{
30 struct D3nChunkDataInfo
* lru_prev
;
31 struct D3nChunkDataInfo
* lru_next
;
33 D3nChunkDataInfo(): size(0) {}
35 void set_ctx(CephContext
*_cct
) {
39 void dump(Formatter
*f
) const;
40 static void generate_test_instances(std::list
<D3nChunkDataInfo
*>& o
);
43 struct D3nCacheAioWriteRequest
{
48 D3nDataCache
*priv_data
;
51 D3nCacheAioWriteRequest(CephContext
*_cct
) : cct(_cct
) {}
52 int d3n_prepare_libaio_write_op(bufferlist
& bl
, unsigned int len
, std::string oid
, std::string cache_location
);
54 ~D3nCacheAioWriteRequest() {
56 cb
->aio_buf
= nullptr;
66 std::unordered_map
<std::string
, D3nChunkDataInfo
*> d3n_cache_map
;
67 std::set
<std::string
> d3n_outstanding_write_list
;
68 std::mutex d3n_cache_lock
;
69 std::mutex d3n_eviction_lock
;
77 enum class _eviction_policy
{
81 struct sigaction action
;
82 uint64_t free_data_cache_size
= 0;
83 uint64_t outstanding_write_size
= 0;
84 struct D3nChunkDataInfo
* head
;
85 struct D3nChunkDataInfo
* tail
;
93 while (lru_eviction() > 0);
96 std::string cache_location
;
98 bool get(const std::string
& oid
, const off_t len
);
99 void put(bufferlist
& bl
, unsigned int len
, std::string
& obj_key
);
100 int d3n_io_write(bufferlist
& bl
, unsigned int len
, std::string oid
);
101 int d3n_libaio_create_write_request(bufferlist
& bl
, unsigned int len
, std::string oid
);
102 void d3n_libaio_write_completion_cb(D3nCacheAioWriteRequest
* c
);
103 size_t random_eviction();
104 size_t lru_eviction();
106 void init(CephContext
*_cct
);
108 void lru_insert_head(struct D3nChunkDataInfo
* o
) {
109 lsubdout(g_ceph_context
, rgw_datacache
, 30) << "D3nDataCache: " << __func__
<< "()" << dendl
;
111 o
->lru_prev
= nullptr;
120 void lru_insert_tail(struct D3nChunkDataInfo
* o
) {
121 lsubdout(g_ceph_context
, rgw_datacache
, 30) << "D3nDataCache: " << __func__
<< "()" << dendl
;
122 o
->lru_next
= nullptr;
132 void lru_remove(struct D3nChunkDataInfo
* o
) {
133 lsubdout(g_ceph_context
, rgw_datacache
, 30) << "D3nDataCache: " << __func__
<< "()" << dendl
;
135 o
->lru_next
->lru_prev
= o
->lru_prev
;
139 o
->lru_prev
->lru_next
= o
->lru_next
;
142 o
->lru_next
= o
->lru_prev
= nullptr;
148 class D3nRGWDataCache
: public T
{
153 int init_rados() override
{
155 ret
= T::init_rados();
162 int get_obj_iterate_cb(const DoutPrefixProvider
*dpp
, const rgw_raw_obj
& read_obj
, off_t obj_ofs
,
163 off_t read_ofs
, off_t len
, bool is_head_obj
,
164 RGWObjState
*astate
, void *arg
) override
;
168 int D3nRGWDataCache
<T
>::get_obj_iterate_cb(const DoutPrefixProvider
*dpp
, const rgw_raw_obj
& read_obj
, off_t obj_ofs
,
169 off_t read_ofs
, off_t len
, bool is_head_obj
,
170 RGWObjState
*astate
, void *arg
) {
171 lsubdout(g_ceph_context
, rgw_datacache
, 30) << "D3nDataCache::" << __func__
<< "(): is head object : " << is_head_obj
<< dendl
;
172 librados::ObjectReadOperation op
;
173 struct get_obj_data
* d
= static_cast<struct get_obj_data
*>(arg
);
174 std::string oid
, key
;
177 // only when reading from the head object do we need to do the atomic test
178 int r
= T::append_atomic_test(dpp
, astate
, op
);
183 obj_ofs
< astate
->data
.length()) {
184 unsigned chunk_len
= std::min((uint64_t)astate
->data
.length() - obj_ofs
, (uint64_t)len
);
186 r
= d
->client_cb
->handle_data(astate
->data
, obj_ofs
, chunk_len
);
191 d
->offset
+= chunk_len
;
192 read_ofs
+= chunk_len
;
193 obj_ofs
+= chunk_len
;
198 auto obj
= d
->rgwrados
->svc
.rados
->obj(read_obj
);
201 lsubdout(g_ceph_context
, rgw
, 4) << "failed to open rados context for " << read_obj
<< dendl
;
205 ldpp_dout(dpp
, 20) << "D3nDataCache::" << __func__
<< "(): oid=" << read_obj
.oid
<< " obj-ofs=" << obj_ofs
<< " read_ofs=" << read_ofs
<< " len=" << len
<< dendl
;
206 op
.read(read_ofs
, len
, nullptr, nullptr);
208 const uint64_t cost
= len
;
209 const uint64_t id
= obj_ofs
; // use logical object offset for sorting replies
211 auto completed
= d
->aio
->get(obj
, rgw::Aio::librados_op(std::move(op
), d
->yield
), cost
, id
);
212 return d
->flush(std::move(completed
));
214 ldpp_dout(dpp
, 20) << "D3nDataCache::" << __func__
<< "(): oid=" << read_obj
.oid
<< ", is_head_obj=" << is_head_obj
<< ", obj-ofs=" << obj_ofs
<< ", read_ofs=" << read_ofs
<< ", len=" << len
<< dendl
;
217 op
.read(read_ofs
, len
, nullptr, nullptr);
219 const uint64_t cost
= len
;
220 const uint64_t id
= obj_ofs
; // use logical object offset for sorting replies
223 auto obj
= d
->rgwrados
->svc
.rados
->obj(read_obj
);
226 lsubdout(g_ceph_context
, rgw
, 0) << "D3nDataCache: Error: failed to open rados context for " << read_obj
<< ", r=" << r
<< dendl
;
230 const bool is_compressed
= (astate
->attrset
.find(RGW_ATTR_COMPRESSION
) != astate
->attrset
.end());
231 const bool is_encrypted
= (astate
->attrset
.find(RGW_ATTR_CRYPT_MODE
) != astate
->attrset
.end());
232 if (read_ofs
!= 0 || astate
->size
!= astate
->accounted_size
|| is_compressed
|| is_encrypted
) {
233 d
->d3n_bypass_cache_write
= true;
234 lsubdout(g_ceph_context
, rgw
, 5) << "D3nDataCache: " << __func__
<< "(): Note - bypassing datacache: oid=" << read_obj
.oid
<< ", read_ofs!=0 = " << read_ofs
<< ", size=" << astate
->size
<< " != accounted_size=" << astate
->accounted_size
<< ", is_compressed=" << is_compressed
<< ", is_encrypted=" << is_encrypted
<< dendl
;
235 auto completed
= d
->aio
->get(obj
, rgw::Aio::librados_op(std::move(op
), d
->yield
), cost
, id
);
236 r
= d
->flush(std::move(completed
));
240 if (d
->rgwrados
->d3n_data_cache
->get(oid
, len
)) {
242 ldpp_dout(dpp
, 20) << "D3nDataCache: " << __func__
<< "(): READ FROM CACHE: oid=" << read_obj
.oid
<< ", obj-ofs=" << obj_ofs
<< ", read_ofs=" << read_ofs
<< ", len=" << len
<< dendl
;
243 auto completed
= d
->aio
->get(obj
, rgw::Aio::d3n_cache_op(dpp
, d
->yield
, read_ofs
, len
, d
->rgwrados
->d3n_data_cache
->cache_location
), cost
, id
);
244 r
= d
->flush(std::move(completed
));
246 lsubdout(g_ceph_context
, rgw
, 0) << "D3nDataCache: " << __func__
<< "(): Error: failed to drain/flush, r= " << r
<< dendl
;
251 ldpp_dout(dpp
, 20) << "D3nDataCache: " << __func__
<< "(): WRITE TO CACHE: oid=" << read_obj
.oid
<< ", obj-ofs=" << obj_ofs
<< ", read_ofs=" << read_ofs
<< " len=" << len
<< dendl
;
252 auto completed
= d
->aio
->get(obj
, rgw::Aio::librados_op(std::move(op
), d
->yield
), cost
, id
);
253 return d
->flush(std::move(completed
));
256 lsubdout(g_ceph_context
, rgw
, 1) << "D3nDataCache: " << __func__
<< "(): Warning: Check head object cache handling flow, oid=" << read_obj
.oid
<< dendl
;