| @ -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_ | |||