Reputation: 209
My understanding is that this code can keep a vector in a file.
using Alloc = boost::interprocess::allocator<int32_t, boost::interprocess::managed_mapped_file::segment_manager>;
using Vec = boost::interprocess::vector<int32_t, Alloc>;
void f() {
boost::interprocess::managed_mapped_file seg(boost::interprocess::open_or_create, "data.dat", 1024);
auto vec = seg.find_or_construct<Vec>("vec")(seg.get_segment_manager());
// ......
}
However, when the vector tried to get too many bytes it throws bad_alloc
exception.
I'm not able to predict how many bytes are required so I came up with growing the file when free_memory is reducing. However sometimes assertion failed occurs when growing.
Here is minimum code.
using Alloc = allocator<int32_t, managed_mapped_file::segment_manager>;
using Vec = vector<int32_t, Alloc>;
void test(int, int);
int main()
{
test(4096, 4); // Change this value if not reproduced
return 0;
}
void test(int initialBytes, int extraBytes) {
fprintf(stderr, "test(%d, %d)\n", initialBytes, extraBytes);
remove("data.dat");
auto seg = make_unique<managed_mapped_file>(open_or_create, "data.dat", initialBytes);
auto vec = seg->find_or_construct<Vec>("vec")(seg->get_segment_manager());
fprintf(stderr, "vec->capacity=%ld\n", vec->capacity());
fprintf(stderr, "seg.get_free_memory()=%ld\n\n", seg->get_free_memory());
seg = nullptr;
fprintf(stderr, "tag1\n");
boost::interprocess::managed_mapped_file::grow("data.dat", extraBytes);
fprintf(stderr, "tag2\n");
seg = make_unique<managed_mapped_file>(open_only, "data.dat");
fprintf(stderr, "tag3\n");
vec = seg->find<Vec>("vec").first;
fprintf(stderr, "tag4\n");
fprintf(stderr, "vec->capacity=%ld\n", vec->capacity());
fprintf(stderr, "seg.get_free_memory()=%ld\n\n", seg->get_free_memory());
}
More smaller
void test(int initialBytes, int extraBytes) {
remove("data.dat");
auto seg = std::make_unique<managed_mapped_file>(open_or_create, "data.dat", initialBytes);
seg = nullptr;
managed_mapped_file::grow("data.dat", extraBytes);
}
Ask: How can I store elastic vector without assuming maximum size?
I misunderstood grow
- it's static function. So I fixed the code. Still fails the assertion.
I found assertion fails when 4 <= extraBytes && extraBytes < 24
Upvotes: 0
Views: 843
Reputation: 1277
You can see working example below. This program creates small memory mapped file, creates vector container and then fills vector by push_back. If it is impossible to make next push_back, control is transferred to catch block. In this block the file is closed, the function grow is called, memory mapped file is opened, the vector is founded and the push_back is repeated.
#include <iostream>
#define BOOST_DATE_TIME_NO_LIB
#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/interprocess/file_mapping.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <string>
namespace IP = boost::interprocess;
template <typename T> using MyVectorT = IP::vector < T, IP::allocator<T, IP::managed_mapped_file::segment_manager>>;
int main(int )
{
const char *FileName = "file.bin";
const std::size_t FileSize = 1000;
using MyVector = MyVectorT<size_t>;
try
{
IP::remove_file_on_destroy tmp{ FileName };
IP::managed_mapped_file segment(IP::create_only
, FileName //Mapped file name
, FileSize); //Mapped file initial size
MyVector *myvector = segment.construct<MyVector>("MyVector")(segment.get_segment_manager());
for (size_t i = 0; i < 100000; ++i) //Insert data in the vector
{
bool push_failure = true;
do
{
try
{
myvector->push_back(i);
push_failure = false; //success of push_back
}
catch (const IP::bad_alloc &) //memory mapped file is too small for vector
{
const size_t grow_size = std::max<size_t>(FileSize, 2 * (myvector->size() + 1) * sizeof(MyVector::value_type)); //estimate memory for new vector capacity
std::cout << "segment size = " << segment.get_size() << " Vector capacity = " << myvector->capacity() << " grow_size = " << grow_size;
//free memory mapped file
segment.flush();
segment.~basic_managed_mapped_file();
IP::managed_mapped_file::grow(FileName, grow_size);
new (&segment) IP::managed_mapped_file(IP::open_only, FileName);
std::cout << " -> new segment size = " << segment.get_size() << std::endl;
myvector = segment.find<MyVector>("MyVector").first;
push_failure = true; //try push_back again!!!
}
} while (push_failure);
}
std::cout << "Vector size =" << myvector->size() << "\n";
for (size_t i = 0; i < 100000; ++i)
{
if ((*myvector)[i] != i)
{
std::cout << "vector error!!! i = " << i << " vector[i] = " << (*myvector)[i] << std::endl;
}
}
}
catch (const std::exception &e)
{
std::cout << "Error " << e.what() << std::endl;
}
catch (...)
{
std::cout << "Error";
}
return 0;
}
Upvotes: 1