Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1100)

Unified Diff: net/disk_cache/v3/backend_worker.cc

Issue 17507006: Disk cache v3 ref2 Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Incl IndexTable cl Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « net/disk_cache/v3/backend_worker.h ('k') | net/disk_cache/v3/block_bitmaps.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/disk_cache/v3/backend_worker.cc
===================================================================
--- net/disk_cache/v3/backend_worker.cc (revision 232523)
+++ net/disk_cache/v3/backend_worker.cc (working copy)
@@ -2,42 +2,32 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "net/disk_cache/backend_impl.h"
+#include "net/disk_cache/v3/backend_worker.h"
#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/file_util.h"
-#include "base/files/file_path.h"
-#include "base/hash.h"
#include "base/message_loop/message_loop.h"
-#include "base/metrics/field_trial.h"
-#include "base/metrics/histogram.h"
-#include "base/metrics/stats_counters.h"
-#include "base/rand_util.h"
-#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
-#include "base/sys_info.h"
-#include "base/threading/thread_restrictions.h"
-#include "base/time/time.h"
-#include "base/timer/timer.h"
#include "net/base/net_errors.h"
#include "net/disk_cache/cache_util.h"
-#include "net/disk_cache/entry_impl.h"
#include "net/disk_cache/errors.h"
#include "net/disk_cache/experiments.h"
-#include "net/disk_cache/file.h"
+#include "net/disk_cache/mapped_file.h"
+#include "net/disk_cache/v3/backend_work_item.h"
+#include "net/disk_cache/v3/disk_format_v3.h"
-// This has to be defined before including histogram_macros.h from this file.
-#define NET_DISK_CACHE_BACKEND_IMPL_CC_
-#include "net/disk_cache/histogram_macros.h"
-
using base::Time;
using base::TimeDelta;
using base::TimeTicks;
namespace {
-const char* kIndexName = "index";
+const char kIndexName[] = "index";
+const char kIndexBackupName[] = "index_bak";
+const char kTable1Name[] = "index_tb1";
+const char kTable2Name[] = "index_tb2";
+const char kTable2TempName[] = "index_tb2_tmp";
+const int kMaxOldFolders = 100;
// Seems like ~240 MB correspond to less than 50k entries for 99% of the people.
// Note that the actual target is to keep the index table load factor under 55%
@@ -68,31 +58,28 @@
}
size_t GetIndexSize(int table_len) {
- size_t table_size = sizeof(disk_cache::CacheAddr) * table_len;
- return sizeof(disk_cache::IndexHeader) + table_size;
+ //
+ //size_t table_size = sizeof(disk_cache::CacheAddr) * table_len;
+ //return sizeof(disk_cache::IndexHeaderV3) + table_size;
+ return 0;
}
+size_t GetIndexBitmapSize(int table_len) {
+ DCHECK_LT(table_len, 1 << 22);
+ size_t base_bits = disk_cache::kBaseBitmapBytes * 8;
+ if (table_len < static_cast<int>(base_bits))
+ return sizeof(disk_cache::IndexBitmap);
+
+ size_t extra_pages = (table_len / 8) - disk_cache::kBaseBitmapBytes;
+ extra_pages = (extra_pages + 4095) / 4096;
+ return sizeof(disk_cache::IndexBitmap) + extra_pages * 4096;
+}
+
// ------------------------------------------------------------------------
// Sets group for the current experiment. Returns false if the files should be
// discarded.
-bool InitExperiment(disk_cache::IndexHeader* header, bool cache_created) {
- if (header->experiment == disk_cache::EXPERIMENT_OLD_FILE1 ||
- header->experiment == disk_cache::EXPERIMENT_OLD_FILE2) {
- // Discard current cache.
- return false;
- }
-
- if (base::FieldTrialList::FindFullName("SimpleCacheTrial") ==
- "ExperimentControl") {
- if (cache_created) {
- header->experiment = disk_cache::EXPERIMENT_SIMPLE_CONTROL;
- return true;
- } else if (header->experiment != disk_cache::EXPERIMENT_SIMPLE_CONTROL) {
- return false;
- }
- }
-
+bool InitExperiment(disk_cache::IndexHeaderV3* header) {
header->experiment = disk_cache::NO_EXPERIMENT;
return true;
}
@@ -103,204 +90,363 @@
namespace disk_cache {
-BackendImpl::BackendImpl(const base::FilePath& path,
- base::MessageLoopProxy* cache_thread,
- net::NetLog* net_log)
- : background_queue_(this, cache_thread),
- path_(path),
- block_files_(path),
- mask_(0),
- max_size_(0),
- up_ticks_(0),
- cache_type_(net::DISK_CACHE),
- uma_report_(0),
- user_flags_(0),
- init_(false),
- restarted_(false),
- unit_test_(false),
- read_only_(false),
- disabled_(false),
- new_eviction_(false),
- first_timer_(true),
- user_load_(false),
- net_log_(net_log),
- done_(true, false),
- ptr_factory_(this) {
+BackendImplV3::Worker::Worker(const base::FilePath& path,
+ base::MessageLoopProxy* main_thread)
+ : path_(path),
+ main_thread_(main_thread),
+ cleanup_work_item_(NULL),
+ init_(false),
+ doubling_index_(false),
+ user_flags_(0) {
}
-int BackendImpl::SyncInit() {
-#if defined(NET_BUILD_STRESS_CACHE)
- // Start evictions right away.
- up_ticks_ = kTrimDelay * 2;
-#endif
+int BackendImplV3::Worker::Init(uint32 flags, scoped_ptr<InitResult>* result) {
DCHECK(!init_);
if (init_)
- return net::ERR_FAILED;
+ return ERR_INIT_FAILED;
+ user_flags_ = flags;
+ result->reset(new InitResult);
+
bool create_files = false;
- if (!InitBackingStore(&create_files)) {
- ReportError(ERR_STORAGE_ERROR);
- return net::ERR_FAILED;
+ if (!InitBackingStore(&create_files))
+ return ERR_STORAGE_ERROR;
+
+ init_ = true;
+ if (!LoadIndex(result->get()))
+ return ERR_INIT_FAILED;
+
+ int rv = ERR_NO_ERROR;
+ IndexHeaderV3* index =
+ reinterpret_cast<IndexHeaderV3*>(index_header_->buffer());
+ if (create_files || !index->num_entries)
+ rv = ERR_CACHE_CREATED;
+
+ if (create_files && (flags & EVICTION_V2)) {
+ index->flags |= CACHE_EVICTION_2;
}
- num_refs_ = num_pending_io_ = max_refs_ = 0;
- entry_count_ = byte_count_ = 0;
+ if (!(flags & BASIC_UNIT_TEST) && !InitExperiment(index))
+ return ERR_INIT_FAILED;
- if (!restarted_) {
- buffer_bytes_ = 0;
- trace_object_ = TraceObject::GetTraceObject();
- // Create a recurrent timer of 30 secs.
- int timer_delay = unit_test_ ? 1000 : 30000;
- timer_.reset(new base::RepeatingTimer<BackendImpl>());
- timer_->Start(FROM_HERE, TimeDelta::FromMilliseconds(timer_delay), this,
- &BackendImpl::OnStatsTimer);
+ if (index->crash != 0)
+ rv = ERR_PREVIOUS_CRASH;
+ index->crash = 1;
+
+ block_files_.reset(new BlockFiles(path_));
+ if (flags & BASIC_UNIT_TEST)
+ block_files_->UseSmallSizeIncrementsForTest();
+
+ if (!block_files_->Init(create_files, kFirstAdditionalBlockFileV3))
+ return ERR_INIT_FAILED;
+
+ block_files_->GetBitmaps(index->max_block_file,
+ &result->get()->block_bitmaps);
+ index->max_block_file = static_cast<int>(result->get()->block_bitmaps.size());
+
+ if (!InitStats(index, result->get()))
+ return ERR_INIT_FAILED;
+
+#if defined(STRESS_CACHE_EXTENDED_VALIDATION)
+ trace_object_->EnableTracing(false);
+ int sc = SelfCheck();
+ if (sc < 0 && sc != ERR_NUM_ENTRIES_MISMATCH)
+ NOTREACHED();
+ trace_object_->EnableTracing(true);
+#endif
+
+ return rv;
+}
+
+int BackendImplV3::Worker::Restart(uint32 flags,
+ scoped_ptr<InitResult>* result) {
+ Trace("Worker::Restart");
+ if (init_) {
+ init_ = false;
}
- init_ = true;
- Trace("Init");
+ CloseFiles();
+ DeleteCache(path_, false);
- if (data_->header.experiment != NO_EXPERIMENT &&
- cache_type_ != net::DISK_CACHE) {
- // No experiment for other caches.
- return net::ERR_FAILED;
+ return Init(flags, result);
+}
+
+int BackendImplV3::Worker::GrowIndex(uint32 flags,
+ scoped_ptr<InitResult>* result) {
+ Trace("Worker::GrowIndex, flags 0x%x", flags);
+ if (!init_)
+ return ERR_OPERATION_FAILED;
+
+ if (flags & WorkItem::WORK_COMPLETE) {
+ index_header_ = big_index_header_;
+ big_index_header_ = NULL;
+ if (big_main_table_) {
+ main_table_ = big_main_table_;
+ big_main_table_ = NULL;
+ }
+ if (!big_extra_temp_table_)
+ extra_table_ = big_extra_table_;
+ big_extra_table_ = NULL;
+
+ // If the index takes time to move the cells, it creates a new work item to
+ // notify completion, which executes this code.
+ if (big_extra_temp_table_)
+ return GrowDone();
+
+ return ERR_NO_ERROR;
}
- if (!(user_flags_ & kNoRandom)) {
- // The unit test controls directly what to test.
- new_eviction_ = (cache_type_ == net::DISK_CACHE);
+ IndexHeaderV3* header =
+ reinterpret_cast<IndexHeaderV3*>(index_header_->buffer());
+
+ int current_main_len = header->table_len / kBaseTableLen * kBaseTableLen;
+ int step_size = std::min(8192, current_main_len / 8);
+ if (user_flags_ & BASIC_UNIT_TEST)
+ step_size = 8;
+ if ((user_flags_ & UNIT_TEST_MODE) && !doubling_index_)
+ step_size = (header->table_len * 3 / 2) & 0x7ffffff0;
+ int new_len = header->table_len + step_size;
+
+ bool double_index = false;
+ if (!doubling_index_) {
+ DCHECK(!big_extra_table_);
+ DCHECK(!big_main_table_);
+ double_index = (new_len / kBaseTableLen !=
+ header->table_len / kBaseTableLen);
}
- if (!CheckIndex()) {
- ReportError(ERR_INIT_FAILED);
- return net::ERR_FAILED;
+ int extra_len = new_len - kBaseTableLen;
+ if (double_index) {
+ // We double the table when the extra table is about to reach the size of
+ // the main table. That means that right after this, the new extra table
+ // should be between 19% and 23% of the main table so we start with 25%.
+ extra_len = std::min(8192, current_main_len / 4);
+ extra_len = (user_flags_ & BASIC_UNIT_TEST) ? 128 : extra_len;
+ int main_len = (header->table_len / kBaseTableLen + 1) * kBaseTableLen;
+ new_len = main_len + extra_len;
+
+ if (!CreateExtraTable(extra_len * kBytesPerCell))
+ return ERR_OPERATION_FAILED;
+
+ if (!main_table_->SetLength(main_len * kBytesPerCell))
+ return ERR_OPERATION_FAILED;
+ } else if (doubling_index_) {
+ if (!big_extra_temp_table_->SetLength(extra_len * kBytesPerCell))
+ return ERR_OPERATION_FAILED;
+ } else {
+ if (!extra_table_->SetLength(extra_len * kBytesPerCell))
+ return ERR_OPERATION_FAILED;
}
- if (!restarted_ && (create_files || !data_->header.num_entries))
- ReportError(ERR_CACHE_CREATED);
+ if (!index_header_->SetLength(GetIndexBitmapSize(new_len)))
+ return ERR_OPERATION_FAILED;
- if (!(user_flags_ & kNoRandom) && cache_type_ == net::DISK_CACHE &&
- !InitExperiment(&data_->header, create_files)) {
- return net::ERR_FAILED;
+ scoped_refptr<MappedFile> big_index_header = new MappedFile();
+ if (!big_index_header->Init(path_.AppendASCII(kIndexName), 0)) {
+ LOG(ERROR) << "Unable to remap index";
+ return ERR_OPERATION_FAILED;
}
- // We don't care if the value overflows. The only thing we care about is that
- // the id cannot be zero, because that value is used as "not dirty".
- // Increasing the value once per second gives us many years before we start
- // having collisions.
- data_->header.this_id++;
- if (!data_->header.this_id)
- data_->header.this_id++;
+ scoped_refptr<MappedFile> big_extra_table = new MappedFile();
+ const char* extra_name = (double_index || doubling_index_) ? kTable2TempName :
+ kTable2Name;
+ if (!big_extra_table->Init(path_.AppendASCII(extra_name), 0)) {
+ LOG(ERROR) << "Unable to remap index_tb2";
+ return ERR_OPERATION_FAILED;
+ }
- bool previous_crash = (data_->header.crash != 0);
- data_->header.crash = 1;
+ if (double_index) {
+ scoped_refptr<MappedFile> big_main_table = new MappedFile();
+ if (!big_main_table->Init(path_.AppendASCII(kTable1Name), 0)) {
+ LOG(ERROR) << "Unable to remap index_tb1";
+ return ERR_OPERATION_FAILED;
+ }
+ big_main_table_.swap(big_main_table);
- if (!block_files_.Init(create_files))
- return net::ERR_FAILED;
-
- // We want to minimize the changes to cache for an AppCache.
- if (cache_type() == net::APP_CACHE) {
- DCHECK(!new_eviction_);
- read_only_ = true;
- } else if (cache_type() == net::SHADER_CACHE) {
- DCHECK(!new_eviction_);
+ // Grab an extra reference to the new extra table that can be used for an
+ // extended period, while the index is being rebuilt. The normal reference
+ // (big_extra_table_) will be released when the work item is completed, but
+ // that doesn't mean the index is done with it.
+ // Note that we are able to process slow grow requests even when the index
+ // is being doubled.
+ big_extra_temp_table_ = big_extra_table;
}
+ big_index_header_.swap(big_index_header);
+ big_extra_table_.swap(big_extra_table);
- eviction_.Init(this);
+ header = reinterpret_cast<IndexHeaderV3*>(big_index_header_->buffer());
+ header->table_len = new_len;
- // stats_ and rankings_ may end up calling back to us so we better be enabled.
- disabled_ = false;
- if (!InitStats())
- return net::ERR_FAILED;
+ result->reset(new InitResult);
+ result->get()->index_data.main_table = NULL;
- disabled_ = !rankings_.Init(this, new_eviction_);
+ result->get()->index_data.index_bitmap =
+ reinterpret_cast<IndexBitmap*>(big_index_header_->buffer());
+ result->get()->index_data.extra_table =
+ reinterpret_cast<IndexBucket*>(big_extra_table_->buffer());
-#if defined(STRESS_CACHE_EXTENDED_VALIDATION)
- trace_object_->EnableTracing(false);
- int sc = SelfCheck();
- if (sc < 0 && sc != ERR_NUM_ENTRIES_MISMATCH)
- NOTREACHED();
- trace_object_->EnableTracing(true);
-#endif
+ if (double_index) {
+ result->get()->index_data.main_table =
+ reinterpret_cast<IndexBucket*>(big_main_table_->buffer());
+ doubling_index_ = true;
+ }
- if (previous_crash) {
- ReportError(ERR_PREVIOUS_CRASH);
- } else if (!restarted_) {
- ReportError(ERR_NO_ERROR);
+ return ERR_NO_ERROR;
+}
+
+int BackendImplV3::Worker::GrowFiles(uint32 flags,
+ scoped_ptr<InitResult>* result) {
+ Trace("Worker::GrowFiles, flags 0x%x", flags);
+ if (!init_)
+ return ERR_OPERATION_FAILED;
+
+ if (flags & WorkItem::WORK_COMPLETE) {
+ block_files_.reset();
+ block_files_.swap(big_block_files_);
+ return ERR_NO_ERROR;
}
- FlushIndex();
+ big_block_files_.reset(new BlockFiles(path_));
+ if (user_flags_ & BASIC_UNIT_TEST)
+ big_block_files_->UseSmallSizeIncrementsForTest();
- return disabled_ ? net::ERR_FAILED : net::OK;
+ if (!big_block_files_->Init(false, kFirstAdditionalBlockFileV3))
+ return ERR_INIT_FAILED;
+
+ IndexHeaderV3* index =
+ reinterpret_cast<IndexHeaderV3*>(index_header_->buffer());
+
+ result->reset(new InitResult);
+ big_block_files_->GetBitmaps(index->max_block_file,
+ &result->get()->block_bitmaps);
+ index->max_block_file = static_cast<int>(result->get()->block_bitmaps.size());
+ return ERR_NO_ERROR;
}
-void BackendImpl::PrepareForRestart() {
- // Reset the mask_ if it was not given by the user.
- if (!(user_flags_ & kMask))
- mask_ = 0;
+int BackendImplV3::Worker::Delete(Addr address) {
+ if (address.is_block_file())
+ return ERR_OPERATION_FAILED;
- if (!(user_flags_ & kNewEviction))
- new_eviction_ = false;
+ if (DeleteCacheFile(GetFileName(address)))
+ return ERR_NO_ERROR;
- disabled_ = true;
- data_->header.crash = 0;
- index_->Flush();
- index_ = NULL;
- data_ = NULL;
- block_files_.CloseFiles();
- rankings_.Reset();
- init_ = false;
- restarted_ = true;
+ return ERR_OPERATION_FAILED;
}
-BackendImpl::~BackendImpl() {
- if (user_flags_ & kNoRandom) {
- // This is a unit test, so we want to be strict about not leaking entries
- // and completing all the work.
- background_queue_.WaitForPendingIO();
- } else {
- // This is most likely not a test, so we want to do as little work as
- // possible at this time, at the price of leaving dirty entries behind.
- background_queue_.DropPendingIO();
- }
+int BackendImplV3::Worker::Close(Addr address) {
+ if (address.is_block_file())
+ return ERR_OPERATION_FAILED;
- if (background_queue_.BackgroundIsCurrentThread()) {
- // Unit tests may use the same thread for everything.
- CleanupCache();
- } else {
- background_queue_.background_thread()->PostTask(
- FROM_HERE, base::Bind(&FinalCleanupCallback, base::Unretained(this)));
- // http://crbug.com/74623
- base::ThreadRestrictions::ScopedAllowWait allow_wait;
- done_.Wait();
+ FilesMap::iterator it = files_.find(address.value());
+ if (it != files_.end())
+ files_.erase(it);
+
+ return ERR_NO_ERROR;
+}
+
+void BackendImplV3::Worker::OnDoWork(WorkItem* work_item) {
+ if (work_item->type() == WorkItem::WORK_CLEANUP)
+ return Cleanup(work_item);
+
+ work_item->Start(this);
+}
+
+void BackendImplV3::Worker::DoneWithItem(WorkItem* work_item) {
+ bool rv = main_thread_->PostTask(FROM_HERE,
+ base::Bind(&WorkItem::OnDone, work_item));
+ DCHECK(rv);
+}
+
+File* BackendImplV3::Worker::GetBackingFile(Addr address, bool for_write) {
+ disk_cache::File* file;
+ if (address.is_separate_file())
+ file = GetExternalFile(address, for_write);
+ else
+ file = block_files_->GetFile(address);
+ return file;
+}
+
+File* BackendImplV3::Worker::GetBackupIndexFile() {
+ DCHECK(!index_backup_.get());
+ index_backup_ = new MappedFile();
+ index_backup_->set_force_creation();
+ if (!index_backup_->InitNoMap(path_.AppendASCII(kIndexBackupName))) {
+ LOG(ERROR) << "Unable to open index_bak";
+ return NULL;
}
+ return index_backup_.get();
}
-void BackendImpl::CleanupCache() {
- Trace("Backend Cleanup");
- eviction_.Stop();
- timer_.reset();
+void BackendImplV3::Worker::CloseBackupIndexFile() {
+ index_backup_ = NULL;
+}
+bool BackendImplV3::Worker::IsValid() {
+ return init_;
+}
+
+// ------------------------------------------------------------------------
+
+BackendImplV3::Worker::~Worker() {
+ if (cleanup_work_item_)
+ main_thread_->PostTask(FROM_HERE,
+ base::Bind(&WorkItem::OnDone, cleanup_work_item_));
+}
+
+void BackendImplV3::Worker::Cleanup(WorkItem* work_item) {
+ Trace("Worker::Cleanup");
+ if (!work_item->user_callback().is_null())
+ cleanup_work_item_ = work_item;
+
if (init_) {
- StoreStats();
- if (data_)
- data_->header.crash = 0;
+ IndexHeaderV3* index =
+ reinterpret_cast<IndexHeaderV3*>(index_header_->buffer());
+ index->crash = 0;
+ }
- if (user_flags_ & kNoRandom) {
- // This is a net_unittest, verify that we are not 'leaking' entries.
- File::WaitForPendingIO(&num_pending_io_);
- DCHECK(!num_refs_);
- } else {
- File::DropPendingIO();
- }
+ CloseFiles();
+ init_ = false;
+
+ if (work_item->user_callback().is_null()) {
+ // This is the only message we don't return to the main thread, we are done
+ // with the work item for good.
+ work_item->Release();
}
- block_files_.CloseFiles();
- FlushIndex();
- index_ = NULL;
- ptr_factory_.InvalidateWeakPtrs();
- done_.Signal();
}
-base::FilePath BackendImpl::GetFileName(Addr address) const {
+void BackendImplV3::Worker::CloseFiles() {
+ index_header_ = NULL;
+ main_table_ = NULL;
+ extra_table_ = NULL;
+ index_backup_ = NULL;
+ block_files_->CloseFiles();
+ files_.clear();
+
+ big_index_header_ = NULL;
+ big_main_table_ = NULL;
+ big_extra_table_ = NULL;
+ big_extra_temp_table_ = NULL;
+ if (big_block_files_.get())
+ big_block_files_->CloseFiles();
+}
+
+File* BackendImplV3::Worker::GetExternalFile(Addr address, bool for_write) {
+ FilesMap::iterator it = files_.find(address.value());
+ if (it != files_.end())
+ return it->second;
+
+ scoped_refptr<disk_cache::File> file(new disk_cache::File(false));
+ if (for_write)
+ file->set_force_creation();
+ if (file->Init(GetFileName(address)))
+ files_[address.value()] = file.get();
+ else
+ file = NULL;
+
+ return file;
+}
+
+base::FilePath BackendImplV3::Worker::GetFileName(Addr address) const {
if (!address.is_separate_file() || !address.is_initialized()) {
NOTREACHED();
return base::FilePath();
@@ -312,25 +458,86 @@
// We just created a new file so we're going to write the header and set the
// file length to include the hash table (zero filled).
-bool BackendImpl::CreateBackingStore(disk_cache::File* file) {
- AdjustMaxCacheSize(0);
+bool BackendImplV3::Worker::CreateBackingStore(disk_cache::File* file) {
+ IndexHeaderV3 header;
+ memset(&header, 0, sizeof(header));
+ header.magic = kIndexMagicV3;
+ header.version = kVersion3;
+ header.max_block_file = kFirstAdditionalBlockFileV3;
+
+ // Start with 12.5% of the size of the main table.
+ int extra_len = (user_flags_ & BASIC_UNIT_TEST) ? 8 : kBaseTableLen / 8;
+ header.table_len = kBaseTableLen + extra_len;
+ header.max_bucket = kBaseTableLen / 4 - 1;
+ header.flags = SMALL_CACHE;
- IndexHeader header;
- header.table_len = DesiredIndexTableLen(max_size_);
-
- // We need file version 2.1 for the new eviction algorithm.
- if (new_eviction_)
- header.version = 0x20001;
-
header.create_time = Time::Now().ToInternalValue();
+ header.base_time = (Time::Now() - TimeDelta::FromDays(20)).ToInternalValue();
if (!file->Write(&header, sizeof(header), 0))
return false;
- return file->SetLength(GetIndexSize(header.table_len));
+ if (!file->SetLength(GetIndexBitmapSize(header.table_len)))
+ return false;
+
+ int flags = base::PLATFORM_FILE_READ |
+ base::PLATFORM_FILE_WRITE |
+ base::PLATFORM_FILE_CREATE |
+ base::PLATFORM_FILE_EXCLUSIVE_WRITE;
+
+ base::FilePath name = path_.AppendASCII(kIndexBackupName);
+ scoped_refptr<disk_cache::File> file2(new disk_cache::File(
+ base::CreatePlatformFile(name, flags, NULL, NULL)));
+
+ if (!file2->IsValid())
+ return false;
+
+ if (!file2->Write(&header, sizeof(header), 0))
+ return false;
+
+ if (!file2->SetLength(GetIndexBitmapSize(header.table_len)))
+ return false;
+
+ name = path_.AppendASCII(kTable1Name);
+ file2 = new disk_cache::File(base::CreatePlatformFile(name, flags, NULL,
+ NULL));
+ if (!file2->IsValid())
+ return false;
+
+ if (!file2->SetLength(kBaseTableLen * kBytesPerCell))
+ return false;
+
+ name = path_.AppendASCII(kTable2Name);
+ file2 = new disk_cache::File(base::CreatePlatformFile(name, flags, NULL,
+ NULL));
+ if (!file2->IsValid())
+ return false;
+
+ if (!file2->SetLength(extra_len * kBytesPerCell))
+ return false;
+
+ return true;
}
-bool BackendImpl::InitBackingStore(bool* file_created) {
+bool BackendImplV3::Worker::CreateExtraTable(int extra_len) {
+ int flags = base::PLATFORM_FILE_READ |
+ base::PLATFORM_FILE_WRITE |
+ base::PLATFORM_FILE_CREATE |
+ base::PLATFORM_FILE_EXCLUSIVE_WRITE;
+
+ base::FilePath name = path_.AppendASCII(kTable2TempName);
+ scoped_refptr<disk_cache::File> file(new disk_cache::File(
+ base::CreatePlatformFile(name, flags, NULL, NULL)));
+ if (!file->IsValid())
+ return false;
+
+ if (!file->SetLength(extra_len * kBytesPerCell))
+ return false;
+
+ return true;
+}
+
+bool BackendImplV3::Worker::InitBackingStore(bool* file_created) {
if (!file_util::CreateDirectory(path_))
return false;
@@ -348,124 +555,152 @@
bool ret = true;
if (*file_created)
- ret = CreateBackingStore(file.get());
+ ret = CreateBackingStore(file);
file = NULL;
if (!ret)
return false;
- index_ = new MappedFile();
- data_ = reinterpret_cast<Index*>(index_->Init(index_name, 0));
- if (!data_) {
- LOG(ERROR) << "Unable to map Index file";
+ index_header_ = new MappedFile();
+ if (!index_header_->Init(index_name, 0)) {
+ LOG(ERROR) << "Unable to map index";
return false;
}
- if (index_->GetLength() < sizeof(Index)) {
+ if (index_header_->GetLength() < sizeof(IndexBitmap)) {
// We verify this again on CheckIndex() but it's easier to make sure now
// that the header is there.
- LOG(ERROR) << "Corrupt Index file";
+ LOG(ERROR) << "Corrupt index file";
return false;
}
+ main_table_ = new MappedFile();
+ if (!main_table_->Init(path_.AppendASCII(kTable1Name), 0)) {
+ LOG(ERROR) << "Unable to map index_tb1";
+ return false;
+ }
+
+ extra_table_ = new MappedFile();
+ if (!extra_table_->Init(path_.AppendASCII(kTable2Name), 0)) {
+ LOG(ERROR) << "Unable to map index_tb2";
+ return false;
+ }
+
+ index_backup_ = new MappedFile();
+ if (!index_backup_->Init(path_.AppendASCII(kIndexBackupName), 0)) {
+ LOG(ERROR) << "Unable to map index_bak";
+ return false;
+ }
+
return true;
}
-void BackendImpl::ReportError(int error) {
- STRESS_DCHECK(!error || error == ERR_PREVIOUS_CRASH ||
- error == ERR_CACHE_CREATED);
+bool BackendImplV3::Worker::LoadIndex(InitResult* init_result) {
+ init_result->index_data.index_bitmap =
+ reinterpret_cast<IndexBitmap*>(index_header_->buffer());
+ init_result->index_data.main_table =
+ reinterpret_cast<IndexBucket*>(main_table_->buffer());
+ init_result->index_data.extra_table =
+ reinterpret_cast<IndexBucket*>(extra_table_->buffer());
- // We transmit positive numbers, instead of direct error codes.
- DCHECK_LE(error, 0);
- CACHE_UMA(CACHE_ERROR, "Error", 0, error * -1);
-}
+ if (!CheckIndexFile(index_header_))
+ return false;
+ if (!CheckIndexFile(index_backup_))
+ return false;
-bool BackendImpl::CheckIndex() {
- DCHECK(data_);
+ IndexHeaderV3& header = init_result->index_data.index_bitmap->header;
- size_t current_size = index_->GetLength();
- if (current_size < sizeof(Index)) {
+ size_t extra_table_len = header.table_len % kBaseTableLen;
+ size_t main_table_len = (kBaseTableLen - extra_table_len) * kBytesPerCell;
+ extra_table_len *= kBytesPerCell;
+
+ if (main_table_->GetLength() < main_table_len ||
+ extra_table_->GetLength() < extra_table_len) {
+ LOG(ERROR) << "Truncated table";
+ return false;
+ }
+
+ IndexBitmap* index = reinterpret_cast<IndexBitmap*>(index_backup_->buffer());
+
+ init_result->index_data.backup_header.reset(new IndexHeaderV3);
+ memcpy(init_result->index_data.backup_header.get(), &index->header,
+ sizeof(index->header));
+
+ size_t bitmap_len = GetIndexBitmapSize(index->header.table_len) -
+ sizeof(index->header);
+ init_result->index_data.backup_bitmap.reset(new uint32[bitmap_len / 4]);
+ memcpy(init_result->index_data.backup_bitmap.get(), &index->bitmap,
+ bitmap_len);
+
+ // Close the backup.
+ index_backup_ = NULL;
+ return true;
+}
+
+bool BackendImplV3::Worker::CheckIndexFile(MappedFile* file) {
+ size_t current_size = file->GetLength();
+ if (current_size < sizeof(IndexBitmap)) {
LOG(ERROR) << "Corrupt Index file";
return false;
}
- if (new_eviction_) {
- // We support versions 2.0 and 2.1, upgrading 2.0 to 2.1.
- if (kIndexMagic != data_->header.magic ||
- kCurrentVersion >> 16 != data_->header.version >> 16) {
- LOG(ERROR) << "Invalid file version or magic";
- return false;
- }
- if (kCurrentVersion == data_->header.version) {
- // We need file version 2.1 for the new eviction algorithm.
- UpgradeTo2_1();
- }
- } else {
- if (kIndexMagic != data_->header.magic ||
- kCurrentVersion != data_->header.version) {
- LOG(ERROR) << "Invalid file version or magic";
- return false;
- }
+ IndexHeaderV3* header = reinterpret_cast<IndexHeaderV3*>(file->buffer());
+
+ if (kIndexMagicV3 != header->magic || kVersion3 != header->version) {
+ LOG(ERROR) << "Invalid file version or magic";
+ return false;
}
- if (!data_->header.table_len) {
+ if (header->table_len <= 0 || header->table_len > 1 << 22) {
LOG(ERROR) << "Invalid table size";
return false;
}
- if (current_size < GetIndexSize(data_->header.table_len) ||
- data_->header.table_len & (kBaseTableLen - 1)) {
+ int min_mask = (user_flags_ & BASIC_UNIT_TEST) ? 0x3 : 0xff;
+ if (current_size < GetIndexBitmapSize(header->table_len) ||
+ header->table_len & (min_mask)) {
LOG(ERROR) << "Corrupt Index file";
return false;
}
- AdjustMaxCacheSize(data_->header.table_len);
+ //AdjustMaxCacheSize(header->table_len);
#if !defined(NET_BUILD_STRESS_CACHE)
- if (data_->header.num_bytes < 0 ||
- (max_size_ < kint32max - kDefaultCacheSize &&
- data_->header.num_bytes > max_size_ + kDefaultCacheSize)) {
- LOG(ERROR) << "Invalid cache (current) size";
+ if (header->num_bytes < 0 || header->max_bytes < 0 ||
+ header->num_bytes > header->max_bytes + kDefaultCacheSize) {
+ LOG(ERROR) << "Invalid cache size";
return false;
}
#endif
- if (data_->header.num_entries < 0) {
+ if (header->num_entries < 0) {
LOG(ERROR) << "Invalid number of entries";
return false;
}
- if (!mask_)
- mask_ = data_->header.table_len - 1;
-
// Load the table into memory with a single read.
- scoped_ptr<char[]> buf(new char[current_size]);
- return index_->Read(buf.get(), current_size, 0);
+ //scoped_array<char> buf(new char[current_size]);
+ //return index_->Read(buf.get(), current_size, 0);
+
+ return true;
}
-bool BackendImpl::InitStats() {
- Addr address(data_->header.stats);
- int size = stats_.StorageSize();
+bool BackendImplV3::Worker::InitStats(IndexHeaderV3* index,
+ InitResult* result) {
+ Addr address(index->stats);
+ if (!address.is_initialized())
+ return true;
- if (!address.is_initialized()) {
- FileType file_type = Addr::RequiredFileType(size);
- DCHECK_NE(file_type, EXTERNAL);
- int num_blocks = Addr::RequiredBlocks(size, file_type);
-
- if (!CreateBlock(file_type, num_blocks, &address))
- return false;
- return stats_.Init(NULL, 0, address);
- }
-
if (!address.is_block_file()) {
NOTREACHED();
return false;
}
+ int size = address.num_blocks() * address.BlockSize();
+
// Load the required data.
- size = address.num_blocks() * address.BlockSize();
- MappedFile* file = File(address);
+ MappedFile* file = GetMappedFile(address);
if (!file)
return false;
@@ -475,11 +710,22 @@
if (!file->Read(data.get(), size, offset))
return false;
- if (!stats_.Init(data.get(), size, address))
- return false;
- if (cache_type_ == net::DISK_CACHE && ShouldReportAgain())
- stats_.InitSizeHistogram();
+ result->stats_data = data.Pass();
return true;
}
+int BackendImplV3::Worker::GrowDone() {
+ Trace("Worker::GrowDone");
+ if (!init_)
+ return ERR_OPERATION_FAILED;
+
+ DCHECK(doubling_index_);
+ doubling_index_ = false;
+
+ extra_table_ = big_extra_temp_table_;
+ big_extra_temp_table_ = NULL;
+
+ return ERR_NO_ERROR;
+}
+
} // namespace disk_cache
« no previous file with comments | « net/disk_cache/v3/backend_worker.h ('k') | net/disk_cache/v3/block_bitmaps.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698