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