OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2008 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 "base/logging.h" |
| 6 #include "base/message_loop.h" |
| 7 #include "base/string_util.h" |
| 8 #include "net/disk_cache/backend_impl.h" |
| 9 #include "net/disk_cache/entry_impl.h" |
| 10 |
| 11 namespace { |
| 12 |
| 13 const wchar_t kPipePrefix[] = L"\\\\.\\pipe\\dump_cache_"; |
| 14 const int kChannelSize = 64 * 1024; |
| 15 const int kNumStreams = 2; |
| 16 |
| 17 // Simple macro to print out formatted debug messages. It is similar to a DLOG |
| 18 // except that it doesn't include a header. |
| 19 #ifdef NDEBUG |
| 20 #define DEBUGMSG(...) {} |
| 21 #else |
| 22 #define DEBUGMSG(...) { printf(__VA_ARGS__); } |
| 23 #endif |
| 24 |
| 25 HANDLE OpenServer(const std::wstring pipe_number) { |
| 26 std::wstring pipe_name(kPipePrefix); |
| 27 pipe_name.append(pipe_number); |
| 28 return CreateFile(pipe_name.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, |
| 29 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); |
| 30 } |
| 31 |
| 32 // This is the basic message to use between the two processes. It is intended |
| 33 // to transmit a single action (like "get the key name for entry xx"), with up |
| 34 // to 5 32-bit arguments and 4 64-bit arguments. After this structure, the rest |
| 35 // of the message has |buffer_bytes| of length with the actual data. |
| 36 struct Message { |
| 37 int32 command; |
| 38 int32 result; |
| 39 int32 buffer_bytes; |
| 40 int32 arg1; |
| 41 int32 arg2; |
| 42 int32 arg3; |
| 43 int32 arg4; |
| 44 int32 arg5; |
| 45 int64 long_arg1; |
| 46 int64 long_arg2; |
| 47 int64 long_arg3; |
| 48 int64 long_arg4; |
| 49 Message() { |
| 50 memset(this, 0, sizeof(*this)); |
| 51 } |
| 52 Message& operator= (const Message& other) { |
| 53 memcpy(this, &other, sizeof(*this)); |
| 54 return *this; |
| 55 } |
| 56 }; |
| 57 |
| 58 const int kBufferSize = kChannelSize - sizeof(Message); |
| 59 struct IoBuffer { |
| 60 Message msg; |
| 61 char buffer[kBufferSize]; |
| 62 }; |
| 63 COMPILE_ASSERT(sizeof(IoBuffer) == kChannelSize, invalid_io_buffer); |
| 64 |
| 65 |
| 66 // The list of commands. |
| 67 // Currently, there is support for working ONLY with one entry at a time. |
| 68 enum { |
| 69 // Get the entry from list |arg1| that follows |long_arg1|. |
| 70 // The result is placed on |long_arg1| (closes the previous one). |
| 71 GET_NEXT_ENTRY = 1, |
| 72 // Get the entry from list |arg1| that precedes |long_arg1|. |
| 73 // The result is placed on |long_arg1| (closes the previous one). |
| 74 GET_PREV_ENTRY, |
| 75 // Closes the entry |long_arg1|. |
| 76 CLOSE_ENTRY, |
| 77 // Get the key of the entry |long_arg1|. |
| 78 GET_KEY, |
| 79 // Get last used (long_arg2) and last modified (long_arg3) times for the |
| 80 // entry at |long_arg1|. |
| 81 GET_USE_TIMES, |
| 82 // Returns on |arg2| the data size in bytes if the stream |arg1| of entry at |
| 83 // |long_arg1|. |
| 84 GET_DATA_SIZE, |
| 85 // Returns |arg2| bytes of the stream |arg1| for the entry at |long_arg1|, |
| 86 // starting at offset |arg3|. |
| 87 READ_DATA, |
| 88 // End processing requests. |
| 89 QUIT |
| 90 }; |
| 91 |
| 92 // The list of return codes. |
| 93 enum { |
| 94 RESULT_OK = 0, |
| 95 RESULT_UNKNOWN_COMMAND, |
| 96 RESULT_INVALID_PARAMETER, |
| 97 RESULT_NAME_OVERFLOW |
| 98 }; |
| 99 |
| 100 // ----------------------------------------------------------------------- |
| 101 |
| 102 class BaseSM : public MessageLoopForIO::IOHandler { |
| 103 public: |
| 104 BaseSM(disk_cache::BackendImpl* cache, HANDLE channel); |
| 105 virtual ~BaseSM(); |
| 106 |
| 107 protected: |
| 108 bool SendMsg(const Message& msg); |
| 109 bool ReceiveMsg(); |
| 110 bool ConnectChannel(); |
| 111 bool IsPending(); |
| 112 |
| 113 MessageLoopForIO::IOContext in_context_; |
| 114 MessageLoopForIO::IOContext out_context_; |
| 115 disk_cache::BackendImpl* cache_; |
| 116 disk_cache::EntryImpl* entry_; |
| 117 HANDLE channel_; |
| 118 int state_; |
| 119 int pending_count_; |
| 120 scoped_array<char> in_buffer_; |
| 121 scoped_array<char> out_buffer_; |
| 122 IoBuffer* input_; |
| 123 IoBuffer* output_; |
| 124 DISALLOW_COPY_AND_ASSIGN(BaseSM); |
| 125 }; |
| 126 |
| 127 BaseSM::BaseSM(disk_cache::BackendImpl* cache, HANDLE channel) |
| 128 : cache_(cache), entry_(NULL), channel_(channel), state_(0), |
| 129 pending_count_(0) { |
| 130 in_buffer_.reset(new char[kChannelSize]); |
| 131 out_buffer_.reset(new char[kChannelSize]); |
| 132 input_ = reinterpret_cast<IoBuffer*>(in_buffer_.get()); |
| 133 output_ = reinterpret_cast<IoBuffer*>(out_buffer_.get()); |
| 134 |
| 135 memset(&in_context_, 0, sizeof(in_context_)); |
| 136 memset(&out_context_, 0, sizeof(out_context_)); |
| 137 in_context_.handler = this; |
| 138 out_context_.handler = this; |
| 139 MessageLoopForIO::current()->RegisterIOHandler(channel_, this); |
| 140 } |
| 141 |
| 142 BaseSM::~BaseSM() { |
| 143 if (entry_) |
| 144 entry_->Close(); |
| 145 } |
| 146 |
| 147 bool BaseSM::SendMsg(const Message& msg) { |
| 148 // Only one command will be in-flight at a time. Let's start the Read IO here |
| 149 // when we know that it will be pending. |
| 150 if (!ReceiveMsg()) |
| 151 return false; |
| 152 |
| 153 output_->msg = msg; |
| 154 DWORD written; |
| 155 if (!WriteFile(channel_, output_, sizeof(msg) + msg.buffer_bytes, &written, |
| 156 &out_context_.overlapped)) { |
| 157 if (ERROR_IO_PENDING != GetLastError()) |
| 158 return false; |
| 159 } |
| 160 pending_count_++; |
| 161 return true; |
| 162 } |
| 163 |
| 164 bool BaseSM::ReceiveMsg() { |
| 165 DWORD read; |
| 166 if (!ReadFile(channel_, input_, kChannelSize, &read, |
| 167 &in_context_.overlapped)) { |
| 168 if (ERROR_IO_PENDING != GetLastError()) |
| 169 return false; |
| 170 } |
| 171 pending_count_++; |
| 172 return true; |
| 173 } |
| 174 |
| 175 bool BaseSM::ConnectChannel() { |
| 176 if (!ConnectNamedPipe(channel_, &in_context_.overlapped)) { |
| 177 DWORD error = GetLastError(); |
| 178 if (ERROR_PIPE_CONNECTED == error) |
| 179 return true; |
| 180 // By returning true in case of a generic error, we allow the operation to |
| 181 // fail while sending the first message. |
| 182 if (ERROR_IO_PENDING != error) |
| 183 return true; |
| 184 } |
| 185 pending_count_++; |
| 186 return false; |
| 187 } |
| 188 |
| 189 bool BaseSM::IsPending() { |
| 190 return pending_count_ != 0; |
| 191 } |
| 192 |
| 193 // ----------------------------------------------------------------------- |
| 194 |
| 195 class MasterSM : public BaseSM { |
| 196 public: |
| 197 MasterSM(disk_cache::BackendImpl* cache, HANDLE channel) |
| 198 : BaseSM(cache, channel) {} |
| 199 virtual ~MasterSM() {} |
| 200 |
| 201 bool DoInit(); |
| 202 virtual void OnIOCompleted(MessageLoopForIO::IOContext* context, |
| 203 DWORD bytes_transfered, DWORD error); |
| 204 |
| 205 private: |
| 206 enum { |
| 207 MASTER_INITIAL = 0, |
| 208 MASTER_CONNECT, |
| 209 MASTER_GET_ENTRY, |
| 210 MASTER_GET_NEXT_ENTRY, |
| 211 MASTER_GET_KEY, |
| 212 MASTER_GET_USE_TIMES, |
| 213 MASTER_GET_DATA_SIZE, |
| 214 MASTER_READ_DATA, |
| 215 MASTER_END |
| 216 }; |
| 217 |
| 218 void SendGetPrevEntry(); |
| 219 void DoGetEntry(); |
| 220 void DoGetKey(int bytes_read); |
| 221 void DoGetUseTimes(); |
| 222 void SendGetDataSize(); |
| 223 void DoGetDataSize(); |
| 224 void CloseEntry(); |
| 225 void SendReadData(); |
| 226 void DoReadData(int bytes_read); |
| 227 void SendQuit(); |
| 228 void DoEnd(); |
| 229 void Fail(); |
| 230 |
| 231 base::Time last_used_; |
| 232 base::Time last_modified_; |
| 233 int64 remote_entry_; |
| 234 int stream_; |
| 235 int bytes_remaining_; |
| 236 int offset_; |
| 237 int copied_entries_; |
| 238 }; |
| 239 |
| 240 void MasterSM::OnIOCompleted(MessageLoopForIO::IOContext* context, |
| 241 DWORD bytes_transfered, DWORD error) { |
| 242 pending_count_--; |
| 243 if (context == &out_context_) { |
| 244 if (!error) |
| 245 return; |
| 246 return Fail(); |
| 247 } |
| 248 |
| 249 int bytes_read = static_cast<int>(bytes_transfered); |
| 250 if (bytes_read < sizeof(Message) && state_ != MASTER_END && |
| 251 state_ != MASTER_CONNECT) { |
| 252 printf("Communication breakdown\n"); |
| 253 return Fail(); |
| 254 } |
| 255 |
| 256 switch (state_) { |
| 257 case MASTER_CONNECT: |
| 258 SendGetPrevEntry(); |
| 259 break; |
| 260 case MASTER_GET_ENTRY: |
| 261 DoGetEntry(); |
| 262 break; |
| 263 case MASTER_GET_KEY: |
| 264 DoGetKey(bytes_read); |
| 265 break; |
| 266 case MASTER_GET_USE_TIMES: |
| 267 DoGetUseTimes(); |
| 268 break; |
| 269 case MASTER_GET_DATA_SIZE: |
| 270 DoGetDataSize(); |
| 271 break; |
| 272 case MASTER_READ_DATA: |
| 273 DoReadData(bytes_read); |
| 274 break; |
| 275 case MASTER_END: |
| 276 if (!IsPending()) |
| 277 DoEnd(); |
| 278 break; |
| 279 default: |
| 280 NOTREACHED(); |
| 281 break; |
| 282 } |
| 283 } |
| 284 |
| 285 bool MasterSM::DoInit() { |
| 286 DEBUGMSG("Master DoInit\n"); |
| 287 DCHECK(state_ == MASTER_INITIAL); |
| 288 |
| 289 copied_entries_ = 0; |
| 290 remote_entry_ = 0; |
| 291 |
| 292 if (ConnectChannel()) { |
| 293 SendGetPrevEntry(); |
| 294 // If we don't have pending operations we couldn't connect. |
| 295 return IsPending(); |
| 296 } |
| 297 |
| 298 state_ = MASTER_CONNECT; |
| 299 return true; |
| 300 } |
| 301 |
| 302 void MasterSM::SendGetPrevEntry() { |
| 303 DEBUGMSG("Master SendGetPrevEntry\n"); |
| 304 state_ = MASTER_GET_ENTRY; |
| 305 Message msg; |
| 306 msg.command = GET_PREV_ENTRY; |
| 307 msg.long_arg1 = remote_entry_; |
| 308 SendMsg(msg); |
| 309 } |
| 310 |
| 311 void MasterSM::DoGetEntry() { |
| 312 DEBUGMSG("Master DoGetEntry\n"); |
| 313 DCHECK(state_ == MASTER_GET_ENTRY); |
| 314 DCHECK(input_->msg.command == GET_PREV_ENTRY); |
| 315 if (input_->msg.result != RESULT_OK) |
| 316 return Fail(); |
| 317 |
| 318 if (!input_->msg.long_arg1) { |
| 319 printf("Done: %d entries copied over.\n", copied_entries_); |
| 320 return SendQuit(); |
| 321 } |
| 322 remote_entry_ = input_->msg.long_arg1; |
| 323 state_ = MASTER_GET_KEY; |
| 324 Message msg; |
| 325 msg.command = GET_KEY; |
| 326 msg.long_arg1 = remote_entry_; |
| 327 SendMsg(msg); |
| 328 } |
| 329 |
| 330 void MasterSM::DoGetKey(int bytes_read) { |
| 331 DEBUGMSG("Master DoGetKey\n"); |
| 332 DCHECK(state_ == MASTER_GET_KEY); |
| 333 DCHECK(input_->msg.command == GET_KEY); |
| 334 if (input_->msg.result == RESULT_NAME_OVERFLOW) |
| 335 // The key is too long. Just move on. |
| 336 return SendGetPrevEntry(); |
| 337 |
| 338 if (input_->msg.result != RESULT_OK) |
| 339 return Fail(); |
| 340 |
| 341 std::string key(input_->buffer); |
| 342 DCHECK(key.size() == input_->msg.buffer_bytes - 1); |
| 343 if (!cache_->CreateEntry(key, reinterpret_cast<disk_cache::Entry**>(&entry_))) |
| 344 return Fail(); |
| 345 |
| 346 if (key.size() < 60) { |
| 347 DEBUGMSG("Entry \"%s\" created\n", key.c_str()); |
| 348 } else { |
| 349 DEBUGMSG("Entry (long name) created\n", key.c_str()); |
| 350 } |
| 351 state_ = MASTER_GET_USE_TIMES; |
| 352 Message msg; |
| 353 msg.command = GET_USE_TIMES; |
| 354 msg.long_arg1 = remote_entry_; |
| 355 SendMsg(msg); |
| 356 } |
| 357 |
| 358 void MasterSM::DoGetUseTimes() { |
| 359 DEBUGMSG("Master DoGetUseTimes\n"); |
| 360 DCHECK(state_ == MASTER_GET_USE_TIMES); |
| 361 DCHECK(input_->msg.command == GET_USE_TIMES); |
| 362 if (input_->msg.result != RESULT_OK) |
| 363 return Fail(); |
| 364 |
| 365 last_used_ = base::Time::FromInternalValue(input_->msg.long_arg2); |
| 366 last_modified_ = base::Time::FromInternalValue(input_->msg.long_arg3); |
| 367 stream_ = 0; |
| 368 SendGetDataSize(); |
| 369 } |
| 370 |
| 371 void MasterSM::SendGetDataSize() { |
| 372 DEBUGMSG("Master SendGetDataSize (%d)\n", stream_); |
| 373 state_ = MASTER_GET_DATA_SIZE; |
| 374 Message msg; |
| 375 msg.command = GET_DATA_SIZE; |
| 376 msg.arg1 = stream_; |
| 377 msg.long_arg1 = remote_entry_; |
| 378 SendMsg(msg); |
| 379 } |
| 380 |
| 381 void MasterSM::DoGetDataSize() { |
| 382 DEBUGMSG("Master DoGetDataSize: %d\n", input_->msg.arg2); |
| 383 DCHECK(state_ == MASTER_GET_DATA_SIZE); |
| 384 DCHECK(input_->msg.command == GET_DATA_SIZE); |
| 385 if (input_->msg.result == RESULT_INVALID_PARAMETER) |
| 386 // No more streams, move to the next entry. |
| 387 return CloseEntry(); |
| 388 |
| 389 if (input_->msg.result != RESULT_OK) |
| 390 return Fail(); |
| 391 |
| 392 bytes_remaining_ = input_->msg.arg2; |
| 393 offset_ = 0; |
| 394 SendReadData(); |
| 395 } |
| 396 |
| 397 void MasterSM::CloseEntry() { |
| 398 DEBUGMSG("Master CloseEntry\n"); |
| 399 printf("%c\r", copied_entries_ % 2 ? 'x' : '+'); |
| 400 entry_->SetTimes(last_used_, last_modified_); |
| 401 entry_->Close(); |
| 402 entry_ = NULL; |
| 403 copied_entries_++; |
| 404 SendGetPrevEntry(); |
| 405 } |
| 406 |
| 407 void MasterSM::SendReadData() { |
| 408 int read_size = std::min(bytes_remaining_, kBufferSize); |
| 409 DEBUGMSG("Master SendReadData (%d): %d bytes at %d\n", stream_, read_size, |
| 410 offset_); |
| 411 if (bytes_remaining_ <= 0) { |
| 412 stream_++; |
| 413 if (stream_ >= kNumStreams) |
| 414 return CloseEntry(); |
| 415 return SendGetDataSize(); |
| 416 } |
| 417 |
| 418 state_ = MASTER_READ_DATA; |
| 419 Message msg; |
| 420 msg.command = READ_DATA; |
| 421 msg.arg1 = stream_; |
| 422 msg.arg2 = read_size; |
| 423 msg.arg3 = offset_; |
| 424 msg.long_arg1 = remote_entry_; |
| 425 SendMsg(msg); |
| 426 } |
| 427 |
| 428 void MasterSM::DoReadData(int bytes_read) { |
| 429 DEBUGMSG("Master DoReadData: %d bytes\n", input_->msg.buffer_bytes); |
| 430 DCHECK(state_ == MASTER_READ_DATA); |
| 431 DCHECK(input_->msg.command == READ_DATA); |
| 432 if (input_->msg.result != RESULT_OK) |
| 433 return Fail(); |
| 434 |
| 435 int read_size = input_->msg.buffer_bytes; |
| 436 if (read_size != entry_->WriteData(stream_, offset_, input_->buffer, |
| 437 read_size, NULL, false)) |
| 438 return Fail(); |
| 439 |
| 440 offset_ += read_size; |
| 441 bytes_remaining_ -= read_size; |
| 442 // Read some more. |
| 443 SendReadData(); |
| 444 } |
| 445 |
| 446 void MasterSM::SendQuit() { |
| 447 DEBUGMSG("Master SendQuit\n"); |
| 448 state_ = MASTER_END; |
| 449 Message msg; |
| 450 msg.command = QUIT; |
| 451 SendMsg(msg); |
| 452 if (!IsPending()) |
| 453 DoEnd(); |
| 454 } |
| 455 |
| 456 void MasterSM::DoEnd() { |
| 457 DEBUGMSG("Master DoEnd\n"); |
| 458 MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); |
| 459 } |
| 460 |
| 461 void MasterSM::Fail() { |
| 462 DEBUGMSG("Master Fail\n"); |
| 463 printf("Unexpected failure\n"); |
| 464 SendQuit(); |
| 465 } |
| 466 |
| 467 // ----------------------------------------------------------------------- |
| 468 |
| 469 class SlaveSM : public BaseSM { |
| 470 public: |
| 471 SlaveSM(disk_cache::BackendImpl* cache, HANDLE channel) |
| 472 : BaseSM(cache, channel), iterator_(NULL) {} |
| 473 virtual ~SlaveSM(); |
| 474 |
| 475 bool DoInit(); |
| 476 virtual void OnIOCompleted(MessageLoopForIO::IOContext* context, |
| 477 DWORD bytes_transfered, DWORD error); |
| 478 |
| 479 private: |
| 480 enum { |
| 481 SLAVE_INITIAL = 0, |
| 482 SLAVE_WAITING, |
| 483 SLAVE_END |
| 484 }; |
| 485 |
| 486 void DoGetNextEntry(); |
| 487 void DoGetPrevEntry(); |
| 488 int32 GetEntryFromList(); |
| 489 void DoCloseEntry(); |
| 490 void DoGetKey(); |
| 491 void DoGetUseTimes(); |
| 492 void DoGetDataSize(); |
| 493 void DoReadData(); |
| 494 void DoEnd(); |
| 495 void Fail(); |
| 496 |
| 497 void* iterator_; |
| 498 }; |
| 499 |
| 500 SlaveSM::~SlaveSM() { |
| 501 if (iterator_) |
| 502 cache_->EndEnumeration(&iterator_); |
| 503 } |
| 504 |
| 505 void SlaveSM::OnIOCompleted(MessageLoopForIO::IOContext* context, |
| 506 DWORD bytes_transfered, DWORD error) { |
| 507 pending_count_--; |
| 508 if (state_ == SLAVE_END) { |
| 509 if (IsPending()) |
| 510 return; |
| 511 return DoEnd(); |
| 512 } |
| 513 |
| 514 if (context == &out_context_) { |
| 515 if (!error) |
| 516 return; |
| 517 return Fail(); |
| 518 } |
| 519 |
| 520 int bytes_read = static_cast<int>(bytes_transfered); |
| 521 if (bytes_read < sizeof(Message)) { |
| 522 printf("Communication breakdown\n"); |
| 523 return Fail(); |
| 524 } |
| 525 DCHECK(state_ == SLAVE_WAITING); |
| 526 |
| 527 switch (input_->msg.command) { |
| 528 case GET_NEXT_ENTRY: |
| 529 DoGetNextEntry(); |
| 530 break; |
| 531 case GET_PREV_ENTRY: |
| 532 DoGetPrevEntry(); |
| 533 break; |
| 534 case CLOSE_ENTRY: |
| 535 DoCloseEntry(); |
| 536 break; |
| 537 case GET_KEY: |
| 538 DoGetKey(); |
| 539 break; |
| 540 case GET_USE_TIMES: |
| 541 DoGetUseTimes(); |
| 542 break; |
| 543 case GET_DATA_SIZE: |
| 544 DoGetDataSize(); |
| 545 break; |
| 546 case READ_DATA: |
| 547 DoReadData(); |
| 548 break; |
| 549 case QUIT: |
| 550 DoEnd(); |
| 551 break; |
| 552 default: |
| 553 NOTREACHED(); |
| 554 break; |
| 555 } |
| 556 } |
| 557 |
| 558 bool SlaveSM::DoInit() { |
| 559 DEBUGMSG("\t\t\tSlave DoInit\n"); |
| 560 DCHECK(state_ == SLAVE_INITIAL); |
| 561 state_ = SLAVE_WAITING; |
| 562 return ReceiveMsg(); |
| 563 } |
| 564 |
| 565 void SlaveSM::DoGetNextEntry() { |
| 566 DEBUGMSG("\t\t\tSlave DoGetNextEntry\n"); |
| 567 Message msg; |
| 568 msg.command = GET_NEXT_ENTRY; |
| 569 |
| 570 if (input_->msg.arg1) { |
| 571 // We only support one list. |
| 572 msg.result = RESULT_UNKNOWN_COMMAND; |
| 573 } else { |
| 574 msg.result = GetEntryFromList(); |
| 575 msg.long_arg1 = reinterpret_cast<int64>(entry_); |
| 576 } |
| 577 SendMsg(msg); |
| 578 } |
| 579 |
| 580 void SlaveSM::DoGetPrevEntry() { |
| 581 DEBUGMSG("\t\t\tSlave DoGetPrevEntry\n"); |
| 582 Message msg; |
| 583 msg.command = GET_PREV_ENTRY; |
| 584 |
| 585 if (input_->msg.arg1) { |
| 586 // We only support one list. |
| 587 msg.result = RESULT_UNKNOWN_COMMAND; |
| 588 } else { |
| 589 msg.result = GetEntryFromList(); |
| 590 msg.long_arg1 = reinterpret_cast<int64>(entry_); |
| 591 } |
| 592 SendMsg(msg); |
| 593 } |
| 594 |
| 595 // Move to the next or previous entry on the list. |
| 596 int32 SlaveSM::GetEntryFromList() { |
| 597 DEBUGMSG("\t\t\tSlave GetEntryFromList\n"); |
| 598 if (input_->msg.long_arg1 != reinterpret_cast<int64>(entry_)) |
| 599 return RESULT_INVALID_PARAMETER; |
| 600 |
| 601 // We know that the current iteration is valid. |
| 602 if (entry_) |
| 603 entry_->Close(); |
| 604 |
| 605 bool ret; |
| 606 if (input_->msg.command == GET_NEXT_ENTRY) { |
| 607 ret = cache_->OpenNextEntry(&iterator_, |
| 608 reinterpret_cast<disk_cache::Entry**>(&entry_)); |
| 609 } else { |
| 610 DCHECK(input_->msg.command == GET_PREV_ENTRY); |
| 611 ret = cache_->OpenPrevEntry(&iterator_, |
| 612 reinterpret_cast<disk_cache::Entry**>(&entry_)); |
| 613 } |
| 614 |
| 615 if (!ret) |
| 616 entry_ = NULL; |
| 617 |
| 618 if (!entry_) |
| 619 DEBUGMSG("\t\t\tSlave end of list\n"); |
| 620 |
| 621 return RESULT_OK; |
| 622 } |
| 623 |
| 624 void SlaveSM::DoCloseEntry() { |
| 625 DEBUGMSG("\t\t\tSlave DoCloseEntry\n"); |
| 626 Message msg; |
| 627 msg.command = GET_KEY; |
| 628 |
| 629 if (!entry_ || input_->msg.long_arg1 != reinterpret_cast<int64>(entry_)) { |
| 630 msg.result = RESULT_INVALID_PARAMETER; |
| 631 } else { |
| 632 entry_->Close(); |
| 633 entry_ = NULL; |
| 634 cache_->EndEnumeration(&iterator_); |
| 635 msg.result = RESULT_OK; |
| 636 } |
| 637 SendMsg(msg); |
| 638 } |
| 639 |
| 640 void SlaveSM::DoGetKey() { |
| 641 DEBUGMSG("\t\t\tSlave DoGetKey\n"); |
| 642 Message msg; |
| 643 msg.command = GET_KEY; |
| 644 |
| 645 if (!entry_ || input_->msg.long_arg1 != reinterpret_cast<int64>(entry_)) { |
| 646 msg.result = RESULT_INVALID_PARAMETER; |
| 647 } else { |
| 648 std::string key = entry_->GetKey(); |
| 649 msg.buffer_bytes = std::min(key.size() + 1, |
| 650 static_cast<size_t>(kBufferSize)); |
| 651 memcpy(output_->buffer, key.c_str(), msg.buffer_bytes); |
| 652 if (msg.buffer_bytes != key.size() + 1) { |
| 653 // We don't support moving this entry. Just tell the master. |
| 654 msg.result = RESULT_NAME_OVERFLOW; |
| 655 } else { |
| 656 msg.result = RESULT_OK; |
| 657 } |
| 658 } |
| 659 SendMsg(msg); |
| 660 } |
| 661 |
| 662 void SlaveSM::DoGetUseTimes() { |
| 663 DEBUGMSG("\t\t\tSlave DoGetUseTimes\n"); |
| 664 Message msg; |
| 665 msg.command = GET_USE_TIMES; |
| 666 |
| 667 if (!entry_ || input_->msg.long_arg1 != reinterpret_cast<int64>(entry_)) { |
| 668 msg.result = RESULT_INVALID_PARAMETER; |
| 669 } else { |
| 670 msg.long_arg2 = entry_->GetLastUsed().ToInternalValue(); |
| 671 msg.long_arg3 = entry_->GetLastModified().ToInternalValue(); |
| 672 msg.result = RESULT_OK; |
| 673 } |
| 674 SendMsg(msg); |
| 675 } |
| 676 |
| 677 void SlaveSM::DoGetDataSize() { |
| 678 DEBUGMSG("\t\t\tSlave DoGetDataSize\n"); |
| 679 Message msg; |
| 680 msg.command = GET_DATA_SIZE; |
| 681 |
| 682 int stream = input_->msg.arg1; |
| 683 if (!entry_ || input_->msg.long_arg1 != reinterpret_cast<int64>(entry_) || |
| 684 stream < 0 || stream >= kNumStreams) { |
| 685 msg.result = RESULT_INVALID_PARAMETER; |
| 686 } else { |
| 687 msg.arg1 = stream; |
| 688 msg.arg2 = entry_->GetDataSize(stream); |
| 689 msg.result = RESULT_OK; |
| 690 } |
| 691 SendMsg(msg); |
| 692 } |
| 693 |
| 694 void SlaveSM::DoReadData() { |
| 695 DEBUGMSG("\t\t\tSlave DoReadData\n"); |
| 696 Message msg; |
| 697 msg.command = READ_DATA; |
| 698 |
| 699 int stream = input_->msg.arg1; |
| 700 int size = input_->msg.arg2; |
| 701 if (!entry_ || input_->msg.long_arg1 != reinterpret_cast<int64>(entry_) || |
| 702 stream < 0 || stream > 1 || size > kBufferSize) { |
| 703 msg.result = RESULT_INVALID_PARAMETER; |
| 704 } else { |
| 705 int ret = entry_->ReadData(stream, input_->msg.arg3, output_->buffer, size, |
| 706 NULL); |
| 707 |
| 708 msg.buffer_bytes = (ret < 0) ? 0 : ret; |
| 709 msg.result = RESULT_OK; |
| 710 } |
| 711 SendMsg(msg); |
| 712 } |
| 713 |
| 714 void SlaveSM::DoEnd() { |
| 715 DEBUGMSG("\t\t\tSlave DoEnd\n"); |
| 716 MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); |
| 717 } |
| 718 |
| 719 void SlaveSM::Fail() { |
| 720 DEBUGMSG("\t\t\tSlave Fail\n"); |
| 721 printf("Unexpected failure\n"); |
| 722 state_ = SLAVE_END; |
| 723 if (IsPending()) { |
| 724 CancelIo(channel_); |
| 725 } else { |
| 726 DoEnd(); |
| 727 } |
| 728 } |
| 729 |
| 730 } // namespace. |
| 731 |
| 732 // ----------------------------------------------------------------------- |
| 733 |
| 734 HANDLE CreateServer(std::wstring* pipe_number) { |
| 735 std::wstring pipe_name(kPipePrefix); |
| 736 srand(static_cast<int>(base::Time::Now().ToInternalValue())); |
| 737 *pipe_number = IntToWString(rand()); |
| 738 pipe_name.append(*pipe_number); |
| 739 |
| 740 DWORD mode = PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | |
| 741 FILE_FLAG_OVERLAPPED; |
| 742 |
| 743 return CreateNamedPipe(pipe_name.c_str(), mode, 0, 1, kChannelSize, |
| 744 kChannelSize, 0, NULL); |
| 745 } |
| 746 |
| 747 // This is the controller process for an upgrade operation. |
| 748 int Upgrade(const std::wstring output_path, HANDLE pipe) { |
| 749 MessageLoop loop(MessageLoop::TYPE_IO); |
| 750 disk_cache::BackendImpl cache(output_path); |
| 751 if (!cache.Init()) { |
| 752 printf("Unable to initialize new files\n"); |
| 753 return -1; |
| 754 } |
| 755 |
| 756 MasterSM master(&cache, pipe); |
| 757 if (!master.DoInit()) { |
| 758 printf("Unable to talk with the helper\n"); |
| 759 return -1; |
| 760 } |
| 761 |
| 762 loop.Run(); |
| 763 return 0; |
| 764 } |
| 765 |
| 766 // This process will only execute commands from the controller. |
| 767 int RunSlave(const std::wstring input_path, const std::wstring pipe_number) { |
| 768 MessageLoop loop(MessageLoop::TYPE_IO); |
| 769 |
| 770 ScopedHandle pipe(OpenServer(pipe_number)); |
| 771 if (!pipe.IsValid()) { |
| 772 printf("Unable to open the server pipe\n"); |
| 773 return -1; |
| 774 } |
| 775 |
| 776 disk_cache::BackendImpl cache(input_path); |
| 777 if (!cache.Init()) { |
| 778 printf("Unable to open cache files\n"); |
| 779 return -1; |
| 780 } |
| 781 cache.SetUpgradeMode(); |
| 782 |
| 783 SlaveSM slave(&cache, pipe); |
| 784 if (!slave.DoInit()) { |
| 785 printf("Unable to talk with the main process\n"); |
| 786 return -1; |
| 787 } |
| 788 |
| 789 loop.Run(); |
| 790 return 0; |
| 791 } |
OLD | NEW |