GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
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 |
} |
Generated by: GCOVR (Version 4.1) |