CernVM-FS  2.12.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 "util/concurrency.h"
15 #include "util/logging.h"
16 #include "util/posix.h"
17 #include "util/string.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 %lu B, %u entries",
51  max_size, max_entries);
53  "DEPRECATION WARNING: The RAM cache manager is depcreated and "
54  "will be removed from future releases.");
55 }
56 
57 
59  pthread_rwlock_destroy(&rwlock_);
60 }
61 
62 
64  int result = fd_table_.OpenFd(handle);
65  if (result == -ENFILE) {
66  LogCvmfs(kLogCache, kLogDebug, "too many open files");
68  }
69  return result;
70 }
71 
72 
74  assert(quota_mgr != NULL);
76  LogCvmfs(kLogCache, kLogDebug, "set quota manager");
77  return true;
78 }
79 
80 
82  WriteLockGuard guard(rwlock_);
83  return DoOpen(object.id);
84 }
85 
86 
88  bool ok;
89  bool is_volatile;
90  MemoryBuffer buf;
91 
92  if (regular_entries_.Contains(id)) {
93  is_volatile = false;
94  } else if (volatile_entries_.Contains(id)) {
95  is_volatile = true;
96  } else {
97  LogCvmfs(kLogCache, kLogDebug, "miss for %s",
98  id.ToString().c_str());
100  return -ENOENT;
101  }
102  ReadOnlyHandle generic_handle(id, is_volatile);
103  int fd = AddFd(generic_handle);
104  if (fd < 0) {
105  LogCvmfs(kLogCache, kLogDebug, "error while opening %s: %s",
106  id.ToString().c_str(), strerror(-fd));
107  return fd;
108  }
109  if (is_volatile) {
110  LogCvmfs(kLogCache, kLogDebug, "hit in volatile entries for %s",
111  id.ToString().c_str());
113  } else {
114  LogCvmfs(kLogCache, kLogDebug, "hit in regular entries for %s",
115  id.ToString().c_str());
117  }
118  ok = GetStore(generic_handle)->IncRef(id);
119  assert(ok);
120  return fd;
121 }
122 
123 
124 int64_t RamCacheManager::GetSize(int fd) {
125  ReadLockGuard guard(rwlock_);
126  ReadOnlyHandle generic_handle = fd_table_.GetHandle(fd);
127  if (generic_handle.handle == kInvalidHandle) {
128  LogCvmfs(kLogCache, kLogDebug, "bad fd %d on GetSize", fd);
129  return -EBADF;
130  }
132  return GetStore(generic_handle)->GetSize(generic_handle.handle);
133 }
134 
135 
137  bool rc;
138 
139  WriteLockGuard guard(rwlock_);
140  ReadOnlyHandle generic_handle = fd_table_.GetHandle(fd);
141  if (generic_handle.handle == kInvalidHandle) {
142  LogCvmfs(kLogCache, kLogDebug, "bad fd %d on Close", fd);
143  return -EBADF;
144  }
145  rc = GetStore(generic_handle)->Unref(generic_handle.handle);
146  assert(rc);
147 
148  int rc_int = fd_table_.CloseFd(fd);
149  assert(rc_int == 0);
150  LogCvmfs(kLogCache, kLogDebug, "closed fd %d", fd);
152  return 0;
153 }
154 
155 
157  int fd,
158  void *buf,
159  uint64_t size,
160  uint64_t offset)
161 {
162  ReadLockGuard guard(rwlock_);
163  ReadOnlyHandle generic_handle = fd_table_.GetHandle(fd);
164  if (generic_handle.handle == kInvalidHandle) {
165  LogCvmfs(kLogCache, kLogDebug, "bad fd %d on Pread", fd);
166  return -EBADF;
167  }
169  return GetStore(generic_handle)->Read(
170  generic_handle.handle, buf, size, offset);
171 }
172 
173 
174 int RamCacheManager::Dup(int fd) {
175  bool ok;
176  int rc;
177  WriteLockGuard guard(rwlock_);
178  ReadOnlyHandle generic_handle = fd_table_.GetHandle(fd);
179  if (generic_handle.handle == kInvalidHandle) {
180  LogCvmfs(kLogCache, kLogDebug, "bad fd %d on Dup", fd);
181  return -EBADF;
182  }
183  rc = AddFd(generic_handle);
184  if (rc < 0) return rc;
185  ok = GetStore(generic_handle)->IncRef(generic_handle.handle);
186  assert(ok);
187  LogCvmfs(kLogCache, kLogDebug, "dup fd %d", fd);
189  return rc;
190 }
191 
192 
197  ReadLockGuard guard(rwlock_);
198  ReadOnlyHandle generic_handle = fd_table_.GetHandle(fd);
199  if (generic_handle.handle == kInvalidHandle) {
200  LogCvmfs(kLogCache, kLogDebug, "bad fd %d on Readahead", fd);
201  return -EBADF;
202  }
203  LogCvmfs(kLogCache, kLogDebug, "readahead (no-op) on %d", fd);
205  return 0;
206 }
207 
208 
209 int RamCacheManager::StartTxn(const shash::Any &id, uint64_t size, void *txn) {
210  LogCvmfs(kLogCache, kLogDebug, "new transaction with id %s",
211  id.ToString().c_str());
212  Transaction *transaction = new (txn) Transaction();
213  transaction->buffer.id = id;
214  transaction->pos = 0;
215  transaction->expected_size = size;
216  transaction->buffer.size = (size == kSizeUnknown) ? kPageSize : size;
217  transaction->buffer.address = malloc(transaction->buffer.size);
218  if (!transaction->buffer.address && size > 0) {
220  "failed to allocate %lu B for %s",
221  size, id.ToString().c_str());
222  return -errno;
223  }
225  return 0;
226 }
227 
228 
229 void RamCacheManager::CtrlTxn(const Label &label, const int /* flags */,
230  void *txn)
231 {
232  Transaction *transaction = reinterpret_cast<Transaction *>(txn);
233  transaction->description = label.GetDescription();
234  transaction->buffer.object_flags = label.flags;
235  LogCvmfs(kLogCache, kLogDebug, "modified transaction %s",
236  transaction->buffer.id.ToString().c_str());
237 }
238 
239 
240 int64_t RamCacheManager::Write(const void *buf, uint64_t size, void *txn) {
241  Transaction *transaction = reinterpret_cast<Transaction *>(txn);
242 
243  assert(transaction->pos <= transaction->buffer.size);
244  if (transaction->pos + size > transaction->buffer.size) {
245  if (transaction->expected_size == kSizeUnknown) {
247  size_t new_size = max(2*transaction->buffer.size,
248  static_cast<size_t>(size + transaction->pos));
249  LogCvmfs(kLogCache, kLogDebug, "reallocate transaction for %s to %lu B",
250  transaction->buffer.id.ToString().c_str(),
251  transaction->buffer.size);
252  void *new_ptr = realloc(transaction->buffer.address, new_size);
253  if (!new_ptr) {
255  "failed to allocate %lu B for %s",
256  new_size, transaction->buffer.id.ToString().c_str());
257  return -EIO;
258  }
259  transaction->buffer.address = new_ptr;
260  transaction->buffer.size = new_size;
261  } else {
263  "attempted to write more than requested (%lu>%zu)",
264  size, transaction->buffer.size);
265  return -EFBIG;
266  }
267  }
268 
269  if (transaction->buffer.address && buf) {
270  // LogCvmfs(kLogCache, kLogDebug, "copy %u bytes of transaction %s",
271  // size, transaction->id.ToString().c_str());
272  memcpy(static_cast<char *>(transaction->buffer.address) + transaction->pos,
273  buf, size);
274  }
275  transaction->pos += size;
277  return size;
278 }
279 
280 
281 int RamCacheManager::Reset(void *txn) {
282  Transaction *transaction = reinterpret_cast<Transaction *>(txn);
283  transaction->pos = 0;
284  LogCvmfs(kLogCache, kLogDebug, "reset transaction %s",
285  transaction->buffer.id.ToString().c_str());
287  return 0;
288 }
289 
290 
292  WriteLockGuard guard(rwlock_);
293  Transaction *transaction = reinterpret_cast<Transaction *>(txn);
294  int64_t retval = CommitToKvStore(transaction);
295  if (retval < 0) {
297  "error while committing transaction on %s: %s",
298  transaction->buffer.id.ToString().c_str(), strerror(-retval));
299  return retval;
300  }
301  LogCvmfs(kLogCache, kLogDebug, "open pending transaction for %s",
302  transaction->buffer.id.ToString().c_str());
304  return DoOpen(transaction->buffer.id);
305 }
306 
307 
309  Transaction *transaction = reinterpret_cast<Transaction *>(txn);
310  free(transaction->buffer.address);
311  LogCvmfs(kLogCache, kLogDebug, "abort transaction %s",
312  transaction->buffer.id.ToString().c_str());
314  return 0;
315 }
316 
317 
319  WriteLockGuard guard(rwlock_);
320  Transaction *transaction = reinterpret_cast<Transaction *>(txn);
322  int64_t rc = CommitToKvStore(transaction);
323  if (rc < 0) return rc;
324  free(transaction->buffer.address);
325  return rc;
326 }
327 
328 
330  MemoryKvStore *store;
331 
333  {
334  store = &volatile_entries_;
335  } else {
336  store = &regular_entries_;
337  }
338  if ((transaction->buffer.object_flags & CacheManager::kLabelPinned) ||
340  {
341  transaction->buffer.refcount = 1;
342  } else {
343  transaction->buffer.refcount = 0;
344  }
345 
346  int64_t regular_size = regular_entries_.GetUsed();
347  int64_t volatile_size = volatile_entries_.GetUsed();
348  int64_t overrun = regular_size + volatile_size +
349  transaction->buffer.size - max_size_;
350 
351  if (overrun > 0) {
352  // if we're going to clean the cache, try to remove at least 25%
353  overrun = max(overrun, (int64_t) max_size_>>2);
355  volatile_entries_.ShrinkTo(max((int64_t) 0, volatile_size - overrun));
356  }
357  overrun -= volatile_size - volatile_entries_.GetUsed();
358  if (overrun > 0) {
359  regular_entries_.ShrinkTo(max((int64_t) 0, regular_size - overrun));
360  }
361  overrun -= regular_size -regular_entries_.GetUsed();
362  if (overrun > 0) {
364  "transaction for %s would overrun the cache limit by %ld",
365  transaction->buffer.id.ToString().c_str(), overrun);
367  return -ENOSPC;
368  }
369 
370  int rc = store->Commit(transaction->buffer);
371  if (rc < 0) {
373  "commit on %s failed",
374  transaction->buffer.id.ToString().c_str());
375  return rc;
376  }
377  LogCvmfs(kLogCache, kLogDebug, "committed %s to cache",
378  transaction->buffer.id.ToString().c_str());
379  return 0;
380 }
perf::Counter * n_aborttxn
Definition: cache_ram.h:55
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:291
std::string GetDescription() const
Definition: cache.h:110
virtual int Open(const LabeledObject &object)
Definition: cache_ram.cc:81
perf::Counter * n_pread
Definition: cache_ram.h:49
static const shash::Any kInvalidHandle
Definition: cache_ram.h:243
static const int kLabelCatalog
Definition: cache.h:80
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:249
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:136
perf::Counter * n_committxn
Definition: cache_ram.h:56
virtual int CommitTxn(void *txn)
Definition: cache_ram.cc:318
assert((mem||(size==0))&&"Out Of Memory")
MemoryKvStore * GetStore(const ReadOnlyHandle &fd)
Definition: cache_ram.h:276
unsigned int refcount
Definition: kvstore.h:49
virtual int AbortTxn(void *txn)
Definition: cache_ram.cc:308
perf::Counter * n_starttxn
Definition: cache_ram.h:52
virtual int Dup(int fd)
Definition: cache_ram.cc:174
virtual void CtrlTxn(const Label &label, const int flags, void *txn)
Definition: cache_ram.cc:229
virtual int StartTxn(const shash::Any &id, uint64_t size, void *txn)
Definition: cache_ram.cc:209
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:156
virtual int Readahead(int fd)
Definition: cache_ram.cc:196
FdTable< ReadOnlyHandle > fd_table_
Definition: cache_ram.h:297
perf::Counter * n_readahead
Definition: cache_ram.h:51
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:63
int64_t CommitToKvStore(Transaction *transaction)
Definition: cache_ram.cc:329
perf::Counter * n_openregular
Definition: cache_ram.h:58
bool Unref(const shash::Any &id)
Definition: kvstore.cc:217
static const int kLabelPinned
Definition: cache.h:81
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:87
int object_flags
Definition: kvstore.h:50
perf::Counter * n_close
Definition: cache_ram.h:48
perf::Counter * n_enfile
Definition: cache_ram.h:57
static const int kLabelVolatile
Definition: cache.h:82
perf::Counter * n_openvolatile
Definition: cache_ram.h:59
virtual std::string Describe()
Definition: cache_ram.cc:23
int64_t GetSize(const shash::Any &id)
Definition: kvstore.cc:166
Counters counters_
Definition: cache_ram.h:301
QuotaManager * quota_mgr()
Definition: cache.h:193
uint64_t max_size_
Definition: cache_ram.h:296
void * address
Definition: kvstore.h:47
size_t size
Definition: kvstore.h:48
const unsigned kPageSize
Definition: posix.h:30
pthread_rwlock_t rwlock_
Definition: cache_ram.h:298
QuotaManager * quota_mgr_
Definition: cache.h:235
Definition: mutex.h:42
virtual int64_t GetSize(int fd)
Definition: cache_ram.cc:124
virtual int Reset(void *txn)
Definition: cache_ram.cc:281
virtual ~RamCacheManager()
Definition: cache_ram.cc:58
MemoryKvStore regular_entries_
Definition: cache_ram.h:299
MemoryKvStore volatile_entries_
Definition: cache_ram.h:300
virtual int64_t Write(const void *buf, uint64_t size, void *txn)
Definition: cache_ram.cc:240
static void size_t size
Definition: smalloc.h:54
virtual bool AcquireQuotaManager(QuotaManager *quota_mgr)
Definition: cache_ram.cc:73
static const uint64_t kSizeUnknown
Definition: cache.h:74
CVMFS_EXPORT void LogCvmfs(const LogSource source, const int mask, const char *format,...)
Definition: logging.cc:528