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  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  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  uint64_t newsize = (size_ * 2 < pos_ + len) ? (pos_ + len) : (size_ * 2);
77  buf_ = reinterpret_cast<unsigned char *>(srealloc(buf_, newsize));
78  size_ = newsize;
79  }
80 
81  memcpy(buf_ + pos_, source, len);
82  pos_ += len;
83  } else {
84  assert(fp_ != NULL);
85  uint64_t bytes_written = fwrite(source, 1, len, fp_);
86  if (bytes_written != len) {
88  "could not append to temporary file %s: length %lu, "
89  "actually written %lu, error %d",
90  file_path_.c_str(), len, bytes_written, ferror(fp_));
91  }
92  pos_ += len;
93  size_ += len;
94  }
95 }
96 
99 
100  if (mode_ == kFileMode) {
101  int retval = fclose(fp_);
102  if (retval != 0)
103  PANIC(kLogStderr, "could not close file after writing finished: %s",
104  file_path_.c_str());
105  fp_ = NULL;
106 
108  if (!mmapped_->Map())
109  PANIC(kLogStderr, "could not memory-map file %s", file_path_.c_str());
110  } else {
111  // Trim memory chunk size to actual data size
112  buf_ = reinterpret_cast<unsigned char *>(srealloc(buf_, pos_));
113  size_ = pos_;
114  }
115 
116  pos_ = 0;
117  state_ = kReadState;
118 }
119 
120 int64_t FileBackedBuffer::Data(void **ptr, int64_t len, uint64_t pos) {
122 
123  int64_t actual_len = (pos + len <= size_) ? len
124  : static_cast<int64_t>(size_)
125  - static_cast<int64_t>(pos);
126  assert(actual_len >= 0);
127 
128  if (mode_ == kMemoryMode) {
129  *ptr = buf_ + pos;
130  } else {
131  *ptr = mmapped_->buffer() + pos;
132  }
133  return actual_len;
134 }
135 
136 int64_t FileBackedBuffer::Read(void *ptr, int64_t len) {
137  int64_t bytes_read = ReadP(ptr, len, pos_);
138  pos_ += bytes_read;
139  return bytes_read;
140 }
141 
142 int64_t FileBackedBuffer::ReadP(void *ptr, int64_t len, uint64_t pos) {
143  void *source;
144  int64_t bytes_read = Data(&source, len, pos);
145  memcpy(ptr, source, bytes_read);
146  return bytes_read;
147 }
148 
151  pos_ = 0;
152 }
153 
154 uint64_t FileBackedBuffer::GetSize() const {
155  if (state_ == kWriteState && mode_ == kMemoryMode)
156  return pos_;
157  return size_;
158 }
159 
160 
164 
165  assert(fp_ == NULL);
166  fp_ = CreateTempFile(tmp_dir_, 0644, "w", &file_path_);
167  if (fp_ == NULL)
168  PANIC(kLogStderr, "could not create temporary file");
169 
170  uint64_t bytes_written = fwrite(buf_, 1, pos_, fp_);
171  if (bytes_written != pos_) {
173  "could not write to temporary file %s: length %lu, "
174  "actually written %lu, error %d",
175  file_path_.c_str(), pos_, bytes_written, ferror(fp_));
176  }
177 
178  free(buf_);
179  buf_ = NULL;
180  size_ = pos_;
181  mode_ = kFileMode;
182 }
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:1013
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