Directory: | cvmfs/ |
---|---|
File: | cvmfs/util/file_backed_buffer.cc |
Date: | 2025-06-22 02:36:02 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 102 | 111 | 91.9% |
Branches: | 52 | 78 | 66.7% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | /** | ||
2 | * This file is part of the CernVM File System. | ||
3 | */ | ||
4 | |||
5 | #include "file_backed_buffer.h" | ||
6 | |||
7 | #include <cassert> | ||
8 | #include <cstdio> | ||
9 | #include <cstring> | ||
10 | |||
11 | #include "util/exception.h" | ||
12 | #include "util/logging.h" | ||
13 | #include "util/posix.h" | ||
14 | #include "util/smalloc.h" | ||
15 | |||
16 | 8675 | FileBackedBuffer *FileBackedBuffer::Create(uint64_t in_memory_threshold, | |
17 | const std::string &tmp_dir) { | ||
18 |
1/2✓ Branch 2 taken 8675 times.
✗ Branch 3 not taken.
|
8675 | return new FileBackedBuffer(in_memory_threshold, tmp_dir); |
19 | } | ||
20 | |||
21 | 8675 | FileBackedBuffer::FileBackedBuffer(uint64_t in_memory_threshold, | |
22 | 8675 | const std::string &tmp_dir) | |
23 | 8675 | : in_memory_threshold_(in_memory_threshold) | |
24 | 8675 | , tmp_dir_(tmp_dir) | |
25 | 8675 | , state_(kWriteState) | |
26 | 8675 | , mode_(kMemoryMode) | |
27 | 8675 | , size_(0) | |
28 | 8675 | , buf_(NULL) | |
29 | 8675 | , pos_(0) | |
30 | 8675 | , fp_(NULL) | |
31 |
1/2✓ Branch 2 taken 8675 times.
✗ Branch 3 not taken.
|
8675 | , file_path_("") |
32 | 17350 | , mmapped_(NULL) { } | |
33 | |||
34 | 17350 | FileBackedBuffer::~FileBackedBuffer() { | |
35 | 8675 | free(buf_); | |
36 |
2/2✓ Branch 0 taken 5123 times.
✓ Branch 1 taken 3552 times.
|
8675 | if (mode_ != kFileMode) |
37 | 5123 | return; | |
38 | |||
39 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3552 times.
|
3552 | if (state_ == kWriteState) { |
40 | ✗ | const int retval = fclose(fp_); | |
41 | ✗ | if (retval != 0) | |
42 | ✗ | PANIC(kLogStderr, "could not close temporary file %s: error %d", | |
43 | file_path_.c_str(), retval); | ||
44 | } else { | ||
45 | 3552 | mmapped_->Unmap(); | |
46 |
1/2✓ Branch 0 taken 3552 times.
✗ Branch 1 not taken.
|
3552 | delete mmapped_; |
47 | } | ||
48 | 3552 | const int retval = unlink(file_path_.c_str()); | |
49 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3552 times.
|
3552 | if (retval != 0) |
50 | ✗ | PANIC(kLogStderr, "could not delete temporary file %s: error %d", | |
51 | file_path_.c_str(), retval); | ||
52 |
4/4✓ Branch 1 taken 3552 times.
✓ Branch 2 taken 5123 times.
✓ Branch 4 taken 3552 times.
✓ Branch 5 taken 5123 times.
|
13798 | } |
53 | |||
54 | 2794913 | void FileBackedBuffer::Append(const void *source, uint64_t len) { | |
55 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2794913 times.
|
2794913 | assert(source != NULL); |
56 | |||
57 | // Cannot write after Commit() | ||
58 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2794913 times.
|
2794913 | assert(state_ == kWriteState); |
59 | |||
60 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2794908 times.
|
2794913 | if (len == 0) |
61 | 5 | return; | |
62 | |||
63 | // check the size and eventually save to file | ||
64 |
4/4✓ Branch 0 taken 331178 times.
✓ Branch 1 taken 2463730 times.
✓ Branch 2 taken 3552 times.
✓ Branch 3 taken 327626 times.
|
2794908 | if (mode_ == kMemoryMode && pos_ + len > in_memory_threshold_) { |
65 | // changes mode_ to kFileMode | ||
66 | 3552 | SaveToFile(); | |
67 | } | ||
68 | |||
69 |
2/2✓ Branch 0 taken 327626 times.
✓ Branch 1 taken 2467282 times.
|
2794908 | if (mode_ == kMemoryMode) { |
70 |
2/2✓ Branch 0 taken 5895 times.
✓ Branch 1 taken 321731 times.
|
327626 | if (buf_ == NULL) { |
71 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5895 times.
|
5895 | assert(size_ == 0); |
72 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5895 times.
|
5895 | assert(pos_ == 0); |
73 | 5895 | buf_ = reinterpret_cast<unsigned char *>(smalloc(len)); | |
74 | 5895 | size_ = len; | |
75 |
2/2✓ Branch 0 taken 27166 times.
✓ Branch 1 taken 294565 times.
|
321731 | } else if (size_ < pos_ + len) { |
76 | 27166 | const uint64_t newsize = | |
77 | 27166 | (size_ * 2 < pos_ + len) ? (pos_ + len) : (size_ * 2); | |
78 | 27166 | buf_ = reinterpret_cast<unsigned char *>(srealloc(buf_, newsize)); | |
79 | 27166 | size_ = newsize; | |
80 | } | ||
81 | |||
82 | 327626 | memcpy(buf_ + pos_, source, len); | |
83 | 327626 | pos_ += len; | |
84 | } else { | ||
85 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2467282 times.
|
2467282 | assert(fp_ != NULL); |
86 | 2467282 | const uint64_t bytes_written = fwrite(source, 1, len, fp_); | |
87 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2467296 times.
|
2467296 | if (bytes_written != len) { |
88 | ✗ | PANIC(kLogStderr, | |
89 | "could not append to temporary file %s: length %lu, " | ||
90 | "actually written %lu, error %d", | ||
91 | file_path_.c_str(), len, bytes_written, ferror(fp_)); | ||
92 | } | ||
93 | 2467296 | pos_ += len; | |
94 | 2467296 | size_ += len; | |
95 | } | ||
96 | } | ||
97 | |||
98 | 8542 | void FileBackedBuffer::Commit() { | |
99 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8542 times.
|
8542 | assert(state_ == kWriteState); |
100 | |||
101 |
2/2✓ Branch 0 taken 3552 times.
✓ Branch 1 taken 4990 times.
|
8542 | if (mode_ == kFileMode) { |
102 | 3552 | const int retval = fclose(fp_); | |
103 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3552 times.
|
3552 | if (retval != 0) |
104 | ✗ | PANIC(kLogStderr, "could not close file after writing finished: %s", | |
105 | file_path_.c_str()); | ||
106 | 3552 | fp_ = NULL; | |
107 | |||
108 |
1/2✓ Branch 2 taken 3552 times.
✗ Branch 3 not taken.
|
3552 | mmapped_ = new MemoryMappedFile(file_path_); |
109 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3552 times.
|
3552 | if (!mmapped_->Map()) |
110 | ✗ | PANIC(kLogStderr, "could not memory-map file %s", file_path_.c_str()); | |
111 | } else { | ||
112 | // Trim memory chunk size to actual data size | ||
113 | 4990 | buf_ = reinterpret_cast<unsigned char *>(srealloc(buf_, pos_)); | |
114 | 4990 | size_ = pos_; | |
115 | } | ||
116 | |||
117 | 8542 | pos_ = 0; | |
118 | 8542 | state_ = kReadState; | |
119 | 8542 | } | |
120 | |||
121 | 227938 | int64_t FileBackedBuffer::Data(void **ptr, int64_t len, uint64_t pos) { | |
122 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 227938 times.
|
227938 | assert(state_ == kReadState); |
123 | |||
124 | 227938 | const int64_t actual_len = | |
125 | 227938 | (pos + len <= size_) | |
126 |
2/2✓ Branch 0 taken 3863 times.
✓ Branch 1 taken 224075 times.
|
227938 | ? len |
127 | 3863 | : static_cast<int64_t>(size_) - static_cast<int64_t>(pos); | |
128 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 227938 times.
|
227938 | assert(actual_len >= 0); |
129 | |||
130 |
2/2✓ Branch 0 taken 8328 times.
✓ Branch 1 taken 219610 times.
|
227938 | if (mode_ == kMemoryMode) { |
131 | 8328 | *ptr = buf_ + pos; | |
132 | } else { | ||
133 | 219610 | *ptr = mmapped_->buffer() + pos; | |
134 | } | ||
135 | 227938 | return actual_len; | |
136 | } | ||
137 | |||
138 | 219401 | int64_t FileBackedBuffer::Read(void *ptr, int64_t len) { | |
139 | 219401 | const int64_t bytes_read = ReadP(ptr, len, pos_); | |
140 | 219401 | pos_ += bytes_read; | |
141 | 219401 | return bytes_read; | |
142 | } | ||
143 | |||
144 | 219401 | int64_t FileBackedBuffer::ReadP(void *ptr, int64_t len, uint64_t pos) { | |
145 | void *source; | ||
146 |
1/2✓ Branch 1 taken 219401 times.
✗ Branch 2 not taken.
|
219401 | const int64_t bytes_read = Data(&source, len, pos); |
147 | 219401 | memcpy(ptr, source, bytes_read); | |
148 | 219401 | return bytes_read; | |
149 | } | ||
150 | |||
151 | 8512 | void FileBackedBuffer::Rewind() { | |
152 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8512 times.
|
8512 | assert(state_ == kReadState); |
153 | 8512 | pos_ = 0; | |
154 | 8512 | } | |
155 | |||
156 | 44088 | uint64_t FileBackedBuffer::GetSize() const { | |
157 |
4/4✓ Branch 0 taken 99 times.
✓ Branch 1 taken 43989 times.
✓ Branch 2 taken 94 times.
✓ Branch 3 taken 5 times.
|
44088 | if (state_ == kWriteState && mode_ == kMemoryMode) |
158 | 94 | return pos_; | |
159 | 43994 | return size_; | |
160 | } | ||
161 | |||
162 | |||
163 | 3552 | void FileBackedBuffer::SaveToFile() { | |
164 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3552 times.
|
3552 | assert(state_ == kWriteState); |
165 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3552 times.
|
3552 | assert(mode_ == kMemoryMode); |
166 | |||
167 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3552 times.
|
3552 | assert(fp_ == NULL); |
168 | 3552 | fp_ = CreateTempFile(tmp_dir_, 0644, "w", &file_path_); | |
169 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3552 times.
|
3552 | if (fp_ == NULL) |
170 | ✗ | PANIC(kLogStderr, "could not create temporary file"); | |
171 | |||
172 | 3552 | const uint64_t bytes_written = fwrite(buf_, 1, pos_, fp_); | |
173 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3552 times.
|
3552 | if (bytes_written != pos_) { |
174 | ✗ | PANIC(kLogStderr, | |
175 | "could not write to temporary file %s: length %lu, " | ||
176 | "actually written %lu, error %d", | ||
177 | file_path_.c_str(), pos_, bytes_written, ferror(fp_)); | ||
178 | } | ||
179 | |||
180 | 3552 | free(buf_); | |
181 | 3552 | buf_ = NULL; | |
182 | 3552 | size_ = pos_; | |
183 | 3552 | mode_ = kFileMode; | |
184 | 3552 | } | |
185 |