@ -0,0 +1,96 @@ | |||||
#include "vlog_reader.h" | |||||
#include "leveldb/env.h" | |||||
#include "util/coding.h" | |||||
namespace leveldb { | |||||
namespace log { | |||||
VlogReader::VlogReader(SequentialFile *file, Reporter* reporter) | |||||
: file_(file), | |||||
file_random_(nullptr), | |||||
reporter_(reporter), | |||||
backing_store_(new char[kBlockSize]), | |||||
buffer_(), | |||||
eof_(false), | |||||
last_record_offset_(0) {} | |||||
VlogReader::VlogReader(RandomAccessFile *file, Reporter* reporter) | |||||
: file_(nullptr), | |||||
file_random_(file), | |||||
reporter_(reporter), | |||||
backing_store_(new char[kBlockSize]), | |||||
buffer_(), | |||||
eof_(false), | |||||
last_record_offset_(0) {} | |||||
VlogReader::~VlogReader() { delete[] backing_store_; } | |||||
bool VlogReader::ReadValue(uint64_t offset, size_t length, Slice *key_value, char *scratch) { | |||||
if (file_random_ == nullptr) { | |||||
return false; | |||||
} | |||||
Status status = file_random_->Read(offset, length, key_value, scratch); | |||||
if (!status.ok()) { | |||||
return false; | |||||
} | |||||
return true; | |||||
} | |||||
bool VlogReader::ReadRecord(Slice *record, std::string *scratch) { | |||||
if (ReadPhysicalRecord(scratch)) { | |||||
*record = *scratch; | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
uint64_t VlogReader::LastRecordOffset() const { | |||||
return last_record_offset_; | |||||
} | |||||
void VlogReader::ReportCorruption(uint64_t bytes, const Status &reason) { | |||||
if (reporter_ != nullptr) { | |||||
reporter_->Corruption(static_cast<size_t>(bytes), reason); | |||||
} | |||||
} | |||||
bool VlogReader::ReadPhysicalRecord(std::string *result) { | |||||
result->clear(); | |||||
buffer_.clear(); | |||||
char* tmp_head = new char[vHeaderSize]; | |||||
Status status = file_->Read(vHeaderSize, &buffer_, tmp_head); | |||||
if (!status.ok()) { | |||||
buffer_.clear(); | |||||
ReportCorruption(kBlockSize, status); | |||||
eof_ = true; | |||||
return false; | |||||
} else if (buffer_.size() < vHeaderSize) { | |||||
eof_ = true; | |||||
} | |||||
if (!eof_) { | |||||
result->assign(buffer_.data(),buffer_.size()); | |||||
uint32_t length = DecodeFixed32(buffer_.data()); | |||||
buffer_.clear(); | |||||
char* tmp = new char[length]; | |||||
status = file_->Read(length, &buffer_, tmp); | |||||
if (status.ok() && buffer_.size() == length) { | |||||
*result += buffer_.ToString(); | |||||
} else { | |||||
eof_ = true; | |||||
} | |||||
delete [] tmp; | |||||
} | |||||
delete [] tmp_head; | |||||
if (eof_) { | |||||
result->clear(); | |||||
return false; | |||||
} | |||||
return true; | |||||
} | |||||
} // namespace log | |||||
} // namespace leveldb |
@ -1,96 +0,0 @@ | |||||
#include "vlog_reader.h" | |||||
#include "leveldb/env.h" | |||||
#include "util/coding.h" | |||||
namespace leveldb { | |||||
namespace log { | |||||
VlogReader::VlogReader(SequentialFile *file, Reporter* reporter) | |||||
: file_(file), | |||||
file_random_(nullptr), | |||||
reporter_(reporter), | |||||
backing_store_(new char[kBlockSize]), | |||||
buffer_(), | |||||
eof_(false), | |||||
last_record_offset_(0) {} | |||||
VlogReader::VlogReader(RandomAccessFile *file, Reporter* reporter) | |||||
: file_(nullptr), | |||||
file_random_(file), | |||||
reporter_(reporter), | |||||
backing_store_(new char[kBlockSize]), | |||||
buffer_(), | |||||
eof_(false), | |||||
last_record_offset_(0) {} | |||||
VlogReader::~VlogReader() { delete[] backing_store_; } | |||||
bool VlogReader::ReadValue(uint64_t offset, size_t length, Slice *key_value, char *scratch) { | |||||
if (file_random_ == nullptr) { | |||||
return false; | |||||
} | |||||
Status status = file_random_->Read(offset, length, key_value, scratch); | |||||
if (!status.ok()) { | |||||
return false; | |||||
} | |||||
return true; | |||||
} | |||||
bool VlogReader::ReadRecord(Slice *record, std::string *scratch) { | |||||
if (ReadPhysicalRecord(scratch)) { | |||||
*record = *scratch; | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
uint64_t VlogReader::LastRecordOffset() const { | |||||
return last_record_offset_; | |||||
} | |||||
void VlogReader::ReportCorruption(uint64_t bytes, const Status &reason) { | |||||
if (reporter_ != nullptr) { | |||||
reporter_->Corruption(static_cast<size_t>(bytes), reason); | |||||
} | |||||
} | |||||
bool VlogReader::ReadPhysicalRecord(std::string *result) { | |||||
result->clear(); | |||||
buffer_.clear(); | |||||
char* tmp_head = new char[vHeaderSize]; | |||||
Status status = file_->Read(vHeaderSize, &buffer_, tmp_head); | |||||
if (!status.ok()) { | |||||
buffer_.clear(); | |||||
ReportCorruption(kBlockSize, status); | |||||
eof_ = true; | |||||
return false; | |||||
} else if (buffer_.size() < vHeaderSize) { | |||||
eof_ = true; | |||||
} | |||||
if (!eof_) { | |||||
result->assign(buffer_.data(),buffer_.size()); | |||||
uint32_t length = DecodeFixed32(buffer_.data()); | |||||
buffer_.clear(); | |||||
char* tmp = new char[length]; | |||||
status = file_->Read(length, &buffer_, tmp); | |||||
if (status.ok() && buffer_.size() == length) { | |||||
*result += buffer_.ToString(); | |||||
} else { | |||||
eof_ = true; | |||||
} | |||||
delete [] tmp; | |||||
} | |||||
delete [] tmp_head; | |||||
if (eof_) { | |||||
result->clear(); | |||||
return false; | |||||
} | |||||
return true; | |||||
} | |||||
} // namespace log | |||||
} // namespace leveldb |
@ -0,0 +1,42 @@ | |||||
#include "db/vlog_writer.h" | |||||
#include <cstdint> | |||||
#include "leveldb/env.h" | |||||
#include "util/coding.h" | |||||
namespace leveldb { | |||||
namespace log { | |||||
VlogWriter::VlogWriter(WritableFile* dest) : dest_(dest), head_(0) {} | |||||
VlogWriter::VlogWriter(WritableFile* dest, uint64_t dest_length) | |||||
: dest_(dest), head_(0) {} | |||||
Status VlogWriter::AddRecord(const Slice& slice, uint64_t& offset) { | |||||
const char* ptr = slice.data(); | |||||
size_t left = slice.size(); | |||||
Status s; | |||||
s = EmitPhysicalRecord(ptr, left, offset); | |||||
return s; | |||||
} | |||||
Status VlogWriter::EmitPhysicalRecord(const char* ptr, size_t length, | |||||
uint64_t& offset) { | |||||
assert(length <= 0xffff); | |||||
char buf[4]; | |||||
EncodeFixed32(buf, length); | |||||
Status s = dest_->Append(Slice(buf, 4)); | |||||
if (s.ok()) { | |||||
s = dest_->Append(Slice(ptr, length)); | |||||
if (s.ok()) { | |||||
s = dest_->Flush(); | |||||
offset = head_ + 4; | |||||
head_ += 4 + length; | |||||
} | |||||
} | |||||
return s; | |||||
} | |||||
} // namespace log | |||||
} // namespace leveldb |
@ -0,0 +1,44 @@ | |||||
#ifndef LEVELDB_DB_VLOG_WRITER_H_ | |||||
#define LEVELDB_DB_VLOG_WRITER_H_ | |||||
#include "db/log_format.h" | |||||
#include <cstdint> | |||||
#include "leveldb/slice.h" | |||||
#include "leveldb/status.h" | |||||
namespace leveldb { | |||||
class WritableFile; | |||||
namespace log { | |||||
class VlogWriter { | |||||
public: | |||||
// Create a writer that will append data to "*dest". | |||||
// "*dest" must be initially empty. | |||||
// "*dest" must remain live while this Writer is in use. | |||||
explicit VlogWriter(WritableFile* dest); | |||||
// Create a writer that will append data to "*dest". | |||||
// "*dest" must have initial length "dest_length". | |||||
// "*dest" must remain live while this Writer is in use. | |||||
VlogWriter(WritableFile* dest, uint64_t dest_length); | |||||
VlogWriter(const VlogWriter&) = delete; | |||||
VlogWriter& operator=(const VlogWriter&) = delete; | |||||
~VlogWriter() = default; | |||||
Status AddRecord(const Slice& slice, uint64_t& offset); | |||||
private: | |||||
Status EmitPhysicalRecord(const char* ptr, size_t length, uint64_t& offset); | |||||
size_t head_; | |||||
WritableFile* dest_; | |||||
}; | |||||
} // namespace log | |||||
} // namespace leveldb | |||||
#endif // LEVELDB_DB_VLOG_WRITER_H_ |