Add a CREATE mode to the block_io class.

This commit is contained in:
Joe Thornber 2013-01-15 02:33:09 +00:00
parent 779f8e1fd4
commit fb1ad01e19
3 changed files with 84 additions and 14 deletions

View File

@ -85,6 +85,7 @@ namespace persistent_data {
enum mode {
READ_ONLY,
READ_WRITE,
CREATE
};
block_io(std::string const &path, block_address nr_blocks, mode m);

View File

@ -23,6 +23,8 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <boost/bind.hpp>
#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>
block_io<BlockSize>::block_io(std::string const &path, block_address nr_blocks, mode m)
: nr_blocks_(nr_blocks),
mode_(m)
{
int fd_mode = O_DIRECT | O_SYNC;
off_t file_size = nr_blocks * BlockSize;
switch (m) {
case READ_ONLY:
fd_mode |= O_RDONLY;
fd_ = open_block_file(path, file_size, false);
break;
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;
default:
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>
block_io<BlockSize>::~block_io()
{
::close(fd_);
if (::close(fd_) < 0)
syscall_failed("close");
}
template <uint32_t BlockSize>

View File

@ -29,7 +29,8 @@ namespace {
unsigned const MAX_HELD_LOCKS = 16;
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>
@ -61,7 +62,8 @@ namespace {
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)
@ -110,13 +112,13 @@ BOOST_AUTO_TEST_CASE(write_lock_zero_zeroes)
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);
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);
BOOST_CHECK_EQUAL(sizeof(rr.data()), 64 * 1024);
}