CernVM-FS  2.10.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
cache_ram.cc
Go to the documentation of this file.
1 
4 #include "cvmfs_config.h"
5 #include "cache_ram.h"
6 
7 #include <errno.h>
8 #include <algorithm>
9 #include <cassert>
10 #include <cstring>
11 #include <new>
12 
13 #include "kvstore.h"
14 #include "logging.h"
15 #include "util/posix.h"
16 #include "util/string.h"
17 #include "util_concurrency.h"
18 
19 using namespace std; // NOLINT
20 
22 
24  return "Internal in-memory cache manager (size " +
25  StringifyInt(max_size_ / (1024 * 1024)) + "MB)\n";
26 }
27 
28 
30  uint64_t max_size,
31  unsigned max_entries,
33  perf::StatisticsTemplate statistics)
34  : max_size_(max_size)
35  , fd_table_(max_entries, ReadOnlyHandle())
36  // TODO(jblomer): the number of slots in the kv-stores should _not_ be the
37  // number of open files.
38  , regular_entries_(max_entries,
39  alloc,
40  max_size,
41  perf::StatisticsTemplate("kv.regular", statistics))
42  , volatile_entries_(max_entries,
43  alloc,
44  max_size,
45  perf::StatisticsTemplate("kv.volatile", statistics))
46  , counters_(statistics)
47 {
48  int retval = pthread_rwlock_init(&rwlock_, NULL);
49  assert(retval == 0);
50  LogCvmfs(kLogCache, kLogDebug, "max %u B, %u entries",
51  max_size, max_entries);
52 }
53 
54 
56  pthread_rwlock_destroy(&rwlock_);
57 }
58 
59 
61  int result = fd_table_.OpenFd(handle);
62  if (result == -ENFILE) {
63  LogCvmfs(kLogCache, kLogDebug, "too many open files");
65  }
66  return result;
67 }
68 
69 
71  assert(quota_mgr != NULL);
73  LogCvmfs(kLogCache, kLogDebug, "set quota manager");
74  return true;
75 }
76 
77 
79  WriteLockGuard guard(rwlock_);
80  return DoOpen(object.id);
81 }
82 
83 
85  bool ok;
86  bool is_volatile;
87  MemoryBuffer buf;
88 
89  if (regular_entries_.Contains(id)) {
90  is_volatile = false;
91  } else if (volatile_entries_.Contains(id)) {
92  is_volatile = true;
93  } else {
94  LogCvmfs(kLogCache, kLogDebug, "miss for %s",
95  id.ToString().c_str());
97  return -ENOENT;
98  }
99  ReadOnlyHandle generic_handle(id, is_volatile);
100  int fd = AddFd(generic_handle);
101  if (fd < 0) {
102  LogCvmfs(kLogCache, kLogDebug, "error while opening %s: %s",
103  id.ToString().c_str(), strerror(-fd));
104  return fd;
105  }
106  if (is_volatile) {
107  LogCvmfs(kLogCache, kLogDebug, "hit in volatile entries for %s",
108  id.ToString().c_str());
110  } else {
111  LogCvmfs(kLogCache, kLogDebug, "hit in regular entries for %s",
112  id.ToString().c_str());
114  }
115  ok = GetStore(generic_handle)->IncRef(id);
116  assert(ok);
117  return fd;
118 }
119 
120 
121 int64_t RamCacheManager::GetSize(int fd) {
122  ReadLockGuard guard(rwlock_);
123  ReadOnlyHandle generic_handle = fd_table_.GetHandle(fd);
124  if (generic_handle.handle == kInvalidHandle) {
125  LogCvmfs(kLogCache, kLogDebug, "bad fd %d on GetSize", fd);
126  return -EBADF;
127  }
129  return GetStore(generic_handle)->GetSize(generic_handle.handle);
130 }
131 
132 
134  bool rc;
135 
136  WriteLockGuard guard(rwlock_);
137  ReadOnlyHandle generic_handle = fd_table_.GetHandle(fd);
138  if (generic_handle.handle == kInvalidHandle) {
139  LogCvmfs(kLogCache, kLogDebug, "bad fd %d on Close", fd);
140  return -EBADF;
141  }
142  rc = GetStore(generic_handle)->Unref(generic_handle.handle);
143  assert(rc);
144 
145  int rc_int = fd_table_.CloseFd(fd);
146  assert(rc_int == 0);
147  LogCvmfs(kLogCache, kLogDebug, "closed fd %d", fd);
149  return 0;
150 }
151 
152 
154  int fd,
155  void *buf,
156  uint64_t size,
157  uint64_t offset)
158 {
159  ReadLockGuard guard(rwlock_);
160  ReadOnlyHandle generic_handle = fd_table_.GetHandle(fd);
161  if (generic_handle.handle == kInvalidHandle) {
162  LogCvmfs(kLogCache, kLogDebug, "bad fd %d on Pread", fd);
163  return -EBADF;
164  }
166  return GetStore(generic_handle)->Read(
167  generic_handle.handle, buf, size, offset);
168 }
169 
170 
171 int RamCacheManager::Dup(int fd) {
172  bool ok;
173  int rc;
174  WriteLockGuard guard(rwlock_);
175  ReadOnlyHandle generic_handle = fd_table_.GetHandle(fd);
176  if (generic_handle.handle == kInvalidHandle) {
177  LogCvmfs(kLogCache, kLogDebug, "bad fd %d on Dup", fd);
178  return -EBADF;
179  }
180  rc = AddFd(generic_handle);
181  if (rc < 0) return rc;
182  ok = GetStore(generic_handle)->IncRef(generic_handle.handle);
183  assert(ok);
184  LogCvmfs(kLogCache, kLogDebug, "dup fd %d", fd);
186  return rc;
187 }
188 
189 
194  ReadLockGuard guard(rwlock_);
195  ReadOnlyHandle generic_handle = fd_table_.GetHandle(fd);
196  if (generic_handle.handle == kInvalidHandle) {
197  LogCvmfs(kLogCache, kLogDebug, "bad fd %d on Readahead", fd);
198  return -EBADF;
199  }
200  LogCvmfs(kLogCache, kLogDebug, "readahead (no-op) on %d", fd);
202  return 0;
203 }
204 
205 
206 int RamCacheManager::StartTxn(const shash::Any &id, uint64_t size, void *txn) {
207  LogCvmfs(kLogCache, kLogDebug, "new transaction with id %s",
208  id.ToString().c_str());
209  Transaction *transaction = new (txn) Transaction();
210  transaction->buffer.id = id;
211  transaction->pos = 0;
212  transaction->expected_size = size;
213  transaction->buffer.size = (size == kSizeUnknown) ? kPageSize : size;
214  transaction->buffer.address = malloc(transaction->buffer.size);
215  if (!transaction->buffer.address && size > 0) {
217  "failed to allocate %lu B for %s",
218  size, id.ToString().c_str());
219  return -errno;
220  }
222  return 0;
223 }
224 
225 
227  const ObjectInfo &object_info,
228  const int flags,
229  void *txn)
230 {
231  Transaction *transaction = reinterpret_cast<Transaction *>(txn);
232  transaction->description = object_info.description;
233  transaction->buffer.object_type = object_info.type;
234  LogCvmfs(kLogCache, kLogDebug, "modified transaction %s",
235  transaction->buffer.id.ToString().c_str());
236 }
237 
238 
239 int64_t RamCacheManager::Write(const void *buf, uint64_t size, void *txn) {
240  Transaction *transaction = reinterpret_cast<Transaction *>(txn);
241 
242  assert(transaction->pos <= transaction->buffer.size);
243  if (transaction->pos + size > transaction->buffer.size) {
244  if (transaction->expected_size == kSizeUnknown) {
246  size_t new_size = max(2*transaction->buffer.size,
247  (size_t) (size + transaction->pos));
248  LogCvmfs(kLogCache, kLogDebug, "reallocate transaction for %s to %u B",
249  transaction->buffer.id.ToString().c_str(),
250  transaction->buffer.size);
251  void *new_ptr = realloc(transaction->buffer.address, new_size);
252  if (!new_ptr) {
254  "failed to allocate %lu B for %s",
255  new_size, transaction->buffer.id.ToString().c_str());
256  return -EIO;
257  }
258  transaction->buffer.address = new_ptr;
259  transaction->buffer.size = new_size;
260  } else {
262  "attempted to write more than requested (%u>%u)",
263  size, transaction->buffer.size);
264  return -EFBIG;
265  }
266  }
267 
268  if (transaction->buffer.address && buf) {
269  // LogCvmfs(kLogCache, kLogDebug, "copy %u bytes of transaction %s",
270  // size, transaction->id.ToString().c_str());
271  memcpy(static_cast<char *>(transaction->buffer.address) + transaction->pos,
272  buf, size);
273  }
274  transaction->pos += size;
276  return size;
277 }
278 
279 
280 int RamCacheManager::Reset(void *txn) {
281  Transaction *transaction = reinterpret_cast<Transaction *>(txn);
282  transaction->pos = 0;
283  LogCvmfs(kLogCache, kLogDebug, "reset transaction %s",
284  transaction->buffer.id.ToString().c_str());
286  return 0;
287 }
288 
289 
291  WriteLockGuard guard(rwlock_);
292  Transaction *transaction = reinterpret_cast<Transaction *>(txn);
293  int64_t retval = CommitToKvStore(transaction);
294  if (retval < 0) {
296  "error while commiting transaction on %s: %s",
297  transaction->buffer.id.ToString().c_str(), strerror(-retval));
298  return retval;
299  }
300  LogCvmfs(kLogCache, kLogDebug, "open pending transaction for %s",
301  transaction->buffer.id.ToString().c_str());
303  return DoOpen(transaction->buffer.id);
304 }
305 
306 
308  Transaction *transaction = reinterpret_cast<Transaction *>(txn);
309  free(transaction->buffer.address);
310  LogCvmfs(kLogCache, kLogDebug, "abort transaction %s",
311  transaction->buffer.id.ToString().c_str());
313  return 0;
314 }
315 
316 
318  WriteLockGuard guard(rwlock_);
319  Transaction *transaction = reinterpret_cast<Transaction *>(txn);
321  int64_t rc = CommitToKvStore(transaction);
322  if (rc < 0) return rc;
323  free(transaction->buffer.address);
324  return rc;
325 }
326 
327 
329  MemoryKvStore *store;
330 
331  if (transaction->buffer.object_type == kTypeVolatile) {
332  store = &volatile_entries_;
333  } else {
334  store = &regular_entries_;
335  }
336  if (transaction->buffer.object_type == kTypePinned ||
337  transaction->buffer.object_type == kTypeCatalog) {
338  transaction->buffer.refcount = 1;
339  } else {
340  transaction->buffer.refcount = 0;
341  }
342 
343  int64_t regular_size = regular_entries_.GetUsed();
344  int64_t volatile_size = volatile_entries_.GetUsed();
345  int64_t overrun = regular_size + volatile_size +
346  transaction->buffer.size - max_size_;
347 
348  if (overrun > 0) {
349  // if we're going to clean the cache, try to remove at least 25%
350  overrun = max(overrun, (int64_t) max_size_>>2);
352  volatile_entries_.ShrinkTo(max((int64_t) 0, volatile_size - overrun));
353  }
354  overrun -= volatile_size - volatile_entries_.GetUsed();
355  if (overrun > 0) {
356  regular_entries_.ShrinkTo(max((int64_t) 0, regular_size - overrun));
357  }
358  overrun -= regular_size -regular_entries_.GetUsed();
359  if (overrun > 0) {
361  "transaction for %s would overrun the cache limit by %d",
362  transaction->buffer.id.ToString().c_str(), overrun);
364  return -ENOSPC;
365  }
366 
367  int rc = store->Commit(transaction->buffer);
368  if (rc < 0) {
370  "commit on %s failed",
371  transaction->buffer.id.ToString().c_str());
372  return rc;
373  }
374  LogCvmfs(kLogCache, kLogDebug, "committed %s to cache",
375  transaction->buffer.id.ToString().c_str());
376  return 0;
377 }
perf::Counter * n_aborttxn
Definition: cache_ram.h:55
#define LogCvmfs(source, mask,...)
Definition: logging.h:20
perf::Counter * n_openmiss
Definition: cache_ram.h:60
virtual CacheManagerIds id()
Definition: cache_ram.h:103
RamCacheManager(uint64_t max_size, unsigned max_entries, MemoryKvStore::MemoryAllocator alloc, perf::StatisticsTemplate statistics)
Definition: cache_ram.cc:29
perf::Counter * n_getsize
Definition: cache_ram.h:47
virtual int OpenFromTxn(void *txn)
Definition: cache_ram.cc:290
virtual void CtrlTxn(const ObjectInfo &object_info, const int flags, void *txn)
Definition: cache_ram.cc:226
perf::Counter * n_pread
Definition: cache_ram.h:49
static const shash::Any kInvalidHandle
Definition: cache_ram.h:245
perf::Counter * n_write
Definition: cache_ram.h:53
bool Contains(const shash::Any &id)
Definition: kvstore.cc:88
std::string ToString(const bool with_suffix=false) const
Definition: hash.h:248
int64_t Read(const shash::Any &id, void *buf, size_t size, size_t offset)
Definition: kvstore.cc:236
perf::Counter * n_full
Definition: cache_ram.h:62
virtual int Close(int fd)
Definition: cache_ram.cc:133
perf::Counter * n_committxn
Definition: cache_ram.h:56
virtual int CommitTxn(void *txn)
Definition: cache_ram.cc:317
assert((mem||(size==0))&&"Out Of Memory")
MemoryKvStore * GetStore(const ReadOnlyHandle &fd)
Definition: cache_ram.h:278
unsigned int refcount
Definition: kvstore.h:49
virtual int AbortTxn(void *txn)
Definition: cache_ram.cc:307
std::string description
Definition: cache.h:97
perf::Counter * n_starttxn
Definition: cache_ram.h:52
virtual int Dup(int fd)
Definition: cache_ram.cc:171
virtual int StartTxn(const shash::Any &id, uint64_t size, void *txn)
Definition: cache_ram.cc:206
int Commit(const MemoryBuffer &buf)
Definition: kvstore.cc:263
void Transaction()
virtual int64_t Pread(int fd, void *buf, uint64_t size, uint64_t offset)
Definition: cache_ram.cc:153
virtual int Readahead(int fd)
Definition: cache_ram.cc:193
FdTable< ReadOnlyHandle > fd_table_
Definition: cache_ram.h:299
perf::Counter * n_readahead
Definition: cache_ram.h:51
ObjectType type
Definition: cache.h:93
perf::Counter * n_overrun
Definition: cache_ram.h:61
bool IncRef(const shash::Any &id)
Definition: kvstore.cc:198
perf::Counter * n_realloc
Definition: cache_ram.h:63
size_t GetUsed()
Definition: kvstore.h:200
int AddFd(const ReadOnlyHandle &handle)
Definition: cache_ram.cc:60
int64_t CommitToKvStore(Transaction *transaction)
Definition: cache_ram.cc:328
perf::Counter * n_openregular
Definition: cache_ram.h:58
bool Unref(const shash::Any &id)
Definition: kvstore.cc:217
perf::Counter * n_reset
Definition: cache_ram.h:54
shash::Any id
Definition: kvstore.h:51
string StringifyInt(const int64_t value)
Definition: string.cc:78
perf::Counter * n_dup
Definition: cache_ram.h:50
bool ShrinkTo(size_t size)
Definition: kvstore.cc:352
void Inc(class Counter *counter)
Definition: statistics.h:50
virtual int DoOpen(const shash::Any &id)
Definition: cache_ram.cc:84
perf::Counter * n_close
Definition: cache_ram.h:48
perf::Counter * n_enfile
Definition: cache_ram.h:57
perf::Counter * n_openvolatile
Definition: cache_ram.h:59
virtual std::string Describe()
Definition: cache_ram.cc:23
CacheManager::ObjectType object_type
Definition: kvstore.h:50
int64_t GetSize(const shash::Any &id)
Definition: kvstore.cc:166
Counters counters_
Definition: cache_ram.h:303
QuotaManager * quota_mgr()
Definition: cache.h:198
uint64_t max_size_
Definition: cache_ram.h:298
void * address
Definition: kvstore.h:47
size_t size
Definition: kvstore.h:48
const unsigned kPageSize
Definition: posix.h:29
virtual int Open(const BlessedObject &object)
Definition: cache_ram.cc:78
pthread_rwlock_t rwlock_
Definition: cache_ram.h:300
QuotaManager * quota_mgr_
Definition: cache.h:237
Definition: mutex.h:42
virtual int64_t GetSize(int fd)
Definition: cache_ram.cc:121
virtual int Reset(void *txn)
Definition: cache_ram.cc:280
virtual ~RamCacheManager()
Definition: cache_ram.cc:55
MemoryKvStore regular_entries_
Definition: cache_ram.h:301
MemoryKvStore volatile_entries_
Definition: cache_ram.h:302
virtual int64_t Write(const void *buf, uint64_t size, void *txn)
Definition: cache_ram.cc:239
static void size_t size
Definition: smalloc.h:47
virtual bool AcquireQuotaManager(QuotaManager *quota_mgr)
Definition: cache_ram.cc:70
static const uint64_t kSizeUnknown
Definition: cache.h:72