Add a CREATE mode to the block_io class.
This commit is contained in:
parent
779f8e1fd4
commit
fb1ad01e19
@ -85,6 +85,7 @@ namespace persistent_data {
|
|||||||
enum mode {
|
enum mode {
|
||||||
READ_ONLY,
|
READ_ONLY,
|
||||||
READ_WRITE,
|
READ_WRITE,
|
||||||
|
CREATE
|
||||||
};
|
};
|
||||||
|
|
||||||
block_io(std::string const &path, block_address nr_blocks, mode m);
|
block_io(std::string const &path, block_address nr_blocks, mode m);
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include <boost/bind.hpp>
|
#include <boost/bind.hpp>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
@ -35,37 +37,102 @@ using namespace std;
|
|||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
int const DEFAULT_MODE = 0666;
|
||||||
|
int const OPEN_FLAGS = O_DIRECT | O_SYNC;
|
||||||
|
|
||||||
|
// FIXME: introduce a new exception for this, or at least lift this
|
||||||
|
// to exception.h
|
||||||
|
void syscall_failed(char const *call) {
|
||||||
|
char buffer[128];
|
||||||
|
char *msg = strerror_r(errno, buffer, sizeof(buffer));
|
||||||
|
|
||||||
|
ostringstream out;
|
||||||
|
out << "syscall '" << call << "' failed: " << msg;
|
||||||
|
throw runtime_error(out.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
int open_file(string const &path, int flags) {
|
||||||
|
int fd = ::open(path.c_str(), OPEN_FLAGS | flags, DEFAULT_MODE);
|
||||||
|
if (fd < 0)
|
||||||
|
syscall_failed("open");
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool file_exists(string const &path) {
|
||||||
|
typename ::stat info;
|
||||||
|
|
||||||
|
int r = ::stat(path.c_str(), &info);
|
||||||
|
if (r) {
|
||||||
|
if (errno == ENOENT)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
syscall_failed("stat");
|
||||||
|
return false; // never get here
|
||||||
|
|
||||||
|
} else
|
||||||
|
return S_ISREG(info.st_mode) || S_ISBLK(info.st_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
int create_block_file(string const &path, off_t file_size) {
|
||||||
|
if (file_exists(path)) {
|
||||||
|
ostringstream out;
|
||||||
|
out << __FUNCTION__ << ": file '" << path << "' already exists";
|
||||||
|
throw runtime_error(out.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
int fd = open_file(path, O_CREAT | O_RDWR);
|
||||||
|
int r = ::fallocate(fd, 0, 0, file_size);
|
||||||
|
if (r < 0)
|
||||||
|
syscall_failed("fallocate");
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int open_block_file(string const &path, off_t min_size, bool writeable) {
|
||||||
|
if (!file_exists(path)) {
|
||||||
|
ostringstream out;
|
||||||
|
out << __FUNCTION__ << ": file '" << path << "' doesn't exist";
|
||||||
|
throw runtime_error(out.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return open_file(path, writeable ? O_RDWR : O_RDONLY);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template <uint32_t BlockSize>
|
template <uint32_t BlockSize>
|
||||||
block_io<BlockSize>::block_io(std::string const &path, block_address nr_blocks, mode m)
|
block_io<BlockSize>::block_io(std::string const &path, block_address nr_blocks, mode m)
|
||||||
: nr_blocks_(nr_blocks),
|
: nr_blocks_(nr_blocks),
|
||||||
mode_(m)
|
mode_(m)
|
||||||
{
|
{
|
||||||
int fd_mode = O_DIRECT | O_SYNC;
|
off_t file_size = nr_blocks * BlockSize;
|
||||||
|
|
||||||
switch (m) {
|
switch (m) {
|
||||||
case READ_ONLY:
|
case READ_ONLY:
|
||||||
fd_mode |= O_RDONLY;
|
fd_ = open_block_file(path, file_size, false);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case READ_WRITE:
|
case READ_WRITE:
|
||||||
fd_mode |= O_RDWR;
|
fd_ = open_block_file(path, file_size, true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CREATE:
|
||||||
|
fd_ = create_block_file(path, file_size);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw runtime_error("unsupported mode");
|
throw runtime_error("unsupported mode");
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// fd_ = ::open(path.c_str(), writeable ? (O_RDWR | O_CREAT) : O_RDONLY, 0666);
|
|
||||||
fd_ = ::open(path.c_str(), fd_mode, 0666);
|
|
||||||
if (fd_ < 0)
|
|
||||||
throw std::runtime_error("couldn't open file");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <uint32_t BlockSize>
|
template <uint32_t BlockSize>
|
||||||
block_io<BlockSize>::~block_io()
|
block_io<BlockSize>::~block_io()
|
||||||
{
|
{
|
||||||
::close(fd_);
|
if (::close(fd_) < 0)
|
||||||
|
syscall_failed("close");
|
||||||
}
|
}
|
||||||
|
|
||||||
template <uint32_t BlockSize>
|
template <uint32_t BlockSize>
|
||||||
|
@ -29,7 +29,8 @@ namespace {
|
|||||||
unsigned const MAX_HELD_LOCKS = 16;
|
unsigned const MAX_HELD_LOCKS = 16;
|
||||||
|
|
||||||
block_manager<4096>::ptr create_bm(block_address nr = 1024) {
|
block_manager<4096>::ptr create_bm(block_address nr = 1024) {
|
||||||
return block_manager<4096>::ptr(new block_manager<4096>("./test.data", nr, MAX_HELD_LOCKS, true));
|
return block_manager<4096>::ptr(
|
||||||
|
new block_manager<4096>("./test.data", nr, MAX_HELD_LOCKS, block_io<>::READ_WRITE));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <uint32_t BlockSize>
|
template <uint32_t BlockSize>
|
||||||
@ -61,7 +62,8 @@ namespace {
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(bad_path)
|
BOOST_AUTO_TEST_CASE(bad_path)
|
||||||
{
|
{
|
||||||
BOOST_CHECK_THROW(bm4096("/bogus/bogus/bogus", 1234, 4), runtime_error);
|
BOOST_CHECK_THROW(bm4096("/bogus/bogus/bogus", 1234, 4, block_io<>::READ_WRITE),
|
||||||
|
runtime_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(out_of_range_access)
|
BOOST_AUTO_TEST_CASE(out_of_range_access)
|
||||||
@ -110,13 +112,13 @@ BOOST_AUTO_TEST_CASE(write_lock_zero_zeroes)
|
|||||||
BOOST_AUTO_TEST_CASE(different_block_sizes)
|
BOOST_AUTO_TEST_CASE(different_block_sizes)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
bm4096 bm("./test.data", 64, 1);
|
bm4096 bm("./test.data", 64, 1, block_io<>::READ_WRITE);
|
||||||
bm4096::read_ref rr = bm.read_lock(0);
|
bm4096::read_ref rr = bm.read_lock(0);
|
||||||
BOOST_CHECK_EQUAL(sizeof(rr.data()), 4096);
|
BOOST_CHECK_EQUAL(sizeof(rr.data()), 4096);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
block_manager<64 * 1024> bm("./test.data", 64, true);
|
block_manager<64 * 1024> bm("./test.data", 64, 1, block_io<64 * 1024>::READ_WRITE);
|
||||||
block_manager<64 * 1024>::read_ref rr = bm.read_lock(0);
|
block_manager<64 * 1024>::read_ref rr = bm.read_lock(0);
|
||||||
BOOST_CHECK_EQUAL(sizeof(rr.data()), 64 * 1024);
|
BOOST_CHECK_EQUAL(sizeof(rr.data()), 64 * 1024);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user