Directory: | cvmfs/ |
---|---|
File: | cvmfs/util/file_backed_buffer.cc |
Date: | 2025-08-31 02:39:21 |
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 | 2474 | FileBackedBuffer *FileBackedBuffer::Create(uint64_t in_memory_threshold, | |
21 | const std::string &tmp_dir) { | ||
22 |
1/2✓ Branch 2 taken 2474 times.
✗ Branch 3 not taken.
|
2474 | return new FileBackedBuffer(in_memory_threshold, tmp_dir); |
23 | } | ||
24 | |||
25 | 2474 | FileBackedBuffer::FileBackedBuffer(uint64_t in_memory_threshold, | |
26 | 2474 | const std::string &tmp_dir) | |
27 | 2474 | : in_memory_threshold_(in_memory_threshold) | |
28 | 2474 | , tmp_dir_(tmp_dir) | |
29 | 2474 | , state_(kWriteState) | |
30 | 2474 | , mode_(kMemoryMode) | |
31 | 2474 | , size_(0) | |
32 | 2474 | , buf_(NULL) | |
33 | 2474 | , pos_(0) | |
34 | 2474 | , fp_(NULL) | |
35 |
1/2✓ Branch 2 taken 2474 times.
✗ Branch 3 not taken.
|
2474 | , file_path_("") |
36 | 4948 | , mmapped_(NULL) { } | |
37 | |||
38 | 4948 | FileBackedBuffer::~FileBackedBuffer() { | |
39 | 2474 | free(buf_); | |
40 |
2/2✓ Branch 0 taken 1460 times.
✓ Branch 1 taken 1014 times.
|
2474 | if (mode_ != kFileMode) |
41 | 1460 | return; | |
42 | |||
43 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1014 times.
|
1014 | 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 | 1014 | mmapped_->Unmap(); | |
50 |
1/2✓ Branch 0 taken 1014 times.
✗ Branch 1 not taken.
|
1014 | delete mmapped_; |
51 | } | ||
52 | 1014 | const int retval = unlink(file_path_.c_str()); | |
53 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1014 times.
|
1014 | 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 1014 times.
✓ Branch 2 taken 1460 times.
✓ Branch 4 taken 1014 times.
✓ Branch 5 taken 1460 times.
|
3934 | } |
57 | |||
58 | 798545 | void FileBackedBuffer::Append(const void *source, uint64_t len) { | |
59 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 798545 times.
|
798545 | assert(source != NULL); |
60 | |||
61 | // Cannot write after Commit() | ||
62 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 798545 times.
|
798545 | assert(state_ == kWriteState); |
63 | |||
64 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 798544 times.
|
798545 | if (len == 0) |
65 | 1 | return; | |
66 | |||
67 | // check the size and eventually save to file | ||
68 |
4/4✓ Branch 0 taken 94618 times.
✓ Branch 1 taken 703926 times.
✓ Branch 2 taken 1014 times.
✓ Branch 3 taken 93604 times.
|
798544 | if (mode_ == kMemoryMode && pos_ + len > in_memory_threshold_) { |
69 | // changes mode_ to kFileMode | ||
70 | 1014 | SaveToFile(); | |
71 | } | ||
72 | |||
73 |
2/2✓ Branch 0 taken 93604 times.
✓ Branch 1 taken 704940 times.
|
798544 | if (mode_ == kMemoryMode) { |
74 |
2/2✓ Branch 0 taken 1683 times.
✓ Branch 1 taken 91921 times.
|
93604 | if (buf_ == NULL) { |
75 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1683 times.
|
1683 | assert(size_ == 0); |
76 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1683 times.
|
1683 | assert(pos_ == 0); |
77 | 1683 | buf_ = reinterpret_cast<unsigned char *>(smalloc(len)); | |
78 | 1683 | size_ = len; | |
79 |
2/2✓ Branch 0 taken 7760 times.
✓ Branch 1 taken 84161 times.
|
91921 | } else if (size_ < pos_ + len) { |
80 | 7760 | const uint64_t newsize = (size_ * 2 < pos_ + len) ? (pos_ + len) | |
81 | : (size_ * 2); | ||
82 | 7760 | buf_ = reinterpret_cast<unsigned char *>(srealloc(buf_, newsize)); | |
83 | 7760 | size_ = newsize; | |
84 | } | ||
85 | |||
86 | 93604 | memcpy(buf_ + pos_, source, len); | |
87 | 93604 | pos_ += len; | |
88 | } else { | ||
89 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 704940 times.
|
704940 | assert(fp_ != NULL); |
90 | 704940 | const uint64_t bytes_written = fwrite(source, 1, len, fp_); | |
91 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 704940 times.
|
704940 | 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 | 704940 | pos_ += len; | |
98 | 704940 | size_ += len; | |
99 | } | ||
100 | } | ||
101 | |||
102 | 2438 | void FileBackedBuffer::Commit() { | |
103 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2438 times.
|
2438 | assert(state_ == kWriteState); |
104 | |||
105 |
2/2✓ Branch 0 taken 1014 times.
✓ Branch 1 taken 1424 times.
|
2438 | if (mode_ == kFileMode) { |
106 | 1014 | const int retval = fclose(fp_); | |
107 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1014 times.
|
1014 | if (retval != 0) |
108 | ✗ | PANIC(kLogStderr, "could not close file after writing finished: %s", | |
109 | file_path_.c_str()); | ||
110 | 1014 | fp_ = NULL; | |
111 | |||
112 |
1/2✓ Branch 2 taken 1014 times.
✗ Branch 3 not taken.
|
1014 | mmapped_ = new MemoryMappedFile(file_path_); |
113 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1014 times.
|
1014 | 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 | 1424 | buf_ = reinterpret_cast<unsigned char *>(srealloc(buf_, pos_)); | |
118 | 1424 | size_ = pos_; | |
119 | } | ||
120 | |||
121 | 2438 | pos_ = 0; | |
122 | 2438 | state_ = kReadState; | |
123 | 2438 | } | |
124 | |||
125 | 65120 | int64_t FileBackedBuffer::Data(void **ptr, int64_t len, uint64_t pos) { | |
126 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 65120 times.
|
65120 | assert(state_ == kReadState); |
127 | |||
128 | 130240 | const int64_t actual_len = (pos + len <= size_) | |
129 |
2/2✓ Branch 0 taken 1099 times.
✓ Branch 1 taken 64021 times.
|
65120 | ? len |
130 | 1099 | : static_cast<int64_t>(size_) | |
131 | 1099 | - static_cast<int64_t>(pos); | |
132 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 65120 times.
|
65120 | assert(actual_len >= 0); |
133 | |||
134 |
2/2✓ Branch 0 taken 2376 times.
✓ Branch 1 taken 62744 times.
|
65120 | if (mode_ == kMemoryMode) { |
135 | 2376 | *ptr = buf_ + pos; | |
136 | } else { | ||
137 | 62744 | *ptr = mmapped_->buffer() + pos; | |
138 | } | ||
139 | 65120 | return actual_len; | |
140 | } | ||
141 | |||
142 | 62683 | int64_t FileBackedBuffer::Read(void *ptr, int64_t len) { | |
143 | 62683 | const int64_t bytes_read = ReadP(ptr, len, pos_); | |
144 | 62683 | pos_ += bytes_read; | |
145 | 62683 | return bytes_read; | |
146 | } | ||
147 | |||
148 | 62683 | int64_t FileBackedBuffer::ReadP(void *ptr, int64_t len, uint64_t pos) { | |
149 | void *source; | ||
150 |
1/2✓ Branch 1 taken 62683 times.
✗ Branch 2 not taken.
|
62683 | const int64_t bytes_read = Data(&source, len, pos); |
151 | 62683 | memcpy(ptr, source, bytes_read); | |
152 | 62683 | return bytes_read; | |
153 | } | ||
154 | |||
155 | 2432 | void FileBackedBuffer::Rewind() { | |
156 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2432 times.
|
2432 | assert(state_ == kReadState); |
157 | 2432 | pos_ = 0; | |
158 | 2432 | } | |
159 | |||
160 | 12594 | uint64_t FileBackedBuffer::GetSize() const { | |
161 |
4/4✓ Branch 0 taken 27 times.
✓ Branch 1 taken 12567 times.
✓ Branch 2 taken 26 times.
✓ Branch 3 taken 1 times.
|
12594 | if (state_ == kWriteState && mode_ == kMemoryMode) |
162 | 26 | return pos_; | |
163 | 12568 | return size_; | |
164 | } | ||
165 | |||
166 | |||
167 | 1014 | void FileBackedBuffer::SaveToFile() { | |
168 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1014 times.
|
1014 | assert(state_ == kWriteState); |
169 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1014 times.
|
1014 | assert(mode_ == kMemoryMode); |
170 | |||
171 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1014 times.
|
1014 | assert(fp_ == NULL); |
172 | 1014 | fp_ = CreateTempFile(tmp_dir_, 0644, "w", &file_path_); | |
173 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1014 times.
|
1014 | if (fp_ == NULL) |
174 | ✗ | PANIC(kLogStderr, "could not create temporary file"); | |
175 | |||
176 | 1014 | const uint64_t bytes_written = fwrite(buf_, 1, pos_, fp_); | |
177 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1014 times.
|
1014 | 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 | 1014 | free(buf_); | |
185 | 1014 | buf_ = NULL; | |
186 | 1014 | size_ = pos_; | |
187 | 1014 | mode_ = kFileMode; | |
188 | 1014 | } | |
189 |