1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "common/debug.h"
5 #include "SimplePolicy.h"
7 #define dout_context g_ceph_context
8 #define dout_subsys ceph_subsys_immutable_obj_cache
10 #define dout_prefix *_dout << "ceph::cache::SimplePolicy: " << this << " " \
14 namespace immutable_obj_cache
{
16 SimplePolicy::SimplePolicy(CephContext
*cct
, uint64_t cache_size
,
17 uint64_t max_inflight
, double watermark
)
18 : cct(cct
), m_watermark(watermark
), m_max_inflight_ops(max_inflight
),
19 m_max_cache_size(cache_size
) {
21 ldout(cct
, 20) << "max cache size= " << m_max_cache_size
22 << " ,watermark= " << m_watermark
23 << " ,max inflight ops= " << m_max_inflight_ops
<< dendl
;
29 SimplePolicy::~SimplePolicy() {
30 ldout(cct
, 20) << dendl
;
32 for (auto it
: m_cache_map
) {
33 Entry
* entry
= (it
.second
);
38 cache_status_t
SimplePolicy::alloc_entry(std::string file_name
) {
39 ldout(cct
, 20) << "alloc entry for: " << file_name
<< dendl
;
41 std::unique_lock wlocker
{m_cache_map_lock
};
43 // cache hit when promoting
44 if (m_cache_map
.find(file_name
) != m_cache_map
.end()) {
45 ldout(cct
, 20) << "object is under promoting: " << file_name
<< dendl
;
46 return OBJ_CACHE_SKIP
;
49 if ((m_cache_size
< m_max_cache_size
) &&
50 (inflight_ops
< m_max_inflight_ops
)) {
51 Entry
* entry
= new Entry();
52 ceph_assert(entry
!= nullptr);
53 m_cache_map
[file_name
] = entry
;
55 update_status(file_name
, OBJ_CACHE_SKIP
);
56 return OBJ_CACHE_NONE
; // start promotion request
59 // if there's no free entry, return skip to read from rados
60 return OBJ_CACHE_SKIP
;
63 cache_status_t
SimplePolicy::lookup_object(std::string file_name
) {
64 ldout(cct
, 20) << "lookup: " << file_name
<< dendl
;
66 std::shared_lock rlocker
{m_cache_map_lock
};
68 auto entry_it
= m_cache_map
.find(file_name
);
69 // simply promote on first lookup
70 if (entry_it
== m_cache_map
.end()) {
72 return alloc_entry(file_name
);
75 Entry
* entry
= entry_it
->second
;
77 if (entry
->status
== OBJ_CACHE_PROMOTED
|| entry
->status
== OBJ_CACHE_DNE
) {
78 // bump pos in lru on hit
79 m_promoted_lru
.lru_touch(entry
);
85 void SimplePolicy::update_status(std::string file_name
,
86 cache_status_t new_status
, uint64_t size
) {
87 ldout(cct
, 20) << "update status for: " << file_name
88 << " new status = " << new_status
<< dendl
;
90 std::unique_lock locker
{m_cache_map_lock
};
92 auto entry_it
= m_cache_map
.find(file_name
);
93 if (entry_it
== m_cache_map
.end()) {
97 ceph_assert(entry_it
!= m_cache_map
.end());
98 Entry
* entry
= entry_it
->second
;
101 if (entry
->status
== OBJ_CACHE_NONE
&& new_status
== OBJ_CACHE_SKIP
) {
102 entry
->status
= new_status
;
103 entry
->file_name
= file_name
;
109 if (entry
->status
== OBJ_CACHE_SKIP
&& (new_status
== OBJ_CACHE_PROMOTED
||
110 new_status
== OBJ_CACHE_DNE
)) {
111 m_promoted_lru
.lru_insert_top(entry
);
112 entry
->status
= new_status
;
114 m_cache_size
+= entry
->size
;
120 if (entry
->status
== OBJ_CACHE_SKIP
&& new_status
== OBJ_CACHE_NONE
) {
121 // mark this entry as free
122 entry
->file_name
= "";
123 entry
->status
= new_status
;
125 m_cache_map
.erase(entry_it
);
132 if ((entry
->status
== OBJ_CACHE_PROMOTED
|| entry
->status
== OBJ_CACHE_DNE
) &&
133 new_status
== OBJ_CACHE_NONE
) {
134 // mark this entry as free
135 uint64_t size
= entry
->size
;
136 entry
->file_name
= "";
138 entry
->status
= new_status
;
140 m_promoted_lru
.lru_remove(entry
);
141 m_cache_map
.erase(entry_it
);
142 m_cache_size
-= size
;
148 int SimplePolicy::evict_entry(std::string file_name
) {
149 ldout(cct
, 20) << "to evict: " << file_name
<< dendl
;
151 update_status(file_name
, OBJ_CACHE_NONE
);
156 cache_status_t
SimplePolicy::get_status(std::string file_name
) {
157 ldout(cct
, 20) << file_name
<< dendl
;
159 std::shared_lock locker
{m_cache_map_lock
};
160 auto entry_it
= m_cache_map
.find(file_name
);
161 if (entry_it
== m_cache_map
.end()) {
162 return OBJ_CACHE_NONE
;
165 return entry_it
->second
->status
;
168 void SimplePolicy::get_evict_list(std::list
<std::string
>* obj_list
) {
169 ldout(cct
, 20) << dendl
;
171 std::unique_lock locker
{m_cache_map_lock
};
172 // check free ratio, pop entries from LRU
173 if ((double)m_cache_size
> m_max_cache_size
* m_watermark
) {
174 // TODO(dehao): make this configurable
175 int evict_num
= m_cache_map
.size() * 0.1;
176 for (int i
= 0; i
< evict_num
; i
++) {
177 Entry
* entry
= reinterpret_cast<Entry
*>(m_promoted_lru
.lru_expire());
178 if (entry
== nullptr) {
181 std::string file_name
= entry
->file_name
;
182 obj_list
->push_back(file_name
);
188 uint64_t SimplePolicy::get_free_size() {
189 return m_max_cache_size
- m_cache_size
;
192 uint64_t SimplePolicy::get_promoting_entry_num() {
194 std::shared_lock rlocker
{m_cache_map_lock
};
195 for (auto it
: m_cache_map
) {
196 if (it
.second
->status
== OBJ_CACHE_SKIP
) {
203 uint64_t SimplePolicy::get_promoted_entry_num() {
204 return m_promoted_lru
.lru_get_size();
207 std::string
SimplePolicy::get_evict_entry() {
208 Entry
* entry
= reinterpret_cast<Entry
*>(m_promoted_lru
.lru_get_next_expire());
209 if (entry
== nullptr) {
212 return entry
->file_name
;
215 } // namespace immutable_obj_cache