]>
Commit | Line | Data |
---|---|---|
9f95a23c TL |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | ||
4 | #include "common/debug.h" | |
5 | #include "SimplePolicy.h" | |
6 | ||
7 | #define dout_context g_ceph_context | |
8 | #define dout_subsys ceph_subsys_immutable_obj_cache | |
9 | #undef dout_prefix | |
10 | #define dout_prefix *_dout << "ceph::cache::SimplePolicy: " << this << " " \ | |
11 | << __func__ << ": " | |
12 | ||
13 | namespace ceph { | |
14 | namespace immutable_obj_cache { | |
15 | ||
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) { | |
20 | ||
21 | ldout(cct, 20) << "max cache size= " << m_max_cache_size | |
22 | << " ,watermark= " << m_watermark | |
23 | << " ,max inflight ops= " << m_max_inflight_ops << dendl; | |
24 | ||
25 | m_cache_size = 0; | |
26 | ||
27 | } | |
28 | ||
29 | SimplePolicy::~SimplePolicy() { | |
30 | ldout(cct, 20) << dendl; | |
31 | ||
32 | for (auto it : m_cache_map) { | |
33 | Entry* entry = (it.second); | |
34 | delete entry; | |
35 | } | |
36 | } | |
37 | ||
38 | cache_status_t SimplePolicy::alloc_entry(std::string file_name) { | |
39 | ldout(cct, 20) << "alloc entry for: " << file_name << dendl; | |
40 | ||
41 | std::unique_lock wlocker{m_cache_map_lock}; | |
42 | ||
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; | |
47 | } | |
48 | ||
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; | |
54 | wlocker.unlock(); | |
55 | update_status(file_name, OBJ_CACHE_SKIP); | |
56 | return OBJ_CACHE_NONE; // start promotion request | |
57 | } | |
58 | ||
59 | // if there's no free entry, return skip to read from rados | |
60 | return OBJ_CACHE_SKIP; | |
61 | } | |
62 | ||
63 | cache_status_t SimplePolicy::lookup_object(std::string file_name) { | |
64 | ldout(cct, 20) << "lookup: " << file_name << dendl; | |
65 | ||
66 | std::shared_lock rlocker{m_cache_map_lock}; | |
67 | ||
68 | auto entry_it = m_cache_map.find(file_name); | |
69 | // simply promote on first lookup | |
70 | if (entry_it == m_cache_map.end()) { | |
71 | rlocker.unlock(); | |
72 | return alloc_entry(file_name); | |
73 | } | |
74 | ||
75 | Entry* entry = entry_it->second; | |
76 | ||
f91f0fd5 | 77 | if (entry->status == OBJ_CACHE_PROMOTED || entry->status == OBJ_CACHE_DNE) { |
9f95a23c TL |
78 | // bump pos in lru on hit |
79 | m_promoted_lru.lru_touch(entry); | |
80 | } | |
81 | ||
82 | return entry->status; | |
83 | } | |
84 | ||
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; | |
89 | ||
90 | std::unique_lock locker{m_cache_map_lock}; | |
91 | ||
92 | auto entry_it = m_cache_map.find(file_name); | |
93 | if (entry_it == m_cache_map.end()) { | |
94 | return; | |
95 | } | |
96 | ||
97 | ceph_assert(entry_it != m_cache_map.end()); | |
98 | Entry* entry = entry_it->second; | |
99 | ||
100 | // to promote | |
101 | if (entry->status == OBJ_CACHE_NONE && new_status== OBJ_CACHE_SKIP) { | |
102 | entry->status = new_status; | |
103 | entry->file_name = file_name; | |
104 | inflight_ops++; | |
105 | return; | |
106 | } | |
107 | ||
108 | // promoting done | |
f91f0fd5 TL |
109 | if (entry->status == OBJ_CACHE_SKIP && (new_status== OBJ_CACHE_PROMOTED || |
110 | new_status== OBJ_CACHE_DNE)) { | |
9f95a23c TL |
111 | m_promoted_lru.lru_insert_top(entry); |
112 | entry->status = new_status; | |
113 | entry->size = size; | |
114 | m_cache_size += entry->size; | |
115 | inflight_ops--; | |
116 | return; | |
117 | } | |
118 | ||
119 | // promoting failed | |
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; | |
124 | ||
125 | m_cache_map.erase(entry_it); | |
126 | inflight_ops--; | |
127 | delete entry; | |
128 | return; | |
129 | } | |
130 | ||
131 | // to evict | |
f91f0fd5 TL |
132 | if ((entry->status == OBJ_CACHE_PROMOTED || entry->status == OBJ_CACHE_DNE) && |
133 | new_status== OBJ_CACHE_NONE) { | |
9f95a23c TL |
134 | // mark this entry as free |
135 | uint64_t size = entry->size; | |
136 | entry->file_name = ""; | |
137 | entry->size = 0; | |
138 | entry->status = new_status; | |
139 | ||
140 | m_promoted_lru.lru_remove(entry); | |
141 | m_cache_map.erase(entry_it); | |
142 | m_cache_size -= size; | |
143 | delete entry; | |
144 | return; | |
145 | } | |
146 | } | |
147 | ||
148 | int SimplePolicy::evict_entry(std::string file_name) { | |
149 | ldout(cct, 20) << "to evict: " << file_name << dendl; | |
150 | ||
151 | update_status(file_name, OBJ_CACHE_NONE); | |
152 | ||
153 | return 0; | |
154 | } | |
155 | ||
156 | cache_status_t SimplePolicy::get_status(std::string file_name) { | |
157 | ldout(cct, 20) << file_name << dendl; | |
158 | ||
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; | |
163 | } | |
164 | ||
165 | return entry_it->second->status; | |
166 | } | |
167 | ||
168 | void SimplePolicy::get_evict_list(std::list<std::string>* obj_list) { | |
169 | ldout(cct, 20) << dendl; | |
170 | ||
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 > (1 - 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) { | |
179 | continue; | |
180 | } | |
181 | std::string file_name = entry->file_name; | |
182 | obj_list->push_back(file_name); | |
183 | } | |
184 | } | |
185 | } | |
186 | ||
187 | // for unit test | |
188 | uint64_t SimplePolicy::get_free_size() { | |
189 | return m_max_cache_size - m_cache_size; | |
190 | } | |
191 | ||
192 | uint64_t SimplePolicy::get_promoting_entry_num() { | |
193 | uint64_t index = 0; | |
194 | std::shared_lock rlocker{m_cache_map_lock}; | |
195 | for (auto it : m_cache_map) { | |
196 | if (it.second->status == OBJ_CACHE_SKIP) { | |
197 | index++; | |
198 | } | |
199 | } | |
200 | return index; | |
201 | } | |
202 | ||
203 | uint64_t SimplePolicy::get_promoted_entry_num() { | |
204 | return m_promoted_lru.lru_get_size(); | |
205 | } | |
206 | ||
207 | std::string SimplePolicy::get_evict_entry() { | |
208 | Entry* entry = reinterpret_cast<Entry*>(m_promoted_lru.lru_get_next_expire()); | |
209 | if (entry == nullptr) { | |
210 | return ""; | |
211 | } | |
212 | return entry->file_name; | |
213 | } | |
214 | ||
215 | } // namespace immutable_obj_cache | |
216 | } // namespace ceph |