• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "net/tools/dump_cache/simple_cache_dumper.h"
6 
7 #include "base/at_exit.h"
8 #include "base/command_line.h"
9 #include "base/logging.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/message_loop/message_loop_proxy.h"
13 #include "base/threading/thread.h"
14 #include "net/base/cache_type.h"
15 #include "net/base/io_buffer.h"
16 #include "net/base/net_errors.h"
17 #include "net/disk_cache/disk_cache.h"
18 #include "net/tools/dump_cache/cache_dumper.h"
19 
20 namespace net {
21 
SimpleCacheDumper(base::FilePath input_path,base::FilePath output_path)22 SimpleCacheDumper::SimpleCacheDumper(base::FilePath input_path,
23                                      base::FilePath output_path)
24     : state_(STATE_NONE),
25       input_path_(input_path),
26       output_path_(output_path),
27       writer_(new DiskDumper(output_path)),
28       cache_thread_(new base::Thread("CacheThead")),
29       iter_(NULL),
30       src_entry_(NULL),
31       dst_entry_(NULL),
32       io_callback_(base::Bind(&SimpleCacheDumper::OnIOComplete,
33                               base::Unretained(this))),
34       rv_(0) {
35 }
36 
~SimpleCacheDumper()37 SimpleCacheDumper::~SimpleCacheDumper() {
38 }
39 
Run()40 int SimpleCacheDumper::Run() {
41   base::MessageLoopForIO main_message_loop;
42 
43   LOG(INFO) << "Reading cache from: " << input_path_.value();
44   LOG(INFO) << "Writing cache to: " << output_path_.value();
45 
46   if (!cache_thread_->StartWithOptions(
47           base::Thread::Options(base::MessageLoop::TYPE_IO, 0))) {
48     LOG(ERROR) << "Unable to start thread";
49     return ERR_UNEXPECTED;
50   }
51   state_ = STATE_CREATE_CACHE;
52   int rv = DoLoop(OK);
53   if (rv == ERR_IO_PENDING) {
54     main_message_loop.Run();
55     return rv_;
56   }
57   return rv;
58 }
59 
DoLoop(int rv)60 int SimpleCacheDumper::DoLoop(int rv) {
61   do {
62     State state = state_;
63     state_ = STATE_NONE;
64     switch (state) {
65       case STATE_CREATE_CACHE:
66         CHECK_EQ(OK, rv);
67         rv = DoCreateCache();
68         break;
69       case STATE_CREATE_CACHE_COMPLETE:
70         rv = DoCreateCacheComplete(rv);
71         break;
72       case STATE_OPEN_ENTRY:
73         CHECK_EQ(OK, rv);
74         rv = DoOpenEntry();
75         break;
76       case STATE_OPEN_ENTRY_COMPLETE:
77         rv = DoOpenEntryComplete(rv);
78         break;
79       case STATE_CREATE_ENTRY:
80         CHECK_EQ(OK, rv);
81         rv = DoCreateEntry();
82         break;
83       case STATE_CREATE_ENTRY_COMPLETE:
84         rv = DoCreateEntryComplete(rv);
85         break;
86       case STATE_READ_HEADERS:
87         CHECK_EQ(OK, rv);
88         rv = DoReadHeaders();
89         break;
90       case STATE_READ_HEADERS_COMPLETE:
91         rv = DoReadHeadersComplete(rv);
92         break;
93       case STATE_WRITE_HEADERS:
94         CHECK_EQ(OK, rv);
95         rv = DoWriteHeaders();
96         break;
97       case STATE_WRITE_HEADERS_COMPLETE:
98         rv = DoWriteHeadersComplete(rv);
99         break;
100       case STATE_READ_BODY:
101         CHECK_EQ(OK, rv);
102         rv = DoReadBody();
103         break;
104       case STATE_READ_BODY_COMPLETE:
105         rv = DoReadBodyComplete(rv);
106         break;
107       case STATE_WRITE_BODY:
108         CHECK_EQ(OK, rv);
109         rv = DoWriteBody();
110         break;
111       case STATE_WRITE_BODY_COMPLETE:
112         rv = DoWriteBodyComplete(rv);
113         break;
114       default:
115         NOTREACHED() << "state_: " << state_;
116         break;
117     }
118   } while (state_ != STATE_NONE && rv != ERR_IO_PENDING);
119   return rv;
120 }
121 
DoCreateCache()122 int SimpleCacheDumper::DoCreateCache() {
123   DCHECK(!cache_);
124   state_ = STATE_CREATE_CACHE_COMPLETE;
125   return disk_cache::CreateCacheBackend(
126       DISK_CACHE,
127       CACHE_BACKEND_DEFAULT,
128       input_path_,
129       0,
130       false,
131       cache_thread_->message_loop_proxy().get(),
132       NULL,
133       &cache_,
134       io_callback_);
135 }
136 
DoCreateCacheComplete(int rv)137 int SimpleCacheDumper::DoCreateCacheComplete(int rv) {
138   if (rv < 0)
139     return rv;
140 
141   reinterpret_cast<disk_cache::BackendImpl*>(cache_.get())->SetUpgradeMode();
142   reinterpret_cast<disk_cache::BackendImpl*>(cache_.get())->SetFlags(
143       disk_cache::kNoRandom);
144 
145   state_ = STATE_OPEN_ENTRY;
146   return OK;
147 }
148 
DoOpenEntry()149 int SimpleCacheDumper::DoOpenEntry() {
150   DCHECK(!dst_entry_);
151   DCHECK(!src_entry_);
152   state_ = STATE_OPEN_ENTRY_COMPLETE;
153   return cache_->OpenNextEntry(&iter_, &src_entry_, io_callback_);
154 }
155 
DoOpenEntryComplete(int rv)156 int SimpleCacheDumper::DoOpenEntryComplete(int rv) {
157   // ERR_FAILED indicates iteration finished.
158   if (rv == ERR_FAILED) {
159     cache_->EndEnumeration(&iter_);
160     return OK;
161   }
162 
163   if (rv < 0)
164     return rv;
165 
166   state_ = STATE_CREATE_ENTRY;
167   return OK;
168 }
169 
DoCreateEntry()170 int SimpleCacheDumper::DoCreateEntry() {
171   DCHECK(!dst_entry_);
172   state_ = STATE_CREATE_ENTRY_COMPLETE;
173 
174   return writer_->CreateEntry(src_entry_->GetKey(), &dst_entry_,
175                               io_callback_);
176 }
177 
DoCreateEntryComplete(int rv)178 int SimpleCacheDumper::DoCreateEntryComplete(int rv) {
179   if (rv < 0)
180     return rv;
181 
182   state_ = STATE_READ_HEADERS;
183   return OK;
184 }
185 
DoReadHeaders()186 int SimpleCacheDumper::DoReadHeaders() {
187   state_ = STATE_READ_HEADERS_COMPLETE;
188   int32 size = src_entry_->GetDataSize(0);
189   buf_ = new IOBufferWithSize(size);
190   return src_entry_->ReadData(0, 0, buf_.get(), size, io_callback_);
191 }
192 
DoReadHeadersComplete(int rv)193 int SimpleCacheDumper::DoReadHeadersComplete(int rv) {
194   if (rv < 0)
195     return rv;
196 
197   state_ = STATE_WRITE_HEADERS;
198   return OK;
199 }
200 
DoWriteHeaders()201 int SimpleCacheDumper::DoWriteHeaders() {
202   int rv = writer_->WriteEntry(
203       dst_entry_, 0, 0, buf_.get(), buf_->size(), io_callback_);
204   if (rv == 0)
205     return ERR_FAILED;
206 
207   state_ = STATE_WRITE_HEADERS_COMPLETE;
208   return OK;
209 }
210 
DoWriteHeadersComplete(int rv)211 int SimpleCacheDumper::DoWriteHeadersComplete(int rv) {
212   if (rv < 0)
213     return rv;
214 
215   state_ = STATE_READ_BODY;
216   return OK;
217 }
218 
DoReadBody()219 int SimpleCacheDumper::DoReadBody() {
220   state_ = STATE_READ_BODY_COMPLETE;
221   int32 size = src_entry_->GetDataSize(1);
222   // If the body is empty, we can neither read nor write it, so
223   // just move to the next.
224   if (size <= 0) {
225     state_ = STATE_WRITE_BODY_COMPLETE;
226     return OK;
227   }
228   buf_ = new IOBufferWithSize(size);
229   return src_entry_->ReadData(1, 0, buf_.get(), size, io_callback_);
230 }
231 
DoReadBodyComplete(int rv)232 int SimpleCacheDumper::DoReadBodyComplete(int rv) {
233   if (rv < 0)
234     return rv;
235 
236   state_ = STATE_WRITE_BODY;
237   return OK;
238 }
239 
DoWriteBody()240 int SimpleCacheDumper::DoWriteBody() {
241   int rv = writer_->WriteEntry(
242       dst_entry_, 1, 0, buf_.get(), buf_->size(), io_callback_);
243   if (rv == 0)
244     return ERR_FAILED;
245 
246   state_ = STATE_WRITE_BODY_COMPLETE;
247   return OK;
248 }
249 
DoWriteBodyComplete(int rv)250 int SimpleCacheDumper::DoWriteBodyComplete(int rv) {
251   if (rv < 0)
252     return rv;
253 
254   src_entry_->Close();
255   writer_->CloseEntry(dst_entry_, base::Time::Now(), base::Time::Now());
256   src_entry_ = NULL;
257   dst_entry_ = NULL;
258 
259   state_ = STATE_OPEN_ENTRY;
260   return OK;
261 }
262 
OnIOComplete(int rv)263 void SimpleCacheDumper::OnIOComplete(int rv) {
264   rv = DoLoop(rv);
265 
266   if (rv != ERR_IO_PENDING) {
267     rv_ = rv;
268     cache_.reset();
269     base::MessageLoop::current()->Quit();
270   }
271 }
272 
273 }  // namespace net
274