libdballe  9.11
structbuf.h
1 /*
2  * core/structbuf - memory or file-backed storage of structures
3  *
4  * Copyright (C) 2014 ARPA-SIM <urpsim@smr.arpa.emr.it>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18  *
19  * Author: Enrico Zini <enrico@enricozini.com>
20  */
21 
22 #ifndef DBALLE_CORE_STRUCTBUF_H
23 #define DBALLE_CORE_STRUCTBUF_H
24 
25 #include <wreport/error.h>
26 #include <cstdlib>
27 #include <unistd.h>
28 #include <sys/mman.h>
29 
30 namespace dballe {
31 
32 namespace structbuf {
33 int make_anonymous_tmpfile();
34 void write_buffer(int fd, void* buf, size_t size);
35 }
36 
44 template<typename T, int bufsize=1024>
45 class Structbuf
46 {
47 protected:
52  T* membuf = nullptr;
53 
55  unsigned membuf_last = 0;
56 
61  const T* readbuf = (const T*)MAP_FAILED;
62 
64  size_t m_count = 0;
65 
68  int tmpfile_fd = -1;
69 
70 public:
71  Structbuf()
72  : membuf(new T[bufsize])
73  {
74  }
75  ~Structbuf()
76  {
77  delete[] membuf;
78  if (tmpfile_fd != -1)
79  {
80  if (readbuf != MAP_FAILED)
81  munmap(const_cast<T*>(readbuf), m_count * sizeof(T));
82  ::close(tmpfile_fd);
83  }
84  }
85 
87  size_t size() const { return m_count; }
88 
90  bool is_file_backed() const { return tmpfile_fd != -1; }
91 
93  void append(const T& val)
94  {
95  if (readbuf != MAP_FAILED)
96  throw wreport::error_consistency("writing to a Structbuf that is already being read");
97  if (membuf_last == bufsize)
98  write_to_file();
99  membuf[membuf_last++] = val;
100  ++m_count;
101  }
102 
105  {
106  if (tmpfile_fd == -1)
107  readbuf = membuf;
108  else
109  {
110  // Flush the remaining memory data to file
111  if (membuf_last) write_to_file();
112 
113  // mmap the file for reading
114  readbuf = (const T*)mmap(nullptr, m_count * sizeof(T), PROT_READ, MAP_SHARED, tmpfile_fd, 0);
115  if (readbuf == MAP_FAILED)
116  throw wreport::error_system("cannot map temporary file contents to memory");
117  }
118  }
119 
121  const T& operator[](size_t idx) const
122  {
123  return readbuf[idx];
124  }
125 
126 protected:
127  void write_to_file()
128  {
129  if (tmpfile_fd == -1)
130  tmpfile_fd = structbuf::make_anonymous_tmpfile();
131  structbuf::write_buffer(tmpfile_fd, membuf, sizeof(T) * membuf_last);
132  membuf_last = 0;
133  }
134 };
135 
136 }
137 
138 #endif
const T * readbuf
Memory area used for reading.
Definition: structbuf.h:61
unsigned membuf_last
Number of items in membuf.
Definition: structbuf.h:55
T * membuf
In-memory buffer using during appending.
Definition: structbuf.h:52
Buffer of simple structures that becomes file backed if it grows beyond a certain size...
Definition: structbuf.h:45
size_t m_count
Number of items appended so far.
Definition: structbuf.h:64
Definition: cmdline.h:18
size_t size() const
Get the number of structures that have been added to the buffer so far.
Definition: structbuf.h:87
void ready_to_read()
Stop appending and get ready to read back the data.
Definition: structbuf.h:104
int tmpfile_fd
Unix file descriptor to the temporary file, or -1 if we are memory backed.
Definition: structbuf.h:68
void append(const T &val)
Append an item to the buffer.
Definition: structbuf.h:93
bool is_file_backed() const
Return true if the buffer has become file-backed.
Definition: structbuf.h:90
const T & operator[](size_t idx) const
Read back an item.
Definition: structbuf.h:121