13345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be
3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file.
4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
5c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/disk_cache/block_files.h"
6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/file_util.h"
8731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/metrics/histogram.h"
9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/string_util.h"
103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/stringprintf.h"
113f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/thread_checker.h"
12c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/time.h"
13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/disk_cache/cache_util.h"
14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/disk_cache/file_lock.h"
153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "net/disk_cache/trace.h"
16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::TimeTicks;
18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace {
20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottconst char* kBlockName = "data_";
22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// This array is used to perform a fast lookup of the nibble bit pattern to the
24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// type of entry that can be stored there (number of consecutive blocks).
25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottconst char s_types[16] = {4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0};
26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Returns the type of block (number of consecutive blocks that can be stored)
28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// for a given nibble of the bitmap.
29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottinline int GetMapBlockType(uint8 value) {
30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  value &= 0xf;
31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return s_types[value];
32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid FixAllocationCounters(disk_cache::BlockFileHeader* header);
35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Creates a new entry on the allocation map, updating the apropriate counters.
37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// target is the type of block to use (number of empty blocks), and size is the
38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// actual number of blocks to use.
39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool CreateMapBlock(int target, int size, disk_cache::BlockFileHeader* header,
40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                    int* index) {
41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (target <= 0 || target > disk_cache::kMaxNumBlocks ||
42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      size <= 0 || size > disk_cache::kMaxNumBlocks) {
43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NOTREACHED();
44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return false;
45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TimeTicks start = TimeTicks::Now();
48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // We are going to process the map on 32-block chunks (32 bits), and on every
49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // chunk, iterate through the 8 nibbles where the new block can be located.
50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int current = header->hints[target - 1];
51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (int i = 0; i < header->max_entries / 32; i++, current++) {
52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (current == header->max_entries / 32)
53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      current = 0;
54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    uint32 map_block = header->allocation_map[current];
55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    for (int j = 0; j < 8; j++, map_block >>= 4) {
57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      if (GetMapBlockType(map_block) != target)
58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        continue;
59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      disk_cache::FileLock lock(header);
61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      int index_offset = j * 4 + 4 - target;
62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      *index = current * 32 + index_offset;
633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      DCHECK_EQ(*index / 4, (*index + size - 1) / 4);
64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      uint32 to_add = ((1 << size) - 1) << index_offset;
65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      header->allocation_map[current] |= to_add;
66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      header->hints[target - 1] = current;
68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      header->empty[target - 1]--;
69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      DCHECK(header->empty[target - 1] >= 0);
70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      header->num_entries++;
71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      if (target != size) {
72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        header->empty[target - size - 1]++;
73c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      }
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      HISTOGRAM_TIMES("DiskCache.CreateBlock", TimeTicks::Now() - start);
75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return true;
76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // It is possible to have an undetected corruption (for example when the OS
80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // crashes), fix it here.
81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  LOG(ERROR) << "Failing CreateMapBlock";
82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  FixAllocationCounters(header);
83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return false;
84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Deletes the block pointed by index from allocation_map, and updates the
87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// relevant counters on the header.
88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid DeleteMapBlock(int index, int size, disk_cache::BlockFileHeader* header) {
89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (size < 0 || size > disk_cache::kMaxNumBlocks) {
90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    NOTREACHED();
91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return;
92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TimeTicks start = TimeTicks::Now();
94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int byte_index = index / 8;
95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  uint8* byte_map = reinterpret_cast<uint8*>(header->allocation_map);
96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  uint8 map_block = byte_map[byte_index];
97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (index % 8 >= 4)
99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    map_block >>= 4;
100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // See what type of block will be availabe after we delete this one.
102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int bits_at_end = 4 - size - index % 4;
103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  uint8 end_mask = (0xf << (4 - bits_at_end)) & 0xf;
104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  bool update_counters = (map_block & end_mask) == 0;
105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  uint8 new_value = map_block & ~(((1 << size) - 1) << (index % 4));
106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int new_type = GetMapBlockType(new_value);
107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
108c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  disk_cache::FileLock lock(header);
109c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK((((1 << size) - 1) << (index % 8)) < 0x100);
110c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  uint8  to_clear = ((1 << size) - 1) << (index % 8);
111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK((byte_map[byte_index] & to_clear) == to_clear);
112c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  byte_map[byte_index] &= ~to_clear;
113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (update_counters) {
115c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (bits_at_end)
116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      header->empty[bits_at_end - 1]--;
117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    header->empty[new_type - 1]++;
118c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    DCHECK(header->empty[bits_at_end - 1] >= 0);
119c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  header->num_entries--;
121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(header->num_entries >= 0);
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  HISTOGRAM_TIMES("DiskCache.DeleteBlock", TimeTicks::Now() - start);
123c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
124c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
125731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#ifndef NDEBUG
1263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Returns true if the specified block is used. Note that this is a simplified
1273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// version of DeleteMapBlock().
1283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool UsedMapBlock(int index, int size, disk_cache::BlockFileHeader* header) {
1293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (size < 0 || size > disk_cache::kMaxNumBlocks) {
1303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    NOTREACHED();
1313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return false;
1323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int byte_index = index / 8;
1343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  uint8* byte_map = reinterpret_cast<uint8*>(header->allocation_map);
1353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  uint8 map_block = byte_map[byte_index];
1363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (index % 8 >= 4)
1383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    map_block >>= 4;
1393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK((((1 << size) - 1) << (index % 8)) < 0x100);
1413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  uint8  to_clear = ((1 << size) - 1) << (index % 8);
1423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return ((byte_map[byte_index] & to_clear) == to_clear);
1433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
144731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#endif  // NDEBUG
1453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
146c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Restores the "empty counters" and allocation hints.
147c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid FixAllocationCounters(disk_cache::BlockFileHeader* header) {
148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (int i = 0; i < disk_cache::kMaxNumBlocks; i++) {
149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    header->hints[i] = 0;
150c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    header->empty[i] = 0;
151c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
152c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
153c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (int i = 0; i < header->max_entries / 32; i++) {
154c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    uint32 map_block = header->allocation_map[i];
155c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
156c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    for (int j = 0; j < 8; j++, map_block >>= 4) {
157c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      int type = GetMapBlockType(map_block);
158c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      if (type)
159c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        header->empty[type -1]++;
160c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
161c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
162c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
163c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
164c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Returns true if the current block file should not be used as-is to store more
165c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// records. |block_count| is the number of blocks to allocate.
166c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool NeedToGrowBlockFile(const disk_cache::BlockFileHeader* header,
167c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                         int block_count) {
168c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  bool have_space = false;
169c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int empty_blocks = 0;
170c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (int i = 0; i < disk_cache::kMaxNumBlocks; i++) {
171c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    empty_blocks += header->empty[i] * (i + 1);
172c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (i >= block_count - 1 && header->empty[i])
173c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      have_space = true;
174c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
175c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
176c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (header->next_file && (empty_blocks < disk_cache::kMaxBlocks / 10)) {
177c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // This file is almost full but we already created another one, don't use
178c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // this file yet so that it is easier to find empty blocks when we start
179c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // using this file again.
180c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return true;
181c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
182c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return !have_space;
183c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
184c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
185c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}  // namespace
186c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
187c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace disk_cache {
188c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
1893345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickBlockFiles::BlockFiles(const FilePath& path)
1903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    : init_(false), zero_buffer_(NULL), path_(path) {
1913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
193c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottBlockFiles::~BlockFiles() {
194c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (zero_buffer_)
195c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    delete[] zero_buffer_;
196c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  CloseFiles();
197c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
198c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
199c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool BlockFiles::Init(bool create_files) {
200c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(!init_);
201c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (init_)
202c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return false;
203c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
2043f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  thread_checker_.reset(new base::ThreadChecker);
2053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  block_files_.resize(kFirstAdditionalBlockFile);
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (int i = 0; i < kFirstAdditionalBlockFile; i++) {
208c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (create_files)
209c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      if (!CreateBlockFile(i, static_cast<FileType>(i + 1), true))
210c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        return false;
211c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
212c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (!OpenBlockFile(i))
213c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return false;
214c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
215c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Walk this chain of files removing empty ones.
216c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    RemoveEmptyFile(static_cast<FileType>(i + 1));
217c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
218c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
219c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  init_ = true;
220c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return true;
221c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
222c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
22372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenMappedFile* BlockFiles::GetFile(Addr address) {
22472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DCHECK(thread_checker_->CalledOnValidThread());
22572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DCHECK(block_files_.size() >= 4);
22672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DCHECK(address.is_block_file() || !address.is_initialized());
22772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!address.is_initialized())
22872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return NULL;
22972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
23072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  int file_index = address.FileNumber();
23172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (static_cast<unsigned int>(file_index) >= block_files_.size() ||
23272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      !block_files_[file_index]) {
23372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // We need to open the file
23472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (!OpenBlockFile(file_index))
23572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return NULL;
23672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
23772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DCHECK(block_files_.size() >= static_cast<unsigned int>(file_index));
23872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return block_files_[file_index];
23972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
24072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
24172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool BlockFiles::CreateBlock(FileType block_type, int block_count,
24272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                             Addr* block_address) {
24372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DCHECK(thread_checker_->CalledOnValidThread());
24472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (block_type < RANKINGS || block_type > BLOCK_4K ||
24572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      block_count < 1 || block_count > 4)
24672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return false;
24772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!init_)
24872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return false;
24972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
25072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  MappedFile* file = FileForNewBlock(block_type, block_count);
25172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!file)
25272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return false;
25372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
25472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer());
25572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
25672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  int target_size = 0;
25772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  for (int i = block_count; i <= 4; i++) {
25872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (header->empty[i - 1]) {
25972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      target_size = i;
26072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      break;
26172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
26272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
26372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
26472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DCHECK(target_size);
26572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  int index;
26672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!CreateMapBlock(target_size, block_count, header, &index))
26772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return false;
26872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
26972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  Addr address(block_type, block_count, header->this_file, index);
27072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  block_address->set_value(address.value());
27172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  Trace("CreateBlock 0x%x", address.value());
27272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return true;
27372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
27472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
27572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid BlockFiles::DeleteBlock(Addr address, bool deep) {
27672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DCHECK(thread_checker_->CalledOnValidThread());
27772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!address.is_initialized() || address.is_separate_file())
27872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return;
27972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
28072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!zero_buffer_) {
28172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    zero_buffer_ = new char[Addr::BlockSizeForFileType(BLOCK_4K) * 4];
28272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    memset(zero_buffer_, 0, Addr::BlockSizeForFileType(BLOCK_4K) * 4);
28372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
28472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  MappedFile* file = GetFile(address);
28572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!file)
28672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return;
28772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
28872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  Trace("DeleteBlock 0x%x", address.value());
28972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
29072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  size_t size = address.BlockSize() * address.num_blocks();
29172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  size_t offset = address.start_block() * address.BlockSize() +
29272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                  kBlockHeaderSize;
29372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (deep)
29472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    file->Write(zero_buffer_, size, offset);
29572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
296ae2796cabb52f6a27c50818b78107d3ebc858e0cKristian Monsen  BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer());
297ae2796cabb52f6a27c50818b78107d3ebc858e0cKristian Monsen  DeleteMapBlock(address.start_block(), address.num_blocks(), header);
298ae2796cabb52f6a27c50818b78107d3ebc858e0cKristian Monsen
29972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!header->num_entries) {
30072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // This file is now empty. Let's try to delete it.
30172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    FileType type = Addr::RequiredFileType(header->entry_size);
30272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (Addr::BlockSizeForFileType(RANKINGS) == header->entry_size)
30372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      type = RANKINGS;
30472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    RemoveEmptyFile(type);
30572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
30672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
30772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
308c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid BlockFiles::CloseFiles() {
3093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (init_) {
3103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    DCHECK(thread_checker_->CalledOnValidThread());
3113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
312c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  init_ = false;
313c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (unsigned int i = 0; i < block_files_.size(); i++) {
314c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (block_files_[i]) {
315c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      block_files_[i]->Release();
316c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      block_files_[i] = NULL;
317c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
318c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
319c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  block_files_.clear();
320c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
321c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BlockFiles::ReportStats() {
3233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK(thread_checker_->CalledOnValidThread());
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int used_blocks[kFirstAdditionalBlockFile];
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int load[kFirstAdditionalBlockFile];
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (int i = 0; i < kFirstAdditionalBlockFile; i++) {
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GetFileStats(i, &used_blocks[i], &load[i]);
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_0", used_blocks[0]);
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_1", used_blocks[1]);
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_2", used_blocks[2]);
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UMA_HISTOGRAM_COUNTS("DiskCache.Blocks_3", used_blocks[3]);
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_0", load[0], 101);
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_1", load[1], 101);
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_2", load[2], 101);
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UMA_HISTOGRAM_ENUMERATION("DiskCache.BlockLoad_3", load[3], 101);
338c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
339c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
3403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool BlockFiles::IsValid(Addr address) {
3413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#ifdef NDEBUG
3423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return true;
3433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#else
3443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!address.is_initialized() || address.is_separate_file())
3453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return false;
3463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
3473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  MappedFile* file = GetFile(address);
3483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!file)
3493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return false;
3503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
3513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer());
3523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  bool rv = UsedMapBlock(address.start_block(), address.num_blocks(), header);
3533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK(rv);
3543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
3553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  static bool read_contents = false;
3563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (read_contents) {
3573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    scoped_array<char> buffer;
3583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    buffer.reset(new char[Addr::BlockSizeForFileType(BLOCK_4K) * 4]);
3593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    size_t size = address.BlockSize() * address.num_blocks();
3603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    size_t offset = address.start_block() * address.BlockSize() +
3613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                    kBlockHeaderSize;
3623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    bool ok = file->Read(buffer.get(), size, offset);
3633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    DCHECK(ok);
3643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
3653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
3663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return rv;
3673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#endif
3683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
3693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
370c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool BlockFiles::CreateBlockFile(int index, FileType file_type, bool force) {
371c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  FilePath name = Name(index);
372c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int flags =
373c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      force ? base::PLATFORM_FILE_CREATE_ALWAYS : base::PLATFORM_FILE_CREATE;
374c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  flags |= base::PLATFORM_FILE_WRITE | base::PLATFORM_FILE_EXCLUSIVE_WRITE;
375c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
376c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  scoped_refptr<File> file(new File(
3773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      base::CreatePlatformFile(name, flags, NULL, NULL)));
378c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!file->IsValid())
379c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return false;
380c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
381c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  BlockFileHeader header;
382c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  header.entry_size = Addr::BlockSizeForFileType(file_type);
383c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  header.this_file = static_cast<int16>(index);
384c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(index <= kint16max && index >= 0);
385c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
386c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return file->Write(&header, sizeof(header), 0);
387c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
388c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
389c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool BlockFiles::OpenBlockFile(int index) {
390c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (block_files_.size() - 1 < static_cast<unsigned int>(index)) {
391c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    DCHECK(index > 0);
392c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int to_add = index - static_cast<int>(block_files_.size()) + 1;
393c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    block_files_.resize(block_files_.size() + to_add);
394c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
395c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
396c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  FilePath name = Name(index);
397c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  scoped_refptr<MappedFile> file(new MappedFile());
398c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
399c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!file->Init(name, kBlockHeaderSize)) {
400c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    LOG(ERROR) << "Failed to open " << name.value();
401c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return false;
402c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
403c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t file_len = file->GetLength();
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (file_len < static_cast<size_t>(kBlockHeaderSize)) {
406c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    LOG(ERROR) << "File too small " << name.value();
407c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return false;
408c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
409c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
410c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer());
411c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (kBlockMagic != header->magic || kCurrentVersion != header->version) {
412c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    LOG(ERROR) << "Invalid file version or magic";
413c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return false;
414c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
415c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
416c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (header->updating) {
417c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Last instance was not properly shutdown.
418c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (!FixBlockFileHeader(file))
419c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return false;
420c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
421c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
422d129b9e5870dc7fa49745121bf987e1b6ead1b51Kristian Monsen  if (static_cast<int>(file_len) <
423d129b9e5870dc7fa49745121bf987e1b6ead1b51Kristian Monsen      header->max_entries * header->entry_size + kBlockHeaderSize) {
424d129b9e5870dc7fa49745121bf987e1b6ead1b51Kristian Monsen    LOG(ERROR) << "File too small " << name.value();
425d129b9e5870dc7fa49745121bf987e1b6ead1b51Kristian Monsen    return false;
426d129b9e5870dc7fa49745121bf987e1b6ead1b51Kristian Monsen  }
427d129b9e5870dc7fa49745121bf987e1b6ead1b51Kristian Monsen
428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (index == 0) {
429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Load the links file into memory with a single read.
430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_array<char> buf(new char[file_len]);
431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!file->Read(buf.get(), file_len, 0))
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
435c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(!block_files_[index]);
436c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  file.swap(&block_files_[index]);
437c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return true;
438c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
439c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
440c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool BlockFiles::GrowBlockFile(MappedFile* file, BlockFileHeader* header) {
441c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (kMaxBlocks == header->max_entries)
442c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return false;
443c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
444c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(!header->empty[3]);
445c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int new_size = header->max_entries + 1024;
446c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (new_size > kMaxBlocks)
447c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    new_size = kMaxBlocks;
448c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
449c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int new_size_bytes = new_size * header->entry_size + sizeof(*header);
450c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
451c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  FileLock lock(header);
452c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!file->SetLength(new_size_bytes)) {
453c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Most likely we are trying to truncate the file, so the header is wrong.
454c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (header->updating < 10 && !FixBlockFileHeader(file)) {
455c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // If we can't fix the file increase the lock guard so we'll pick it on
456c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // the next start and replace it.
457c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      header->updating = 100;
458c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return false;
459c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
460c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return (header->max_entries >= new_size);
461c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
462c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
463c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  header->empty[3] = (new_size - header->max_entries) / 4;  // 4 blocks entries
464c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  header->max_entries = new_size;
465c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
466c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return true;
467c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
468c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
469c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottMappedFile* BlockFiles::FileForNewBlock(FileType block_type, int block_count) {
470c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  COMPILE_ASSERT(RANKINGS == 1, invalid_fily_type);
471c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  MappedFile* file = block_files_[block_type - 1];
472c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer());
473c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TimeTicks start = TimeTicks::Now();
475c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  while (NeedToGrowBlockFile(header, block_count)) {
476c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (kMaxBlocks == header->max_entries) {
477c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      file = NextFile(file);
478c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      if (!file)
479c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        return NULL;
480c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      header = reinterpret_cast<BlockFileHeader*>(file->buffer());
481c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      continue;
482c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
483c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
484c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (!GrowBlockFile(file, header))
485c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return NULL;
486c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    break;
487c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  HISTOGRAM_TIMES("DiskCache.GetFileForNewBlock", TimeTicks::Now() - start);
489c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return file;
490c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
491c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
492c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottMappedFile* BlockFiles::NextFile(const MappedFile* file) {
493c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer());
494c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int new_file = header->next_file;
495c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!new_file) {
496c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // RANKINGS is not reported as a type for small entries, but we may be
497c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // extending the rankings block file.
498c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    FileType type = Addr::RequiredFileType(header->entry_size);
499c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (header->entry_size == Addr::BlockSizeForFileType(RANKINGS))
500c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      type = RANKINGS;
501c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
502c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    new_file = CreateNextBlockFile(type);
503c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (!new_file)
504c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return NULL;
505c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
506c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    FileLock lock(header);
507c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    header->next_file = new_file;
508c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
509c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
510c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Only the block_file argument is relevant for what we want.
511c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Addr address(BLOCK_256, 1, new_file, 0);
512c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return GetFile(address);
513c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
514c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
515c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint BlockFiles::CreateNextBlockFile(FileType block_type) {
516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (int i = kFirstAdditionalBlockFile; i <= kMaxBlockFile; i++) {
517c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (CreateBlockFile(i, block_type, false))
518c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return i;
519c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
520c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return 0;
521c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
522c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
523c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// We walk the list of files for this particular block type, deleting the ones
524c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// that are empty.
525c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid BlockFiles::RemoveEmptyFile(FileType block_type) {
526c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  MappedFile* file = block_files_[block_type - 1];
527c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer());
528c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
529c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  while (header->next_file) {
530c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Only the block_file argument is relevant for what we want.
531c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    Addr address(BLOCK_256, 1, header->next_file, 0);
532c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    MappedFile* next_file = GetFile(address);
533c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (!next_file)
534c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return;
535c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
536c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    BlockFileHeader* next_header =
537c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        reinterpret_cast<BlockFileHeader*>(next_file->buffer());
538c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (!next_header->num_entries) {
539c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      DCHECK_EQ(next_header->entry_size, header->entry_size);
540c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // Delete next_file and remove it from the chain.
541c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      int file_index = header->next_file;
542c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      header->next_file = next_header->next_file;
543c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      DCHECK(block_files_.size() >= static_cast<unsigned int>(file_index));
5443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
5453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      // We get a new handle to the file and release the old one so that the
5463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      // file gets unmmaped... so we can delete it.
5473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      FilePath name = Name(file_index);
5483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      scoped_refptr<File> this_file(new File(false));
5493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      this_file->Init(name);
550c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      block_files_[file_index]->Release();
551c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      block_files_[file_index] = NULL;
552c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
553c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      int failure = DeleteCacheFile(name) ? 0 : 1;
554c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      UMA_HISTOGRAM_COUNTS("DiskCache.DeleteFailed2", failure);
555c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      if (failure)
556c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        LOG(ERROR) << "Failed to delete " << name.value() << " from the cache.";
557c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      continue;
558c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
559c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
560c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    header = next_header;
561c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    file = next_file;
562c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
563c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
564c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
565c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool BlockFiles::FixBlockFileHeader(MappedFile* file) {
566c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer());
567c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int file_size = static_cast<int>(file->GetLength());
568c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (file_size < static_cast<int>(sizeof(*header)))
569c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return false;  // file_size > 2GB is also an error.
570c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
571c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int expected = header->entry_size * header->max_entries + sizeof(*header);
572c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (file_size != expected) {
573c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int max_expected = header->entry_size * kMaxBlocks + sizeof(*header);
574c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (file_size < expected || header->empty[3] || file_size > max_expected) {
575c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      NOTREACHED();
576c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      LOG(ERROR) << "Unexpected file size";
577c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return false;
578c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
579c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // We were in the middle of growing the file.
580c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int num_entries = (file_size - sizeof(*header)) / header->entry_size;
581c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    header->max_entries = num_entries;
582c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
583c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
584c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  FixAllocationCounters(header);
585c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  header->updating = 0;
586c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return true;
587c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
588c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
5893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// We are interested in the total number of blocks used by this file type, and
590c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// the max number of blocks that we can store (reported as the percentage of
591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// used blocks). In order to find out the number of used blocks, we have to
592c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// substract the empty blocks from the total blocks for each file in the chain.
593c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BlockFiles::GetFileStats(int index, int* used_count, int* load) {
594c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int max_blocks = 0;
595c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *used_count = 0;
596c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *load = 0;
597c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (;;) {
598c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!block_files_[index] && !OpenBlockFile(index))
599c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
600c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
601c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    BlockFileHeader* header =
602c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        reinterpret_cast<BlockFileHeader*>(block_files_[index]->buffer());
603c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
604c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    max_blocks += header->max_entries;
605c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int used = header->max_entries;
606c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (int i = 0; i < 4; i++) {
607c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      used -= header->empty[i] * (i + 1);
608c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      DCHECK_GE(used, 0);
609c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
610c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    *used_count += used;
611c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
612c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!header->next_file)
613c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
614c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    index = header->next_file;
615c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
616c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (max_blocks)
617c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    *load = *used_count * 100 / max_blocks;
618c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
619c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
620c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochFilePath BlockFiles::Name(int index) {
621c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The file format allows for 256 files.
622c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(index < 256 || index >= 0);
6233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  std::string tmp = base::StringPrintf("%s%d", kBlockName, index);
624c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return path_.AppendASCII(tmp);
625c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
626c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
627c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}  // namespace disk_cache
628