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