1a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// found in the LICENSE file.
4a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chrome/browser/media_galleries/fileapi/readahead_file_stream_reader.h"
6a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
7a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include <algorithm>
8a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
9a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/message_loop/message_loop.h"
10a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/numerics/safe_conversions.h"
11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/base/io_buffer.h"
12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/base/net_errors.h"
13a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)using storage::FileStreamReader;
15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace {
17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
18a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const size_t kDesiredNumberOfBuffers = 2;  // So we are always one buffer ahead.
19a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const int kBufferSize = 1024*1024;  // 1MB to minimize transaction costs.
20a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
21a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}  // namespace
22a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
23a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)ReadaheadFileStreamReader::ReadaheadFileStreamReader(FileStreamReader* source)
24a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    : source_(source),
25a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      source_error_(0),
26a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      source_has_pending_read_(false),
27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      weak_factory_(this) {
28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)ReadaheadFileStreamReader::~ReadaheadFileStreamReader() {}
31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)int ReadaheadFileStreamReader::Read(
33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    net::IOBuffer* buf, int buf_len, const net::CompletionCallback& callback) {
34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(!pending_sink_buffer_.get());
35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(pending_read_callback_.is_null());
36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ReadFromSourceIfNeeded();
38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_refptr<net::DrainableIOBuffer> sink =
40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      new net::DrainableIOBuffer(buf, buf_len);
411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  int result = FinishReadFromCacheOrStoredError(sink.get());
42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
43a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // We are waiting for an source read to complete, so save the request.
44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (result == net::ERR_IO_PENDING) {
45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DCHECK(!pending_sink_buffer_.get());
46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DCHECK(pending_read_callback_.is_null());
47a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    pending_sink_buffer_ = sink;
48a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    pending_read_callback_ = callback;
49a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return result;
52a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)int64 ReadaheadFileStreamReader::GetLength(
55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const net::Int64CompletionCallback& callback) {
56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return source_->GetLength(callback);
57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)int ReadaheadFileStreamReader::FinishReadFromCacheOrStoredError(
60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    net::DrainableIOBuffer* sink) {
61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // If we don't have any ready cache, return the pending read code, or
62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // the stored error code.
63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (buffers_.empty()) {
64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (source_.get()) {
65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      DCHECK(source_has_pending_read_);
66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return net::ERR_IO_PENDING;
67a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    } else {
68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return source_error_;
69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  while (sink->BytesRemaining() > 0 && !buffers_.empty()) {
73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    net::DrainableIOBuffer* source_buffer = buffers_.front().get();
74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DCHECK(source_buffer->BytesRemaining() > 0);
76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    int copy_len = std::min(source_buffer->BytesRemaining(),
78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                            sink->BytesRemaining());
79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    std::copy(source_buffer->data(), source_buffer->data() + copy_len,
80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)              sink->data());
81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    source_buffer->DidConsume(copy_len);
83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    sink->DidConsume(copy_len);
84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (source_buffer->BytesRemaining() == 0) {
86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      buffers_.pop();
87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      // Get a new buffer to replace the one we just used up.
89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      ReadFromSourceIfNeeded();
90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return sink->BytesConsumed();
94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void ReadaheadFileStreamReader::ReadFromSourceIfNeeded() {
97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!source_.get() || source_has_pending_read_ ||
98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      buffers_.size() >= kDesiredNumberOfBuffers) {
99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
102a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  source_has_pending_read_ = true;
103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kBufferSize));
105a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  int result = source_->Read(
1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      buf.get(),
107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      kBufferSize,
108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::Bind(&ReadaheadFileStreamReader::OnFinishReadFromSource,
1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 weak_factory_.GetWeakPtr(),
1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 buf));
111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (result != net::ERR_IO_PENDING)
1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    OnFinishReadFromSource(buf.get(), result);
114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void ReadaheadFileStreamReader::OnFinishReadFromSource(net::IOBuffer* buf,
117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                                       int result) {
118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(result != net::ERR_IO_PENDING);
119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(source_has_pending_read_);
120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  source_has_pending_read_ = false;
121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Either store the data read from |source_|, or store the error code.
123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (result > 0) {
124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_refptr<net::DrainableIOBuffer> drainable_buffer(
125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        new net::DrainableIOBuffer(buf, result));
126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    buffers_.push(drainable_buffer);
127a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    ReadFromSourceIfNeeded();
128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  } else {
129a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    source_.reset();
130a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    source_error_ = result;
131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
133a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // If there's a read request waiting for the source FileStreamReader to
134a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // finish reading, fulfill that request now from the cache or stored error.
135a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (pending_sink_buffer_.get()) {
136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DCHECK(!pending_read_callback_.is_null());
137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // Free the pending callback before running it, as the callback often
139a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // dispatches another read.
140a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_refptr<net::DrainableIOBuffer> sink = pending_sink_buffer_;
141a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    pending_sink_buffer_ = NULL;
142a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    net::CompletionCallback completion_callback = pending_read_callback_;
143a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    pending_read_callback_.Reset();
144a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    completion_callback.Run(FinishReadFromCacheOrStoredError(sink.get()));
146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
147a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
148