ProvSQL C/C++ API
Adding support for provenance and uncertainty management to PostgreSQL databases
Loading...
Searching...
No Matches
MMappedVector.hpp
Go to the documentation of this file.
1/**
2 * @file MMappedVector.hpp
3 * @brief Template implementation of @c MMappedVector<T>.
4 *
5 * Provides the out-of-line definitions of all @c MMappedVector<T>
6 * methods declared in @c MMappedVector.h. This file must be included
7 * by any translation unit that instantiates @c MMappedVector<T> for a
8 * specific @c T.
9 *
10 * Implemented methods:
11 * - @c MMappedVector(): open/create the backing file and map it.
12 * - @c ~MMappedVector(): sync and unmap.
13 * - @c operator[](k) const: read element @p k.
14 * - @c operator[](k): write element @p k.
15 * - @c add(): append one element, growing the file if necessary.
16 * - @c sync(): flush dirty pages with @c msync().
17 *
18 * Internal helpers:
19 * - @c mmap(): map (or remap) @p length bytes.
20 * - @c grow(): double the capacity and remap.
21 */
22#ifndef MMAPPED_VECTOR_HPP
23#define MMAPPED_VECTOR_HPP
24
25#include "MMappedVector.h"
26
27#include <cassert>
28#include <cerrno>
29#include <cstdint>
30#include <cstring>
31#include <new>
32#include <stdexcept>
33#include <string>
34#include <vector>
35
36#include <fcntl.h>
37#include <unistd.h>
38
39#include <sys/mman.h>
40
41template <typename T>
42MMappedVector<T>::MMappedVector(const char *filename, bool read_only, uint64_t magic_value)
43{
44 fd=open(filename, O_CREAT|(read_only?O_RDONLY:O_RDWR), 0600); // flawfinder: ignore
45 if(fd==-1)
46 throw std::runtime_error(strerror(errno));
47
48 auto length = lseek(fd, 0, SEEK_END);
49 lseek(fd, 0, SEEK_SET);
50
51 bool empty=false;
52
53 if(length==0) {
54 empty=true;
55 length=offsetof(data_t, d)+sizeof(T)*STARTING_CAPACITY;
56 if(ftruncate(fd, length))
57 throw std::runtime_error(strerror(errno));
58 }
59
60 mmap(length, read_only);
61
62 if(empty) {
63 data->magic = magic_value;
64 data->version = 1;
65 data->elem_size = static_cast<uint16_t>(sizeof(T));
66 data->_reserved = 0;
67 data->capacity = STARTING_CAPACITY;
68 data->nb_elements = 0;
69 } else {
70 if(data->magic != magic_value)
71 throw std::runtime_error("ProvSQL mmap: wrong file type (magic mismatch)");
72 if(data->version != 1)
73 throw std::runtime_error("ProvSQL mmap: unsupported format version "
74 + std::to_string(data->version));
75 if(data->elem_size != sizeof(T))
76 throw std::runtime_error("ProvSQL mmap: element size mismatch (recompile required)");
77 }
78}
79
80template <typename T>
81void MMappedVector<T>::mmap(size_t length, bool read_only)
82{
83 data = reinterpret_cast<data_t *>(::mmap(
84 NULL,
85 length,
86 PROT_READ|(read_only?0:PROT_WRITE),
87 MAP_SHARED,
88 fd,
89 0));
90 if(data == MAP_FAILED)
91 throw std::runtime_error(strerror(errno));
93
94template <typename T>
96{
97 sync();
98 auto new_capacity = data->capacity*2;
99 munmap(data, offsetof(data_t,d)+sizeof(T)*data->capacity);
100
101 auto new_length = offsetof(data_t,d)+sizeof(T)*new_capacity;
102 if(ftruncate(fd, new_length))
103 throw std::runtime_error(strerror(errno));
104 mmap(new_length, false);
105
106 data->capacity = new_capacity;
107}
109template <typename T>
111{
112 munmap(data, offsetof(data_t,d)+sizeof(T)*data->capacity);
113 close(fd);
114}
115
116template <typename T>
117inline const T &MMappedVector<T>::operator[](unsigned long k) const
118{
119 return data->d[k];
120}
121
122template <typename T>
123inline T &MMappedVector<T>::operator[](unsigned long k)
124{
125 return data->d[k];
126}
127
128template <typename T>
129void MMappedVector<T>::add(const T &value)
130{
131 if(data->nb_elements == data->capacity)
132 grow();
133
134 data->d[data->nb_elements++] = value;
135}
136
137template <typename T>
139{
140 msync(data, offsetof(data_t,d)+sizeof(T)*data->capacity, MS_SYNC);
141}
142
143#endif /* MMAPPED_VECTOR_HPP */
Append-only vector template backed by a memory-mapped file.
~MMappedVector()
Sync and unmap the file.
data_t * data
Pointer to the memory-mapped data header.
static constexpr unsigned STARTING_CAPACITY
Initial number of element slots allocated.
void add(const T &value)
Append an element to the end of the vector.
void mmap(size_t length, bool read_only)
Map length bytes from the backing file.
int fd
File descriptor of the backing mmap file.
void grow()
Double the backing file and remap.
MMappedVector(const char *filename, bool read_only, uint64_t magic)
Open (or create) the mmap-backed vector.
const T & operator[](unsigned long k) const
Read-only element access by index.
void sync()
Flush dirty pages to the backing file with msync().
On-disk layout stored at the start of the backing file.