7#include <packager/file/threaded_io_file.h>
15#include <absl/log/check.h>
16#include <absl/log/log.h>
17#include <absl/synchronization/mutex.h>
19#include <packager/file.h>
20#include <packager/file/file_closer.h>
21#include <packager/file/thread_pool.h>
25ThreadedIoFile::ThreadedIoFile(std::unique_ptr<File, FileCloser> internal_file,
27 uint64_t io_cache_size,
28 uint64_t io_block_size)
29 : File(internal_file->file_name()),
30 internal_file_(std::move(internal_file)),
32 cache_(io_cache_size),
33 io_buffer_(io_block_size),
37 internal_file_error_(0),
39 flush_complete_(false),
41 DCHECK(internal_file_);
44ThreadedIoFile::~ThreadedIoFile() {}
46bool ThreadedIoFile::Open() {
47 DCHECK(internal_file_);
49 if (!internal_file_->Open())
53 size_ = internal_file_->Size();
55 ThreadPool::instance.PostTask(std::bind(&ThreadedIoFile::TaskHandler,
this));
59bool ThreadedIoFile::Close() {
60 DCHECK(internal_file_);
63 if (mode_ == kOutputMode)
67 WaitForSignal(&task_exited_mutex_, &task_exited_);
69 result &= internal_file_.release()->Close();
74int64_t ThreadedIoFile::Read(
void* buffer, uint64_t length) {
75 DCHECK(internal_file_);
76 DCHECK_EQ(kInputMode, mode_);
78 if (eof_.load(std::memory_order_relaxed) && !cache_.BytesCached())
81 if (internal_file_error_.load(std::memory_order_relaxed))
82 return internal_file_error_.load(std::memory_order_relaxed);
84 uint64_t bytes_read = cache_.Read(buffer, length);
85 position_ += bytes_read;
90int64_t ThreadedIoFile::Write(
const void* buffer, uint64_t length) {
91 DCHECK(internal_file_);
92 DCHECK_EQ(kOutputMode, mode_);
94 if (internal_file_error_.load(std::memory_order_relaxed))
95 return internal_file_error_.load(std::memory_order_relaxed);
97 uint64_t bytes_written = cache_.Write(buffer, length);
98 position_ += bytes_written;
99 if (position_ > size_)
102 return bytes_written;
105void ThreadedIoFile::CloseForWriting() {}
107int64_t ThreadedIoFile::Size() {
108 DCHECK(internal_file_);
113bool ThreadedIoFile::Flush() {
114 DCHECK(internal_file_);
115 DCHECK_EQ(kOutputMode, mode_);
117 if (internal_file_error_.load(std::memory_order_relaxed))
121 absl::MutexLock lock(flush_mutex_);
123 flush_complete_ =
false;
127 WaitForSignal(&flush_mutex_, &flush_complete_);
129 return internal_file_->Flush();
132bool ThreadedIoFile::Seek(uint64_t position) {
133 if (mode_ == kOutputMode) {
137 if (!internal_file_->Seek(position))
143 WaitForSignal(&task_exited_mutex_, &task_exited_);
145 bool result = internal_file_->Seek(position);
148 if (!internal_file_->Seek(position_) && (position != position_)) {
149 LOG(WARNING) <<
"Seek failed. ThreadedIoFile left in invalid state.";
155 ThreadPool::instance.PostTask(
156 std::bind(&ThreadedIoFile::TaskHandler,
this));
160 position_ = position;
164bool ThreadedIoFile::Tell(uint64_t* position) {
167 *position = position_;
171void ThreadedIoFile::TaskHandler() {
173 absl::MutexLock lock(task_exited_mutex_);
174 task_exited_ =
false;
177 if (mode_ == kInputMode)
183 absl::MutexLock lock(task_exited_mutex_);
188void ThreadedIoFile::RunInInputMode() {
189 DCHECK(internal_file_);
190 DCHECK_EQ(kInputMode, mode_);
193 int64_t read_result =
194 internal_file_->Read(&io_buffer_[0], io_buffer_.size());
195 if (read_result <= 0) {
196 eof_.store(read_result == 0, std::memory_order_relaxed);
197 internal_file_error_.store(read_result, std::memory_order_relaxed);
201 if (cache_.Write(&io_buffer_[0], read_result) == 0) {
207void ThreadedIoFile::RunInOutputMode() {
208 DCHECK(internal_file_);
209 DCHECK_EQ(kOutputMode, mode_);
212 uint64_t write_bytes = cache_.Read(&io_buffer_[0], io_buffer_.size());
213 if (write_bytes == 0) {
214 absl::MutexLock lock(flush_mutex_);
218 flush_complete_ =
true;
223 uint64_t bytes_written(0);
224 while (bytes_written < write_bytes) {
225 int64_t write_result = internal_file_->Write(
226 &io_buffer_[bytes_written], write_bytes - bytes_written);
227 if (write_result < 0) {
228 internal_file_error_.store(write_result, std::memory_order_relaxed);
231 absl::MutexLock lock(flush_mutex_);
234 flush_complete_ =
true;
238 bytes_written += write_result;
244void ThreadedIoFile::WaitForSignal(absl::Mutex* mutex,
bool* condition) {
249 mutex->LockWhen(absl::Condition(condition));
All the methods that are virtual are virtual for mocking.