15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/disk_cache/blockfile/block_files.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/atomicops.h"
890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/files/file_path.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h"
105e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_util.h"
115e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/stringprintf.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread_checker.h"
13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
14a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/disk_cache/blockfile/file_lock.h"
15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/disk_cache/blockfile/stress_support.h"
16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/disk_cache/blockfile/trace.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/disk_cache/cache_util.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::TimeTicks;
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* kBlockName = "data_";
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This array is used to perform a fast lookup of the nibble bit pattern to the
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// type of entry that can be stored there (number of consecutive blocks).
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char s_types[16] = {4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0};
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns the type of block (number of consecutive blocks that can be stored)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// for a given nibble of the bitmap.
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline int GetMapBlockType(uint8 value) {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  value &= 0xf;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return s_types[value];
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}  // namespace
37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace disk_cache {
39eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
40eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochBlockHeader::BlockHeader() : header_(NULL) {
41eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
43eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochBlockHeader::BlockHeader(BlockFileHeader* header) : header_(header) {
44eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
45eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
46eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochBlockHeader::BlockHeader(MappedFile* file)
47eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    : header_(reinterpret_cast<BlockFileHeader*>(file->buffer())) {
48eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
49eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
50eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochBlockHeader::BlockHeader(const BlockHeader& other) : header_(other.header_) {
51eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
52eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
53eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochBlockHeader::~BlockHeader() {
54eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
56d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)bool BlockHeader::CreateMapBlock(int size, int* index) {
57d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DCHECK(size > 0 && size <= kMaxNumBlocks);
58d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  int target = 0;
59d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  for (int i = size; i <= kMaxNumBlocks; i++) {
60d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (header_->empty[i - 1]) {
61d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      target = i;
62d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      break;
63d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
64d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
65d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
66d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (!target) {
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    STRESS_NOTREACHED();
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TimeTicks start = TimeTicks::Now();
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We are going to process the map on 32-block chunks (32 bits), and on every
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // chunk, iterate through the 8 nibbles where the new block can be located.
74eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int current = header_->hints[target - 1];
75eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (int i = 0; i < header_->max_entries / 32; i++, current++) {
76eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (current == header_->max_entries / 32)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      current = 0;
78eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    uint32 map_block = header_->allocation_map[current];
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int j = 0; j < 8; j++, map_block >>= 4) {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (GetMapBlockType(map_block) != target)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
84eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      disk_cache::FileLock lock(header_);
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int index_offset = j * 4 + 4 - target;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *index = current * 32 + index_offset;
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      STRESS_DCHECK(*index / 4 == (*index + size - 1) / 4);
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      uint32 to_add = ((1 << size) - 1) << index_offset;
89eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      header_->num_entries++;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Note that there is no race in the normal sense here, but if we enforce
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // the order of memory accesses between num_entries and allocation_map, we
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // can assert that even if we crash here, num_entries will never be less
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // than the actual number of used blocks.
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::subtle::MemoryBarrier();
96eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      header_->allocation_map[current] |= to_add;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
98eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      header_->hints[target - 1] = current;
99eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      header_->empty[target - 1]--;
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      STRESS_DCHECK(header_->empty[target - 1] >= 0);
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (target != size) {
102eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        header_->empty[target - size - 1]++;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      LOCAL_HISTOGRAM_TIMES("DiskCache.CreateBlock", TimeTicks::Now() - start);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It is possible to have an undetected corruption (for example when the OS
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // crashes), fix it here.
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LOG(ERROR) << "Failing CreateMapBlock";
112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  FixAllocationCounters();
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid BlockHeader::DeleteMapBlock(int index, int size) {
117eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (size < 0 || size > kMaxNumBlocks) {
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TimeTicks start = TimeTicks::Now();
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int byte_index = index / 8;
123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  uint8* byte_map = reinterpret_cast<uint8*>(header_->allocation_map);
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint8 map_block = byte_map[byte_index];
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (index % 8 >= 4)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    map_block >>= 4;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
129eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // See what type of block will be available after we delete this one.
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int bits_at_end = 4 - size - index % 4;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint8 end_mask = (0xf << (4 - bits_at_end)) & 0xf;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool update_counters = (map_block & end_mask) == 0;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint8 new_value = map_block & ~(((1 << size) - 1) << (index % 4));
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int new_type = GetMapBlockType(new_value);
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  disk_cache::FileLock lock(header_);
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  STRESS_DCHECK((((1 << size) - 1) << (index % 8)) < 0x100);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint8  to_clear = ((1 << size) - 1) << (index % 8);
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  STRESS_DCHECK((byte_map[byte_index] & to_clear) == to_clear);
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  byte_map[byte_index] &= ~to_clear;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (update_counters) {
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (bits_at_end)
144eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      header_->empty[bits_at_end - 1]--;
145eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    header_->empty[new_type - 1]++;
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    STRESS_DCHECK(header_->empty[bits_at_end - 1] >= 0);
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::subtle::MemoryBarrier();
149eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  header_->num_entries--;
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  STRESS_DCHECK(header_->num_entries >= 0);
1511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  LOCAL_HISTOGRAM_TIMES("DiskCache.DeleteBlock", TimeTicks::Now() - start);
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
154eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Note that this is a simplified version of DeleteMapBlock().
155eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool BlockHeader::UsedMapBlock(int index, int size) {
156d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (size < 0 || size > kMaxNumBlocks)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
158d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int byte_index = index / 8;
160eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  uint8* byte_map = reinterpret_cast<uint8*>(header_->allocation_map);
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint8 map_block = byte_map[byte_index];
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (index % 8 >= 4)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    map_block >>= 4;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  STRESS_DCHECK((((1 << size) - 1) << (index % 8)) < 0x100);
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint8  to_clear = ((1 << size) - 1) << (index % 8);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ((byte_map[byte_index] & to_clear) == to_clear);
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
171eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid BlockHeader::FixAllocationCounters() {
172eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (int i = 0; i < kMaxNumBlocks; i++) {
173eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    header_->hints[i] = 0;
174eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    header_->empty[i] = 0;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
177eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (int i = 0; i < header_->max_entries / 32; i++) {
178eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    uint32 map_block = header_->allocation_map[i];
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int j = 0; j < 8; j++, map_block >>= 4) {
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int type = GetMapBlockType(map_block);
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (type)
183eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        header_->empty[type -1]++;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
188d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)bool BlockHeader::NeedToGrowBlockFile(int block_count) const {
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool have_space = false;
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int empty_blocks = 0;
191eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (int i = 0; i < kMaxNumBlocks; i++) {
192eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    empty_blocks += header_->empty[i] * (i + 1);
193eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (i >= block_count - 1 && header_->empty[i])
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      have_space = true;
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
197eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (header_->next_file && (empty_blocks < kMaxBlocks / 10)) {
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This file is almost full but we already created another one, don't use
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // this file yet so that it is easier to find empty blocks when we start
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // using this file again.
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return !have_space;
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
206d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)bool BlockHeader::CanAllocate(int block_count) const {
207d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DCHECK_GT(block_count, 0);
208d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  for (int i = block_count - 1; i < kMaxNumBlocks; i++) {
209d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (header_->empty[i])
210d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      return true;
211d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
212d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
213d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return false;
214d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
215d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
216eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint BlockHeader::EmptyBlocks() const {
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int empty_blocks = 0;
218d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  for (int i = 0; i < kMaxNumBlocks; i++) {
219eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    empty_blocks += header_->empty[i] * (i + 1);
220eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (header_->empty[i] < 0)
221eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      return 0;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return empty_blocks;
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
226d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)int BlockHeader::MinimumAllocations() const {
227d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return header_->empty[kMaxNumBlocks - 1];
228d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
229d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
230d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)int BlockHeader::Capacity() const {
231d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return header_->max_entries;
232d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
233d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
234eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool BlockHeader::ValidateCounters() const {
235eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (header_->max_entries < 0 || header_->max_entries > kMaxBlocks ||
236eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      header_->num_entries < 0)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
239eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int empty_blocks = EmptyBlocks();
240eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (empty_blocks + header_->num_entries > header_->max_entries)
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
246d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)int BlockHeader::FileId() const {
247d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return header_->this_file;
248d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
249d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
250d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)int BlockHeader::NextFileId() const {
251d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return header_->next_file;
252d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
253d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
254eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint BlockHeader::Size() const {
255eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return static_cast<int>(sizeof(*header_));
256eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
258d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)BlockFileHeader* BlockHeader::Header() {
259d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return header_;
260d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
261d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
262eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// ------------------------------------------------------------------------
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)BlockFiles::BlockFiles(const base::FilePath& path)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : init_(false), zero_buffer_(NULL), path_(path) {
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BlockFiles::~BlockFiles() {
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (zero_buffer_)
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete[] zero_buffer_;
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseFiles();
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BlockFiles::Init(bool create_files) {
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!init_);
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (init_)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thread_checker_.reset(new base::ThreadChecker);
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  block_files_.resize(kFirstAdditionalBlockFile);
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < kFirstAdditionalBlockFile; i++) {
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (create_files)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!CreateBlockFile(i, static_cast<FileType>(i + 1), true))
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!OpenBlockFile(i))
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Walk this chain of files removing empty ones.
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!RemoveEmptyFile(static_cast<FileType>(i + 1)))
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  init_ = true;
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MappedFile* BlockFiles::GetFile(Addr address) {
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thread_checker_->CalledOnValidThread());
301d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DCHECK_GE(block_files_.size(),
302d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)            static_cast<size_t>(kFirstAdditionalBlockFile));
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(address.is_block_file() || !address.is_initialized());
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!address.is_initialized())
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int file_index = address.FileNumber();
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (static_cast<unsigned int>(file_index) >= block_files_.size() ||
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !block_files_[file_index]) {
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We need to open the file
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!OpenBlockFile(file_index))
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return NULL;
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
314d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DCHECK_GE(block_files_.size(), static_cast<unsigned int>(file_index));
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return block_files_[file_index];
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BlockFiles::CreateBlock(FileType block_type, int block_count,
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             Addr* block_address) {
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thread_checker_->CalledOnValidThread());
321d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DCHECK_NE(block_type, EXTERNAL);
322d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DCHECK_NE(block_type, BLOCK_FILES);
323d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DCHECK_NE(block_type, BLOCK_ENTRIES);
324d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DCHECK_NE(block_type, BLOCK_EVICTED);
325d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (block_count < 1 || block_count > kMaxNumBlocks)
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
327d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!init_)
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MappedFile* file = FileForNewBlock(block_type, block_count);
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!file)
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedFlush flush(file);
336d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  BlockHeader file_header(file);
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int index;
339d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (!file_header.CreateMapBlock(block_count, &index))
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
342d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  Addr address(block_type, block_count, file_header.FileId(), index);
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  block_address->set_value(address.value());
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Trace("CreateBlock 0x%x", address.value());
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BlockFiles::DeleteBlock(Addr address, bool deep) {
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thread_checker_->CalledOnValidThread());
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!address.is_initialized() || address.is_separate_file())
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!zero_buffer_) {
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    zero_buffer_ = new char[Addr::BlockSizeForFileType(BLOCK_4K) * 4];
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memset(zero_buffer_, 0, Addr::BlockSizeForFileType(BLOCK_4K) * 4);
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MappedFile* file = GetFile(address);
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!file)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Trace("DeleteBlock 0x%x", address.value());
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t size = address.BlockSize() * address.num_blocks();
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t offset = address.start_block() * address.BlockSize() +
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  kBlockHeaderSize;
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (deep)
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    file->Write(zero_buffer_, size, offset);
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
369d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  BlockHeader file_header(file);
370d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  file_header.DeleteMapBlock(address.start_block(), address.num_blocks());
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file->Flush();
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
373d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (!file_header.Header()->num_entries) {
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This file is now empty. Let's try to delete it.
375d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    FileType type = Addr::RequiredFileType(file_header.Header()->entry_size);
376d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (Addr::BlockSizeForFileType(RANKINGS) ==
377d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        file_header.Header()->entry_size) {
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      type = RANKINGS;
379d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RemoveEmptyFile(type);  // Ignore failures.
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BlockFiles::CloseFiles() {
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (init_) {
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(thread_checker_->CalledOnValidThread());
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  init_ = false;
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (unsigned int i = 0; i < block_files_.size(); i++) {
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (block_files_[i]) {
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      block_files_[i]->Release();
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      block_files_[i] = NULL;
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  block_files_.clear();
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BlockFiles::ReportStats() {
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thread_checker_->CalledOnValidThread());
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int used_blocks[kFirstAdditionalBlockFile];
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int load[kFirstAdditionalBlockFile];
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < kFirstAdditionalBlockFile; i++) {
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetFileStats(i, &used_blocks[i], &load[i]);
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_0", used_blocks[0]);
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_1", used_blocks[1]);
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_2", used_blocks[2]);
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_3", used_blocks[3]);
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_0", load[0], 101);
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_1", load[1], 101);
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_2", load[2], 101);
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_3", load[3], 101);
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BlockFiles::IsValid(Addr address) {
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef NDEBUG
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!address.is_initialized() || address.is_separate_file())
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MappedFile* file = GetFile(address);
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!file)
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
427eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  BlockHeader header(file);
428eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  bool rv = header.UsedMapBlock(address.start_block(), address.num_blocks());
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(rv);
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool read_contents = false;
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (read_contents) {
433c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_ptr<char[]> buffer;
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    buffer.reset(new char[Addr::BlockSizeForFileType(BLOCK_4K) * 4]);
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t size = address.BlockSize() * address.num_blocks();
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t offset = address.start_block() * address.BlockSize() +
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    kBlockHeaderSize;
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool ok = file->Read(buffer.get(), size, offset);
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(ok);
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rv;
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BlockFiles::CreateBlockFile(int index, FileType file_type, bool force) {
4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath name = Name(index);
448c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  int flags = force ? base::File::FLAG_CREATE_ALWAYS : base::File::FLAG_CREATE;
449c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  flags |= base::File::FLAG_WRITE | base::File::FLAG_EXCLUSIVE_WRITE;
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
451c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  scoped_refptr<File> file(new File(base::File(name, flags)));
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!file->IsValid())
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BlockFileHeader header;
456868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  memset(&header, 0, sizeof(header));
457868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  header.magic = kBlockMagic;
458868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  header.version = kBlockVersion2;
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  header.entry_size = Addr::BlockSizeForFileType(file_type);
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  header.this_file = static_cast<int16>(index);
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(index <= kint16max && index >= 0);
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return file->Write(&header, sizeof(header), 0);
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BlockFiles::OpenBlockFile(int index) {
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (block_files_.size() - 1 < static_cast<unsigned int>(index)) {
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(index > 0);
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int to_add = index - static_cast<int>(block_files_.size()) + 1;
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    block_files_.resize(block_files_.size() + to_add);
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath name = Name(index);
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<MappedFile> file(new MappedFile());
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!file->Init(name, kBlockHeaderSize)) {
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Failed to open " << name.value();
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t file_len = file->GetLength();
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (file_len < static_cast<size_t>(kBlockHeaderSize)) {
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "File too small " << name.value();
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
487d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  BlockHeader file_header(file.get());
488d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  BlockFileHeader* header = file_header.Header();
489868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (kBlockMagic != header->magic || kBlockVersion2 != header->version) {
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Invalid file version or magic " << name.value();
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
494d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (header->updating || !file_header.ValidateCounters()) {
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Last instance was not properly shutdown, or counters are out of sync.
496868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!FixBlockFileHeader(file.get())) {
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Unable to fix block file " << name.value();
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (static_cast<int>(file_len) <
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      header->max_entries * header->entry_size + kBlockHeaderSize) {
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "File too small " << name.value();
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (index == 0) {
509e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    // Load the links file into memory.
510e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    if (!file->Preload())
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
514868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  ScopedFlush flush(file.get());
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!block_files_[index]);
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file.swap(&block_files_[index]);
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BlockFiles::GrowBlockFile(MappedFile* file, BlockFileHeader* header) {
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kMaxBlocks == header->max_entries)
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedFlush flush(file);
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!header->empty[3]);
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int new_size = header->max_entries + 1024;
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (new_size > kMaxBlocks)
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_size = kMaxBlocks;
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int new_size_bytes = new_size * header->entry_size + sizeof(*header);
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!file->SetLength(new_size_bytes)) {
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Most likely we are trying to truncate the file, so the header is wrong.
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (header->updating < 10 && !FixBlockFileHeader(file)) {
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If we can't fix the file increase the lock guard so we'll pick it on
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // the next start and replace it.
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      header->updating = 100;
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return (header->max_entries >= new_size);
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FileLock lock(header);
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  header->empty[3] = (new_size - header->max_entries) / 4;  // 4 blocks entries
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  header->max_entries = new_size;
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MappedFile* BlockFiles::FileForNewBlock(FileType block_type, int block_count) {
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  COMPILE_ASSERT(RANKINGS == 1, invalid_file_type);
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MappedFile* file = block_files_[block_type - 1];
553d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  BlockHeader file_header(file);
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TimeTicks start = TimeTicks::Now();
556d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  while (file_header.NeedToGrowBlockFile(block_count)) {
557d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (kMaxBlocks == file_header.Header()->max_entries) {
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      file = NextFile(file);
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!file)
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return NULL;
561d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      file_header = BlockHeader(file);
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (!GrowBlockFile(file, file_header.Header()))
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return NULL;
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    break;
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  LOCAL_HISTOGRAM_TIMES("DiskCache.GetFileForNewBlock",
5701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                        TimeTicks::Now() - start);
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return file;
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MappedFile* BlockFiles::NextFile(MappedFile* file) {
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedFlush flush(file);
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer());
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int new_file = header->next_file;
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!new_file) {
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // RANKINGS is not reported as a type for small entries, but we may be
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // extending the rankings block file.
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FileType type = Addr::RequiredFileType(header->entry_size);
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (header->entry_size == Addr::BlockSizeForFileType(RANKINGS))
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      type = RANKINGS;
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_file = CreateNextBlockFile(type);
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!new_file)
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return NULL;
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FileLock lock(header);
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    header->next_file = new_file;
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Only the block_file argument is relevant for what we want.
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Addr address(BLOCK_256, 1, new_file, 0);
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetFile(address);
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BlockFiles::CreateNextBlockFile(FileType block_type) {
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = kFirstAdditionalBlockFile; i <= kMaxBlockFile; i++) {
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (CreateBlockFile(i, block_type, false))
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return i;
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We walk the list of files for this particular block type, deleting the ones
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// that are empty.
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BlockFiles::RemoveEmptyFile(FileType block_type) {
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MappedFile* file = block_files_[block_type - 1];
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer());
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (header->next_file) {
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Only the block_file argument is relevant for what we want.
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Addr address(BLOCK_256, 1, header->next_file, 0);
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MappedFile* next_file = GetFile(address);
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!next_file)
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BlockFileHeader* next_header =
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        reinterpret_cast<BlockFileHeader*>(next_file->buffer());
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!next_header->num_entries) {
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK_EQ(next_header->entry_size, header->entry_size);
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Delete next_file and remove it from the chain.
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int file_index = header->next_file;
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      header->next_file = next_header->next_file;
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(block_files_.size() >= static_cast<unsigned int>(file_index));
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      file->Flush();
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We get a new handle to the file and release the old one so that the
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // file gets unmmaped... so we can delete it.
6312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::FilePath name = Name(file_index);
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      scoped_refptr<File> this_file(new File(false));
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this_file->Init(name);
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      block_files_[file_index]->Release();
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      block_files_[file_index] = NULL;
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int failure = DeleteCacheFile(name) ? 0 : 1;
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UMA_HISTOGRAM_COUNTS("DiskCache.DeleteFailed2", failure);
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (failure)
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        LOG(ERROR) << "Failed to delete " << name.value() << " from the cache.";
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    header = next_header;
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    file = next_file;
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note that we expect to be called outside of a FileLock... however, we cannot
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DCHECK on header->updating because we may be fixing a crash.
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BlockFiles::FixBlockFileHeader(MappedFile* file) {
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedFlush flush(file);
654d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  BlockHeader file_header(file);
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int file_size = static_cast<int>(file->GetLength());
656d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (file_size < file_header.Size())
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // file_size > 2GB is also an error.
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int kMinBlockSize = 36;
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int kMaxBlockSize = 4096;
661d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  BlockFileHeader* header = file_header.Header();
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (header->entry_size < kMinBlockSize ||
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      header->entry_size > kMaxBlockSize || header->num_entries < 0)
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure that we survive crashes.
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  header->updating = 1;
668d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  int expected = header->entry_size * header->max_entries + file_header.Size();
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (file_size != expected) {
670d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    int max_expected = header->entry_size * kMaxBlocks + file_header.Size();
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (file_size < expected || header->empty[3] || file_size > max_expected) {
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Unexpected file size";
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We were in the middle of growing the file.
677d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    int num_entries = (file_size - file_header.Size()) / header->entry_size;
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    header->max_entries = num_entries;
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
681d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  file_header.FixAllocationCounters();
682d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  int empty_blocks = file_header.EmptyBlocks();
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (empty_blocks + header->num_entries > header->max_entries)
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    header->num_entries = header->max_entries - empty_blocks;
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
686d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (!file_header.ValidateCounters())
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  header->updating = 0;
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We are interested in the total number of blocks used by this file type, and
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the max number of blocks that we can store (reported as the percentage of
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// used blocks). In order to find out the number of used blocks, we have to
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// substract the empty blocks from the total blocks for each file in the chain.
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BlockFiles::GetFileStats(int index, int* used_count, int* load) {
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int max_blocks = 0;
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *used_count = 0;
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *load = 0;
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (;;) {
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!block_files_[index] && !OpenBlockFile(index))
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BlockFileHeader* header =
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        reinterpret_cast<BlockFileHeader*>(block_files_[index]->buffer());
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    max_blocks += header->max_entries;
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int used = header->max_entries;
710d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    for (int i = 0; i < kMaxNumBlocks; i++) {
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      used -= header->empty[i] * (i + 1);
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK_GE(used, 0);
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *used_count += used;
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!header->next_file)
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    index = header->next_file;
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (max_blocks)
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *load = *used_count * 100 / max_blocks;
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath BlockFiles::Name(int index) {
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The file format allows for 256 files.
726424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(index < 256 && index >= 0);
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string tmp = base::StringPrintf("%s%d", kBlockName, index);
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return path_.AppendASCII(tmp);
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace disk_cache
732