Directory: | cvmfs/ |
---|---|
File: | cvmfs/util/file_backed_buffer.cc |
Date: | 2025-02-02 02:34:22 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 99 | 108 | 91.7% |
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 | 621 | FileBackedBuffer *FileBackedBuffer::Create(uint64_t in_memory_threshold, | |
17 | const std::string &tmp_dir) | ||
18 | { | ||
19 |
1/2✓ Branch 2 taken 621 times.
✗ Branch 3 not taken.
|
621 | return new FileBackedBuffer(in_memory_threshold, tmp_dir); |
20 | } | ||
21 | |||
22 | 621 | FileBackedBuffer::FileBackedBuffer(uint64_t in_memory_threshold, | |
23 | 621 | const std::string &tmp_dir) : | |
24 | 621 | in_memory_threshold_(in_memory_threshold), | |
25 | 621 | tmp_dir_(tmp_dir), | |
26 | 621 | state_(kWriteState), | |
27 | 621 | mode_(kMemoryMode), | |
28 | 621 | size_(0), | |
29 | 621 | buf_(NULL), | |
30 | 621 | pos_(0), | |
31 | 621 | fp_(NULL), | |
32 |
1/2✓ Branch 2 taken 621 times.
✗ Branch 3 not taken.
|
621 | file_path_(""), |
33 | 621 | mmapped_(NULL) | |
34 | { | ||
35 | 621 | } | |
36 | |||
37 | 1242 | FileBackedBuffer::~FileBackedBuffer() { | |
38 | 621 | free(buf_); | |
39 |
2/2✓ Branch 0 taken 366 times.
✓ Branch 1 taken 255 times.
|
621 | if (mode_ != kFileMode) |
40 | 366 | return; | |
41 | |||
42 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 255 times.
|
255 | if (state_ == kWriteState) { |
43 | ✗ | int retval = fclose(fp_); | |
44 | ✗ | if (retval != 0) | |
45 | ✗ | PANIC(kLogStderr, "could not close temporary file %s: error %d", | |
46 | file_path_.c_str(), retval); | ||
47 | } else { | ||
48 | 255 | mmapped_->Unmap(); | |
49 |
1/2✓ Branch 0 taken 255 times.
✗ Branch 1 not taken.
|
255 | delete mmapped_; |
50 | } | ||
51 | 255 | int retval = unlink(file_path_.c_str()); | |
52 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 255 times.
|
255 | if (retval != 0) |
53 | ✗ | PANIC(kLogStderr, "could not delete temporary file %s: error %d", | |
54 | file_path_.c_str(), retval); | ||
55 |
4/4✓ Branch 1 taken 255 times.
✓ Branch 2 taken 366 times.
✓ Branch 4 taken 255 times.
✓ Branch 5 taken 366 times.
|
987 | } |
56 | |||
57 | 199646 | void FileBackedBuffer::Append(const void *source, uint64_t len) { | |
58 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 199646 times.
|
199646 | assert(source != NULL); |
59 | |||
60 | // Cannot write after Commit() | ||
61 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 199646 times.
|
199646 | assert(state_ == kWriteState); |
62 | |||
63 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 199645 times.
|
199646 | if (len == 0) return; |
64 | |||
65 | // check the size and eventually save to file | ||
66 |
4/4✓ Branch 0 taken 23662 times.
✓ Branch 1 taken 175983 times.
✓ Branch 2 taken 255 times.
✓ Branch 3 taken 23407 times.
|
199645 | if (mode_ == kMemoryMode && pos_ + len > in_memory_threshold_) { |
67 | // changes mode_ to kFileMode | ||
68 | 255 | SaveToFile(); | |
69 | } | ||
70 | |||
71 |
2/2✓ Branch 0 taken 23407 times.
✓ Branch 1 taken 176238 times.
|
199645 | if (mode_ == kMemoryMode) { |
72 |
2/2✓ Branch 0 taken 423 times.
✓ Branch 1 taken 22984 times.
|
23407 | if (buf_ == NULL) { |
73 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 423 times.
|
423 | assert(size_ == 0); |
74 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 423 times.
|
423 | assert(pos_ == 0); |
75 | 423 | buf_ = reinterpret_cast<unsigned char *>(smalloc(len)); | |
76 | 423 | size_ = len; | |
77 |
2/2✓ Branch 0 taken 1943 times.
✓ Branch 1 taken 21041 times.
|
22984 | } else if (size_ < pos_ + len) { |
78 | 1943 | uint64_t newsize = (size_ * 2 < pos_ + len) ? (pos_ + len) : (size_ * 2); | |
79 | 1943 | buf_ = reinterpret_cast<unsigned char *>(srealloc(buf_, newsize)); | |
80 | 1943 | size_ = newsize; | |
81 | } | ||
82 | |||
83 | 23407 | memcpy(buf_ + pos_, source, len); | |
84 | 23407 | pos_ += len; | |
85 | } else { | ||
86 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 176238 times.
|
176238 | assert(fp_ != NULL); |
87 | 176238 | uint64_t bytes_written = fwrite(source, 1, len, fp_); | |
88 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 176238 times.
|
176238 | if (bytes_written != len) { |
89 | ✗ | PANIC(kLogStderr, "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 | 176238 | pos_ += len; | |
94 | 176238 | size_ += len; | |
95 | } | ||
96 | } | ||
97 | |||
98 | 614 | void FileBackedBuffer::Commit() { | |
99 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 614 times.
|
614 | assert(state_ == kWriteState); |
100 | |||
101 |
2/2✓ Branch 0 taken 255 times.
✓ Branch 1 taken 359 times.
|
614 | if (mode_ == kFileMode) { |
102 | 255 | int retval = fclose(fp_); | |
103 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 255 times.
|
255 | if (retval != 0) |
104 | ✗ | PANIC(kLogStderr, "could not close file after writing finished: %s", | |
105 | file_path_.c_str()); | ||
106 | 255 | fp_ = NULL; | |
107 | |||
108 |
1/2✓ Branch 2 taken 255 times.
✗ Branch 3 not taken.
|
255 | mmapped_ = new MemoryMappedFile(file_path_); |
109 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 255 times.
|
255 | 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 | 359 | buf_ = reinterpret_cast<unsigned char *>(srealloc(buf_, pos_)); | |
114 | 359 | size_ = pos_; | |
115 | } | ||
116 | |||
117 | 614 | pos_ = 0; | |
118 | 614 | state_ = kReadState; | |
119 | 614 | } | |
120 | |||
121 | 16289 | int64_t FileBackedBuffer::Data(void **ptr, int64_t len, uint64_t pos) { | |
122 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16289 times.
|
16289 | assert(state_ == kReadState); |
123 | |||
124 |
2/2✓ Branch 0 taken 283 times.
✓ Branch 1 taken 16006 times.
|
16289 | int64_t actual_len = (pos + len <= size_) ? |
125 | 283 | len : static_cast<int64_t>(size_) - static_cast<int64_t>(pos); | |
126 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16289 times.
|
16289 | assert(actual_len >= 0); |
127 | |||
128 |
2/2✓ Branch 0 taken 600 times.
✓ Branch 1 taken 15689 times.
|
16289 | if (mode_ == kMemoryMode) { |
129 | 600 | *ptr = buf_ + pos; | |
130 | } else { | ||
131 | 15689 | *ptr = mmapped_->buffer() + pos; | |
132 | } | ||
133 | 16289 | return actual_len; | |
134 | } | ||
135 | |||
136 | 15676 | int64_t FileBackedBuffer::Read(void *ptr, int64_t len) { | |
137 | 15676 | int64_t bytes_read = ReadP(ptr, len, pos_); | |
138 | 15676 | pos_ += bytes_read; | |
139 | 15676 | return bytes_read; | |
140 | } | ||
141 | |||
142 | 15676 | int64_t FileBackedBuffer::ReadP(void *ptr, int64_t len, uint64_t pos) { | |
143 | void *source; | ||
144 |
1/2✓ Branch 1 taken 15676 times.
✗ Branch 2 not taken.
|
15676 | int64_t bytes_read = Data(&source, len, pos); |
145 | 15676 | memcpy(ptr, source, bytes_read); | |
146 | 15676 | return bytes_read; | |
147 | } | ||
148 | |||
149 | 608 | void FileBackedBuffer::Rewind() { | |
150 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 608 times.
|
608 | assert(state_ == kReadState); |
151 | 608 | pos_ = 0; | |
152 | 608 | } | |
153 | |||
154 | 3153 | uint64_t FileBackedBuffer::GetSize() const { | |
155 |
4/4✓ Branch 0 taken 9 times.
✓ Branch 1 taken 3144 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 1 times.
|
3153 | if (state_ == kWriteState && mode_ == kMemoryMode) |
156 | 8 | return pos_; | |
157 | 3145 | return size_; | |
158 | } | ||
159 | |||
160 | |||
161 | 255 | void FileBackedBuffer::SaveToFile() { | |
162 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 255 times.
|
255 | assert(state_ == kWriteState); |
163 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 255 times.
|
255 | assert(mode_ == kMemoryMode); |
164 | |||
165 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 255 times.
|
255 | assert(fp_ == NULL); |
166 | 255 | fp_ = CreateTempFile(tmp_dir_, 0644, "w", &file_path_); | |
167 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 255 times.
|
255 | if (fp_ == NULL) |
168 | ✗ | PANIC(kLogStderr, "could not create temporary file"); | |
169 | |||
170 | 255 | uint64_t bytes_written = fwrite(buf_, 1, pos_, fp_); | |
171 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 255 times.
|
255 | if (bytes_written != pos_) { |
172 | ✗ | PANIC(kLogStderr, "could not write to temporary file %s: length %lu, " | |
173 | "actually written %lu, error %d", | ||
174 | file_path_.c_str(), pos_, bytes_written, ferror(fp_)); | ||
175 | } | ||
176 | |||
177 | 255 | free(buf_); | |
178 | 255 | buf_ = NULL; | |
179 | 255 | size_ = pos_; | |
180 | 255 | mode_ = kFileMode; | |
181 | 255 | } | |
182 |