CernVM-FS  2.12.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 {
19  return new FileBackedBuffer(in_memory_threshold, tmp_dir);
20 }
21 
22 FileBackedBuffer::FileBackedBuffer(uint64_t in_memory_threshold,
23  const std::string &tmp_dir) :
24  in_memory_threshold_(in_memory_threshold),
25  tmp_dir_(tmp_dir),
26  state_(kWriteState),
27  mode_(kMemoryMode),
28  size_(0),
29  buf_(NULL),
30  pos_(0),
31  fp_(NULL),
32  file_path_(""),
33  mmapped_(NULL)
34 {
35 }
36 
38  free(buf_);
39  if (mode_ != kFileMode)
40  return;
41 
42  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  mmapped_->Unmap();
49  delete mmapped_;
50  }
51  int retval = unlink(file_path_.c_str());
52  if (retval != 0)
53  PANIC(kLogStderr, "could not delete temporary file %s: error %d",
54  file_path_.c_str(), retval);
55 }
56 
57 void FileBackedBuffer::Append(const void *source, uint64_t len) {
58  assert(source != NULL);
59 
60  // Cannot write after Commit()
62 
63  if (len == 0) return;
64 
65  // check the size and eventually save to file
66  if (mode_ == kMemoryMode && pos_ + len > in_memory_threshold_) {
67  // changes mode_ to kFileMode
68  SaveToFile();
69  }
70 
71  if (mode_ == kMemoryMode) {
72  if (buf_ == NULL) {
73  assert(size_ == 0);
74  assert(pos_ == 0);
75  buf_ = reinterpret_cast<unsigned char *>(smalloc(len));
76  size_ = len;
77  } else if (size_ < pos_ + len) {
78  uint64_t newsize = (size_ * 2 < pos_ + len) ? (pos_ + len) : (size_ * 2);
79  buf_ = reinterpret_cast<unsigned char *>(srealloc(buf_, newsize));
80  size_ = newsize;
81  }
82 
83  memcpy(buf_ + pos_, source, len);
84  pos_ += len;
85  } else {
86  assert(fp_ != NULL);
87  uint64_t bytes_written = fwrite(source, 1, len, fp_);
88  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  pos_ += len;
94  size_ += len;
95  }
96 }
97 
100 
101  if (mode_ == kFileMode) {
102  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  int64_t actual_len = (pos + len <= size_) ?
125  len : static_cast<int64_t>(size_) - 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_) {
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  free(buf_);
178  buf_ = NULL;
179  size_ = pos_;
180  mode_ = kFileMode;
181 }
std::string file_path_
static FileBackedBuffer * Create(uint64_t in_memory_threshold, const std::string &tmp_dir="/tmp/")
#define PANIC(...)
Definition: exception.h:29
FILE * CreateTempFile(const std::string &path_prefix, const int mode, const char *open_flags, std::string *final_path)
Definition: posix.cc:1005
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