GCC Code Coverage Report
Directory: cvmfs/ Exec Total Coverage
File: cvmfs/cache_tiered.cc Lines: 84 127 66.1 %
Date: 2019-02-03 02:48:13 Branches: 61 100 61.0 %

Line Branch Exec Source
1
/**
2
 * This file is part of the CernVM File System.
3
 */
4
#include "cvmfs_config.h"
5
#include "cache_tiered.h"
6
7
#include <errno.h>
8
9
#include <string>
10
#include <vector>
11
12
#include "platform.h"
13
#include "quota.h"
14
#include "util/posix.h"
15
16
17
std::string TieredCacheManager::Describe() {
18
  return "Tiered Cache\n"
19
    "  - upper layer: " + upper_->Describe() +
20
    "  - lower layer: " + lower_->Describe();
21
}
22
23
24
bool TieredCacheManager::DoFreeState(void *data) {
25
  SavedState *state = reinterpret_cast<SavedState *>(data);
26
  upper_->FreeState(-1, state->state_upper);
27
  lower_->FreeState(-1, state->state_lower);
28
  delete state;
29
  return true;
30
}
31
32
33
bool TieredCacheManager::DoRestoreState(void *data) {
34
  SavedState *state = reinterpret_cast<SavedState *>(data);
35
  upper_->RestoreState(-1, state->state_upper);
36
  lower_->RestoreState(-1, state->state_lower);
37
  return true;
38
}
39
40
41
void *TieredCacheManager::DoSaveState() {
42
  SavedState *state = new SavedState();
43
  state->state_upper = upper_->SaveState(-1);
44
  state->state_lower = lower_->SaveState(-1);
45
  return state;
46
}
47
48
49
6
int TieredCacheManager::Open(const BlessedObject &object) {
50
6
  int fd = upper_->Open(object);
51

6
  if ((fd >= 0) || (fd != -ENOENT)) {return fd;}
52
53
5
  int fd2 = lower_->Open(object);
54
5
  if (fd2 < 0) {return fd;}  // NOTE: use error code from upper.
55
56
  // Lower cache hit; upper cache miss.  Copy object into the upper cache.
57
1
  int64_t size = lower_->GetSize(fd2);
58
1
  if (size < 0) {
59
    lower_->Close(fd2);
60
    return fd;
61
  }
62
63
1
  void *txn = alloca(upper_->SizeOfTxn());
64
1
  if (upper_->StartTxn(object.id, size, txn) < 0) {
65
    lower_->Close(fd2);
66
    return fd;
67
  }
68
1
  upper_->CtrlTxn(object.info, 0, txn);
69
70
1
  std::vector<char> m_buffer;
71
1
  m_buffer.resize(kCopyBufferSize);
72
1
  uint64_t remaining = size;
73
1
  uint64_t offset = 0;
74
3
  while (remaining > 0) {
75
1
    unsigned nbytes = remaining > kCopyBufferSize ? kCopyBufferSize : remaining;
76
1
    int64_t result = lower_->Pread(fd2, &m_buffer[0], nbytes, offset);
77
    // The file we are reading is supposed to be exactly `size` bytes.
78

1
    if ((result < 0) || (result != nbytes)) {
79
      lower_->Close(fd2);
80
      upper_->AbortTxn(txn);
81
      return fd;
82
    }
83
1
    result = upper_->Write(&m_buffer[0], nbytes, txn);
84
1
    if (result < 0) {
85
      lower_->Close(fd2);
86
      upper_->AbortTxn(txn);
87
      return fd;
88
    }
89
1
    offset += nbytes;
90
1
    remaining -= nbytes;
91
  }
92
1
  lower_->Close(fd2);
93
1
  int fd_return = upper_->OpenFromTxn(txn);
94
1
  if (fd_return < 0) {
95
    upper_->AbortTxn(txn);
96
    return fd;
97
  }
98
1
  if (upper_->CommitTxn(txn) < 0) {
99
    upper_->Close(fd_return);
100
    return fd;
101
  }
102
1
  return fd_return;
103
}
104
105
106
3
int TieredCacheManager::StartTxn(const shash::Any &id, uint64_t size, void *txn)
107
{
108
3
  int upper_result = upper_->StartTxn(id, size, txn);
109

3
  if (lower_readonly_ || (upper_result < 0)) {
110
2
    return upper_result;
111
  }
112
113
1
  void *txn2 = static_cast<char *>(txn) + upper_->SizeOfTxn();
114
1
  int lower_result = lower_->StartTxn(id, size, txn2);
115
1
  if (lower_result < 0) {
116
    upper_->AbortTxn(txn);
117
  }
118
1
  return lower_result;
119
}
120
121
122
26
CacheManager *TieredCacheManager::Create(
123
  CacheManager *upper_cache,
124
  CacheManager *lower_cache)
125
{
126
  TieredCacheManager *cache_mgr =
127
26
    new TieredCacheManager(upper_cache, lower_cache);
128
26
  delete cache_mgr->quota_mgr_;
129
26
  cache_mgr->quota_mgr_ = upper_cache->quota_mgr();
130
131
  // The backing directory for the tiered cache manager is tricky.  If there is
132
  // only one backing directory set, take it.  If both layers have backing
133
  // directories, prefer the upper layer unless the lower layer provides a
134
  // .cvmfschecksum... file
135



46
  if (upper_cache->GetBackingDirectory().empty() &&
136
20
      !lower_cache->GetBackingDirectory().empty())
137
  {
138
8
    cache_mgr->backing_directory_ = lower_cache->GetBackingDirectory();
139



24
  } else if (!upper_cache->GetBackingDirectory().empty() &&
140
6
             lower_cache->GetBackingDirectory().empty())
141
  {
142
    cache_mgr->backing_directory_ = upper_cache->GetBackingDirectory();
143



24
  } else if (!upper_cache->GetBackingDirectory().empty() &&
144
6
             !lower_cache->GetBackingDirectory().empty())
145
  {
146
6
    if (!FindFilesByPrefix(upper_cache->GetBackingDirectory(),
147
                           "cvmfschecksum.").empty())
148
    {
149
      cache_mgr->backing_directory_ = upper_cache->GetBackingDirectory();
150
6
    } else if (!FindFilesByPrefix(lower_cache->GetBackingDirectory(),
151
                                  "cvmfschecksum.").empty())
152
    {
153
3
      cache_mgr->backing_directory_ = lower_cache->GetBackingDirectory();
154
    } else {
155
3
      cache_mgr->backing_directory_ = upper_cache->GetBackingDirectory();
156
    }
157
  }
158
159
26
  return cache_mgr;
160
}
161
162
163
2
void TieredCacheManager::CtrlTxn(
164
  const ObjectInfo &object_info,
165
  const int flags,
166
  void *txn)
167
{
168
2
  upper_->CtrlTxn(object_info, flags, txn);
169
2
  if (!lower_readonly_) {
170
1
    void *txn2 = static_cast<char*>(txn) + upper_->SizeOfTxn();
171
1
    lower_->CtrlTxn(object_info, flags, txn2);
172
  }
173
2
}
174
175
176
2
int64_t TieredCacheManager::Write(const void *buf, uint64_t size, void *txn) {
177
2
  int upper_result = upper_->Write(buf, size, txn);
178

2
  if (lower_readonly_ || (upper_result < 0)) { return upper_result; }
179
180
1
  void *txn2 = static_cast<char*>(txn) + upper_->SizeOfTxn();
181
1
  return lower_->Write(buf, size, txn2);
182
}
183
184
185
1
int TieredCacheManager::Reset(void *txn) {
186
1
  int upper_result = upper_->Reset(txn);
187
188
1
  int lower_result = upper_result;
189
1
  if (!lower_readonly_) {
190
    void *txn2 = static_cast<char*>(txn) + upper_->SizeOfTxn();
191
    lower_result = lower_->Reset(txn2);
192
  }
193
194
1
  return (upper_result < 0) ? upper_result : lower_result;
195
}
196
197
198
1
int TieredCacheManager::AbortTxn(void *txn) {
199
1
  int upper_result = upper_->AbortTxn(txn);
200
201
1
  int lower_result = upper_result;
202
1
  if (!lower_readonly_) {
203
    void *txn2 = static_cast<char*>(txn) + upper_->SizeOfTxn();
204
    lower_result = lower_->AbortTxn(txn2);
205
  }
206
207
1
  return (upper_result < 0) ? upper_result : lower_result;
208
}
209
210
211
2
int TieredCacheManager::CommitTxn(void *txn) {
212
2
  int upper_result = upper_->CommitTxn(txn);
213
214
2
  int lower_result = upper_result;
215
2
  if (!lower_readonly_) {
216
1
    void *txn2 = static_cast<char*>(txn) + upper_->SizeOfTxn();
217
1
    lower_result = lower_->CommitTxn(txn2);
218
  }
219
220
2
  return (upper_result < 0) ? upper_result : lower_result;
221
}
222
223
224
void TieredCacheManager::Spawn() {
225
  upper_->Spawn();
226
  lower_->Spawn();
227
}
228
229
230
52
TieredCacheManager::~TieredCacheManager() {
231
26
  quota_mgr_ = NULL;  // gets deleted by upper
232
26
  delete upper_;
233
26
  delete lower_;
234
26
}