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 {
|
||||
READ_ONLY,
|
||||
READ_WRITE,
|
||||
CREATE
|
||||
};
|
||||
|
||||
block_io(std::string const &path, block_address nr_blocks, mode m);
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user