mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Env class that can randomly read and write
Summary: I have implemented basic simple use case that I need for External Value Store I'm working on. There is a potential for making this prettier by refactoring/combining WritableFile and RandomAccessFile, avoiding some copypasta. However, I decided to implement just the basic functionality, so I can continue working on the other diff. Test Plan: Added a unittest Reviewers: dhruba, haobo, kailiu Reviewed By: haobo CC: leveldb Differential Revision: https://reviews.facebook.net/D13365
This commit is contained in:
@@ -565,7 +565,7 @@ class PosixWritableFile : public WritableFile {
|
||||
}
|
||||
|
||||
virtual Status Append(const Slice& data) {
|
||||
char* src = (char *)data.data();
|
||||
const char* src = data.data();
|
||||
size_t left = data.size();
|
||||
Status s;
|
||||
pending_sync_ = true;
|
||||
@@ -709,6 +709,98 @@ class PosixWritableFile : public WritableFile {
|
||||
#endif
|
||||
};
|
||||
|
||||
class PosixRandomRWFile : public RandomRWFile {
|
||||
private:
|
||||
const std::string filename_;
|
||||
int fd_;
|
||||
bool pending_sync_;
|
||||
bool pending_fsync_;
|
||||
|
||||
public:
|
||||
PosixRandomRWFile(const std::string& fname, int fd,
|
||||
const EnvOptions& options) :
|
||||
filename_(fname),
|
||||
fd_(fd),
|
||||
pending_sync_(false),
|
||||
pending_fsync_(false) {
|
||||
assert(!options.use_mmap_writes && !options.use_mmap_reads);
|
||||
}
|
||||
|
||||
~PosixRandomRWFile() {
|
||||
if (fd_ >= 0) {
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
virtual Status Write(uint64_t offset, const Slice& data) {
|
||||
const char* src = data.data();
|
||||
size_t left = data.size();
|
||||
Status s;
|
||||
pending_sync_ = true;
|
||||
pending_fsync_ = true;
|
||||
|
||||
while (left != 0) {
|
||||
ssize_t done = pwrite(fd_, src, left, offset);
|
||||
if (done < 0) {
|
||||
return IOError(filename_, errno);
|
||||
}
|
||||
|
||||
left -= done;
|
||||
src += done;
|
||||
offset += done;
|
||||
}
|
||||
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
virtual Status Read(uint64_t offset, size_t n, Slice* result,
|
||||
char* scratch) const {
|
||||
Status s;
|
||||
ssize_t r = pread(fd_, scratch, n, static_cast<off_t>(offset));
|
||||
*result = Slice(scratch, (r < 0) ? 0 : r);
|
||||
if (r < 0) {
|
||||
s = IOError(filename_, errno);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
virtual Status Close() {
|
||||
Status s = Status::OK();
|
||||
if (fd_ >= 0 && close(fd_) < 0) {
|
||||
s = IOError(filename_, errno);
|
||||
}
|
||||
fd_ = -1;
|
||||
return s;
|
||||
}
|
||||
|
||||
virtual Status Sync() {
|
||||
if (pending_sync_ && fdatasync(fd_) < 0) {
|
||||
return IOError(filename_, errno);
|
||||
}
|
||||
pending_sync_ = false;
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
virtual Status Fsync() {
|
||||
if (pending_fsync_ && fsync(fd_) < 0) {
|
||||
return IOError(filename_, errno);
|
||||
}
|
||||
pending_fsync_ = false;
|
||||
pending_sync_ = false;
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
#ifdef OS_LINUX
|
||||
virtual Status Allocate(off_t offset, off_t len) {
|
||||
if (!fallocate(fd_, FALLOC_FL_KEEP_SIZE, offset, len)) {
|
||||
return Status::OK();
|
||||
} else {
|
||||
return IOError(filename_, errno);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
static int LockOrUnlock(const std::string& fname, int fd, bool lock) {
|
||||
mutex_lockedFiles.Lock();
|
||||
if (lock) {
|
||||
@@ -855,6 +947,25 @@ class PosixEnv : public Env {
|
||||
return s;
|
||||
}
|
||||
|
||||
virtual Status NewRandomRWFile(const std::string& fname,
|
||||
unique_ptr<RandomRWFile>* result,
|
||||
const EnvOptions& options) {
|
||||
result->reset();
|
||||
Status s;
|
||||
const int fd = open(fname.c_str(), O_CREAT | O_RDWR, 0644);
|
||||
if (fd < 0) {
|
||||
s = IOError(fname, errno);
|
||||
} else {
|
||||
SetFD_CLOEXEC(fd, &options);
|
||||
// no support for mmap yet
|
||||
if (options.use_mmap_writes || options.use_mmap_reads) {
|
||||
return Status::NotSupported("No support for mmap read/write yet");
|
||||
}
|
||||
result->reset(new PosixRandomRWFile(fname, fd, options));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
virtual bool FileExists(const std::string& fname) {
|
||||
return access(fname.c_str(), F_OK) == 0;
|
||||
}
|
||||
|
||||
@@ -357,6 +357,25 @@ TEST(EnvPosixTest, InvalidateCache) {
|
||||
ASSERT_OK(env_->DeleteFile(fname));
|
||||
}
|
||||
|
||||
TEST(EnvPosixTest, PosixRandomRWFileTest) {
|
||||
EnvOptions soptions;
|
||||
soptions.use_mmap_writes = soptions.use_mmap_reads = false;
|
||||
std::string fname = test::TmpDir() + "/" + "testfile";
|
||||
|
||||
unique_ptr<RandomRWFile> file;
|
||||
ASSERT_OK(env_->NewRandomRWFile(fname, &file, soptions));
|
||||
ASSERT_OK(file.get()->Allocate(0, 10*1024*1024));
|
||||
ASSERT_OK(file.get()->Write(100, Slice("Hello world")));
|
||||
ASSERT_OK(file.get()->Write(105, Slice("Hello world")));
|
||||
ASSERT_OK(file.get()->Sync());
|
||||
ASSERT_OK(file.get()->Fsync());
|
||||
char scratch[100];
|
||||
Slice result;
|
||||
ASSERT_OK(file.get()->Read(100, 16, &result, scratch));
|
||||
ASSERT_EQ(result.compare("HelloHello world"), 0);
|
||||
ASSERT_OK(file.get()->Close());
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
Reference in New Issue
Block a user