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   	
77   	  if (entry->status == OBJ_CACHE_PROMOTED) {
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
109  	  if (entry->status == OBJ_CACHE_SKIP && new_status== OBJ_CACHE_PROMOTED) {
110  	    m_promoted_lru.lru_insert_top(entry);
111  	    entry->status = new_status;
112  	    entry->size = size;
113  	    m_cache_size += entry->size;
114  	    inflight_ops--;
115  	    return;
116  	  }
117  	
118  	  // promoting failed
119  	  if (entry->status == OBJ_CACHE_SKIP && new_status== OBJ_CACHE_NONE) {
120  	    // mark this entry as free
121  	    entry->file_name = "";
122  	    entry->status = new_status;
123  	
124  	    m_cache_map.erase(entry_it);
125  	    inflight_ops--;
126  	    delete entry;
127  	    return;
128  	  }
129  	
130  	  // to evict
131  	  if (entry->status == OBJ_CACHE_PROMOTED && new_status== OBJ_CACHE_NONE) {
132  	    // mark this entry as free
(1) Event parameter_hidden: declaration hides parameter "size" (declared at line 86)
(2) Event caretline: ^
133  	    uint64_t size = entry->size;
134  	    entry->file_name = "";
135  	    entry->size = 0;
136  	    entry->status = new_status;
137  	
138  	    m_promoted_lru.lru_remove(entry);
139  	    m_cache_map.erase(entry_it);
140  	    m_cache_size -= size;
141  	    delete entry;
142  	    return;
143  	  }
144  	}
145  	
146  	int SimplePolicy::evict_entry(std::string file_name) {
147  	  ldout(cct, 20) << "to evict: " << file_name << dendl;
148  	
149  	  update_status(file_name, OBJ_CACHE_NONE);
150  	
151  	  return 0;
152  	}
153  	
154  	cache_status_t SimplePolicy::get_status(std::string file_name) {
155  	  ldout(cct, 20) << file_name << dendl;
156  	
157  	  std::shared_lock locker{m_cache_map_lock};
158  	  auto entry_it = m_cache_map.find(file_name);
159  	  if (entry_it == m_cache_map.end()) {
160  	    return OBJ_CACHE_NONE;
161  	  }
162  	
163  	  return entry_it->second->status;
164  	}
165  	
166  	void SimplePolicy::get_evict_list(std::list<std::string>* obj_list) {
167  	  ldout(cct, 20) << dendl;
168  	
169  	  std::unique_lock locker{m_cache_map_lock};
170  	  // check free ratio, pop entries from LRU
171  	  if ((double)m_cache_size / m_max_cache_size > (1 - m_watermark)) {
172  	    // TODO(dehao): make this configurable
173  	    int evict_num = m_cache_map.size() * 0.1;
174  	    for (int i = 0; i < evict_num; i++) {
175  	      Entry* entry = reinterpret_cast<Entry*>(m_promoted_lru.lru_expire());
176  	      if (entry == nullptr) {
177  	        continue;
178  	      }
179  	      std::string file_name = entry->file_name;
180  	      obj_list->push_back(file_name);
181  	    }
182  	  }
183  	}
184  	
185  	// for unit test
186  	uint64_t SimplePolicy::get_free_size() {
187  	  return m_max_cache_size - m_cache_size;
188  	}
189  	
190  	uint64_t SimplePolicy::get_promoting_entry_num() {
191  	  uint64_t index = 0;
192  	  std::shared_lock rlocker{m_cache_map_lock};
193  	  for (auto it : m_cache_map) {
194  	    if (it.second->status == OBJ_CACHE_SKIP) {
195  	      index++;
196  	    }
197  	  }
198  	  return index;
199  	}
200  	
201  	uint64_t SimplePolicy::get_promoted_entry_num() {
202  	  return m_promoted_lru.lru_get_size();
203  	}
204  	
205  	std::string SimplePolicy::get_evict_entry() {
206  	  Entry* entry = reinterpret_cast<Entry*>(m_promoted_lru.lru_get_next_expire());
207  	  if (entry == nullptr) {
208  	    return "";
209  	  }
210  	  return entry->file_name;
211  	}
212  	
213  	}  // namespace immutable_obj_cache
214  	}  // namespace ceph
215