7 #include "packager/file/threaded_io_file.h"
9 #include "packager/base/bind.h"
10 #include "packager/base/bind_helpers.h"
11 #include "packager/base/location.h"
12 #include "packager/base/threading/worker_pool.h"
16 ThreadedIoFile::ThreadedIoFile(std::unique_ptr<File, FileCloser> internal_file,
18 uint64_t io_cache_size,
19 uint64_t io_block_size)
20 : File(internal_file->file_name()),
21 internal_file_(std::move(internal_file)),
23 cache_(io_cache_size),
24 io_buffer_(io_block_size),
29 flush_complete_event_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
30 base::WaitableEvent::InitialState::NOT_SIGNALED),
31 internal_file_error_(0),
32 task_exit_event_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
33 base::WaitableEvent::InitialState::NOT_SIGNALED) {
34 DCHECK(internal_file_);
37 ThreadedIoFile::~ThreadedIoFile() {}
39 bool ThreadedIoFile::Open() {
40 DCHECK(internal_file_);
42 if (!internal_file_->Open())
46 size_ = internal_file_->Size();
48 base::WorkerPool::PostTask(
50 base::Bind(&ThreadedIoFile::TaskHandler, base::Unretained(
this)),
55 bool ThreadedIoFile::Close() {
56 DCHECK(internal_file_);
59 if (mode_ == kOutputMode)
63 task_exit_event_.Wait();
65 result &= internal_file_.release()->Close();
70 int64_t ThreadedIoFile::Read(
void* buffer, uint64_t length) {
71 DCHECK(internal_file_);
72 DCHECK_EQ(kInputMode, mode_);
74 if (eof_.load(std::memory_order_relaxed) && !cache_.BytesCached())
77 if (internal_file_error_.load(std::memory_order_relaxed))
78 return internal_file_error_.load(std::memory_order_relaxed);
80 uint64_t bytes_read = cache_.Read(buffer, length);
81 position_ += bytes_read;
86 int64_t ThreadedIoFile::Write(
const void* buffer, uint64_t length) {
87 DCHECK(internal_file_);
88 DCHECK_EQ(kOutputMode, mode_);
90 if (internal_file_error_.load(std::memory_order_relaxed))
91 return internal_file_error_.load(std::memory_order_relaxed);
93 uint64_t bytes_written = cache_.Write(buffer, length);
94 position_ += bytes_written;
95 if (position_ > size_)
101 int64_t ThreadedIoFile::Size() {
102 DCHECK(internal_file_);
107 bool ThreadedIoFile::Flush() {
108 DCHECK(internal_file_);
109 DCHECK_EQ(kOutputMode, mode_);
111 if (internal_file_error_.load(std::memory_order_relaxed))
116 flush_complete_event_.Wait();
117 return internal_file_->Flush();
120 bool ThreadedIoFile::Seek(uint64_t position) {
121 if (mode_ == kOutputMode) {
125 if (!internal_file_->Seek(position))
131 task_exit_event_.Wait();
132 bool result = internal_file_->Seek(position);
135 if (!internal_file_->Seek(position_) && (position != position_)) {
136 LOG(WARNING) <<
"Seek failed. ThreadedIoFile left in invalid state.";
141 base::WorkerPool::PostTask(
143 base::Bind(&ThreadedIoFile::TaskHandler, base::Unretained(
this)),
148 position_ = position;
152 bool ThreadedIoFile::Tell(uint64_t* position) {
155 *position = position_;
159 void ThreadedIoFile::TaskHandler() {
160 if (mode_ == kInputMode)
164 task_exit_event_.Signal();
167 void ThreadedIoFile::RunInInputMode() {
168 DCHECK(internal_file_);
169 DCHECK_EQ(kInputMode, mode_);
172 int64_t read_result =
173 internal_file_->Read(&io_buffer_[0], io_buffer_.size());
174 if (read_result <= 0) {
175 eof_.store(read_result == 0, std::memory_order_relaxed);
176 internal_file_error_.store(read_result, std::memory_order_relaxed);
180 if (cache_.Write(&io_buffer_[0], read_result) == 0) {
186 void ThreadedIoFile::RunInOutputMode() {
187 DCHECK(internal_file_);
188 DCHECK_EQ(kOutputMode, mode_);
191 uint64_t write_bytes = cache_.Read(&io_buffer_[0], io_buffer_.size());
192 if (write_bytes == 0) {
196 flush_complete_event_.Signal();
201 uint64_t bytes_written(0);
202 while (bytes_written < write_bytes) {
203 int64_t write_result = internal_file_->Write(
204 &io_buffer_[bytes_written], write_bytes - bytes_written);
205 if (write_result < 0) {
206 internal_file_error_.store(write_result, std::memory_order_relaxed);
210 flush_complete_event_.Signal();
214 bytes_written += write_result;
All the methods that are virtual are virtual for mocking.