Refactor: add LineFileReader and Status::MustCheck (#8026)
Summary: Removed confusing, awkward, and undocumented internal API ReadOneLine and replaced with very simple LineFileReader. In refactoring backupable_db.cc, this has the side benefit of removing the arbitrary cap on the size of backup metadata files. Also added Status::MustCheck to make it easy to mark a Status as "must check." Using this, I can ensure that after LineFileReader::ReadLine returns false the caller checks GetStatus(). Also removed some excessive conditional compilation in status.h Pull Request resolved: https://github.com/facebook/rocksdb/pull/8026 Test Plan: added unit test, and running tests with ASSERT_STATUS_CHECKED Reviewed By: mrambacher Differential Revision: D26831687 Pulled By: pdillinger fbshipit-source-id: ef749c265a7a26bb13cd44f6f0f97db2955f6f0fmain
parent
847ca9f964
commit
4b18c46d10
@ -0,0 +1,65 @@ |
||||
// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
#include "file/line_file_reader.h" |
||||
|
||||
#include <cstring> |
||||
|
||||
namespace ROCKSDB_NAMESPACE { |
||||
|
||||
Status LineFileReader::Create(const std::shared_ptr<FileSystem>& fs, |
||||
const std::string& fname, |
||||
const FileOptions& file_opts, |
||||
std::unique_ptr<LineFileReader>* reader, |
||||
IODebugContext* dbg) { |
||||
std::unique_ptr<FSSequentialFile> file; |
||||
Status s = fs->NewSequentialFile(fname, file_opts, &file, dbg); |
||||
if (s.ok()) { |
||||
reader->reset(new LineFileReader(std::move(file), fname)); |
||||
} |
||||
return s; |
||||
} |
||||
|
||||
bool LineFileReader::ReadLine(std::string* out) { |
||||
assert(out); |
||||
if (!status_.ok()) { |
||||
// Status should be checked (or permit unchecked) any time we return false.
|
||||
status_.MustCheck(); |
||||
return false; |
||||
} |
||||
out->clear(); |
||||
for (;;) { |
||||
// Look for line delimiter
|
||||
const char* found = static_cast<const char*>( |
||||
std::memchr(buf_begin_, '\n', buf_end_ - buf_begin_)); |
||||
if (found) { |
||||
size_t len = found - buf_begin_; |
||||
out->append(buf_begin_, len); |
||||
buf_begin_ += len + /*delim*/ 1; |
||||
++line_number_; |
||||
return true; |
||||
} |
||||
if (at_eof_) { |
||||
status_.MustCheck(); |
||||
return false; |
||||
} |
||||
// else flush and reload buffer
|
||||
out->append(buf_begin_, buf_end_ - buf_begin_); |
||||
Slice result; |
||||
status_ = sfr_.Read(buf_.size(), &result, buf_.data()); |
||||
if (!status_.ok()) { |
||||
status_.MustCheck(); |
||||
return false; |
||||
} |
||||
if (result.size() != buf_.size()) { |
||||
// The obscure way of indicating EOF
|
||||
at_eof_ = true; |
||||
} |
||||
buf_begin_ = result.data(); |
||||
buf_end_ = result.data() + result.size(); |
||||
} |
||||
} |
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
@ -0,0 +1,59 @@ |
||||
// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
#pragma once |
||||
#include <array> |
||||
|
||||
#include "file/sequence_file_reader.h" |
||||
|
||||
namespace ROCKSDB_NAMESPACE { |
||||
|
||||
// A wrapper on top of Env::SequentialFile for reading text lines from a file.
|
||||
// Lines are delimited by '\n'. The last line may or may not include a
|
||||
// trailing newline. Uses SequentialFileReader internally.
|
||||
class LineFileReader { |
||||
private: |
||||
std::array<char, 8192> buf_; |
||||
SequentialFileReader sfr_; |
||||
Status status_; |
||||
const char* buf_begin_ = buf_.data(); |
||||
const char* buf_end_ = buf_.data(); |
||||
size_t line_number_ = 0; |
||||
bool at_eof_ = false; |
||||
|
||||
public: |
||||
// See SequentialFileReader constructors
|
||||
template <typename... Args> |
||||
explicit LineFileReader(Args&&... args) |
||||
: sfr_(std::forward<Args&&>(args)...) {} |
||||
|
||||
static Status Create(const std::shared_ptr<FileSystem>& fs, |
||||
const std::string& fname, const FileOptions& file_opts, |
||||
std::unique_ptr<LineFileReader>* reader, |
||||
IODebugContext* dbg); |
||||
|
||||
LineFileReader(const LineFileReader&) = delete; |
||||
LineFileReader& operator=(const LineFileReader&) = delete; |
||||
|
||||
// Reads another line from the file, returning true on success and saving
|
||||
// the line to `out`, without delimiter, or returning false on failure. You
|
||||
// must check GetStatus() to determine whether the failure was just
|
||||
// end-of-file (OK status) or an I/O error (another status).
|
||||
bool ReadLine(std::string* out); |
||||
|
||||
// Returns the number of the line most recently returned from ReadLine.
|
||||
// Return value is unspecified if ReadLine has returned false due to
|
||||
// I/O error. After ReadLine returns false due to end-of-file, return
|
||||
// value is the last returned line number, or equivalently the total
|
||||
// number of lines returned.
|
||||
size_t GetLineNumber() const { return line_number_; } |
||||
|
||||
// Returns any error encountered during read. The error is considered
|
||||
// permanent and no retry or recovery is attempted with the same
|
||||
// LineFileReader.
|
||||
const Status& GetStatus() const { return status_; } |
||||
}; |
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
Loading…
Reference in new issue