CernVM-FS  2.13.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
file_backed_buffer.cc
Go to the documentation of this file.
1 
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 FileBackedBuffer *FileBackedBuffer::Create(uint64_t in_memory_threshold,
17  const std::string &tmp_dir) {
18  return new FileBackedBuffer(in_memory_threshold, tmp_dir);
19 }
20 
21 FileBackedBuffer::FileBackedBuffer(uint64_t in_memory_threshold,
22  const std::string &tmp_dir)
23  : in_memory_threshold_(in_memory_threshold)
24  , tmp_dir_(tmp_dir)
25  , state_(kWriteState)
26  , mode_(kMemoryMode)
27  , size_(0)
28  , buf_(NULL)
29  , pos_(0)
30  , fp_(NULL)
31  , file_path_("")
32  , mmapped_(NULL) { }
33 
35  free(buf_);
36  if (mode_ != kFileMode)
37  return;
38 
39  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  mmapped_->Unmap();
46  delete mmapped_;
47  }
48  const int retval = unlink(file_path_.c_str());
49  if (retval != 0)
50  PANIC(kLogStderr, "could not delete temporary file %s: error %d",
51  file_path_.c_str(), retval);
52 }
53 
54 void FileBackedBuffer::Append(const void *source, uint64_t len) {
55  assert(source != NULL);
56 
57  // Cannot write after Commit()
59 
60  if (len == 0)
61  return;
62 
63  // check the size and eventually save to file
64  if (mode_ == kMemoryMode && pos_ + len > in_memory_threshold_) {
65  // changes mode_ to kFileMode
66  SaveToFile();
67  }
68 
69  if (mode_ == kMemoryMode) {
70  if (buf_ == NULL) {
71  assert(size_ == 0);
72  assert(pos_ == 0);
73  buf_ = reinterpret_cast<unsigned char *>(smalloc(len));
74  size_ = len;
75  } else if (size_ < pos_ + len) {
76  const uint64_t newsize =
77  (size_ * 2 < pos_ + len) ? (pos_ + len) : (size_ * 2);
78  buf_ = reinterpret_cast<unsigned char *>(srealloc(buf_, newsize));
79  size_ = newsize;
80  }
81 
82  memcpy(buf_ + pos_, source, len);
83  pos_ += len;
84  } else {
85  assert(fp_ != NULL);
86  const uint64_t bytes_written = fwrite(source, 1, len, fp_);
87  if (bytes_written != len) {
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  pos_ += len;
94  size_ += len;
95  }
96 }
97 
100 
101  if (mode_ == kFileMode) {
102  const int retval = fclose(fp_);
103  if (retval != 0)
104  PANIC(kLogStderr, "could not close file after writing finished: %s",
105  file_path_.c_str());
106  fp_ = NULL;
107 
109  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  buf_ = reinterpret_cast<unsigned char *>(srealloc(buf_, pos_));
114  size_ = pos_;
115  }
116 
117  pos_ = 0;
118  state_ = kReadState;
119 }
120 
121 int64_t FileBackedBuffer::Data(void **ptr, int64_t len, uint64_t pos) {
123 
124  const int64_t actual_len =
125  (pos + len <= size_)
126  ? len
127  : static_cast<int64_t>(size_) - static_cast<int64_t>(pos);
128  assert(actual_len >= 0);
129 
130  if (mode_ == kMemoryMode) {
131  *ptr = buf_ + pos;
132  } else {
133  *ptr = mmapped_->buffer() + pos;
134  }
135  return actual_len;
136 }
137 
138 int64_t FileBackedBuffer::Read(void *ptr, int64_t len) {
139  const int64_t bytes_read = ReadP(ptr, len, pos_);
140  pos_ += bytes_read;
141  return bytes_read;
142 }
143 
144 int64_t FileBackedBuffer::ReadP(void *ptr, int64_t len, uint64_t pos) {
145  void *source;
146  const int64_t bytes_read = Data(&source, len, pos);
147  memcpy(ptr, source, bytes_read);
148  return bytes_read;
149 }
150 
153  pos_ = 0;
154 }
155 
156 uint64_t FileBackedBuffer::GetSize() const {
157  if (state_ == kWriteState && mode_ == kMemoryMode)
158  return pos_;
159  return size_;
160 }
161 
162 
166 
167  assert(fp_ == NULL);
168  fp_ = CreateTempFile(tmp_dir_, 0644, "w", &file_path_);
169  if (fp_ == NULL)
170  PANIC(kLogStderr, "could not create temporary file");
171 
172  const uint64_t bytes_written = fwrite(buf_, 1, pos_, fp_);
173  if (bytes_written != pos_) {
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  free(buf_);
181  buf_ = NULL;
182  size_ = pos_;
183  mode_ = kFileMode;
184 }
std::string file_path_
static FileBackedBuffer * Create(uint64_t in_memory_threshold, const std::string &tmp_dir="/tmp/")
#define PANIC(...)
Definition: exception.h:29
CVMFS_EXPORT const LogSource source
Definition: exception.h:33
FILE * CreateTempFile(const std::string &path_prefix, const int mode, const char *open_flags, std::string *final_path)
Definition: posix.cc:1014
const uint64_t in_memory_threshold_
assert((mem||(size==0))&&"Out Of Memory")
MemoryMappedFile * mmapped_
enum FileBackedBuffer::@4 state_
int64_t ReadP(void *ptr, int64_t len, uint64_t pos)
unsigned char * buf_
int64_t Data(void **ptr, int64_t len, uint64_t pos)
int64_t Read(void *ptr, int64_t len)
enum FileBackedBuffer::@5 mode_
void Append(const void *source, uint64_t len)
FileBackedBuffer(uint64_t in_memory_threshold, const std::string &tmp_dir)
uint64_t GetSize() const
const std::string tmp_dir_
unsigned char * buffer() const
Definition: mmap_file.h:32