1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef NET_DISK_CACHE_BLOCKFILE_STORAGE_BLOCK_INL_H_
6#define NET_DISK_CACHE_BLOCKFILE_STORAGE_BLOCK_INL_H_
7
8#include "net/disk_cache/blockfile/storage_block.h"
9
10#include "base/hash.h"
11#include "base/logging.h"
12#include "net/disk_cache/blockfile/trace.h"
13
14namespace disk_cache {
15
16template<typename T> StorageBlock<T>::StorageBlock(MappedFile* file,
17                                                   Addr address)
18    : data_(NULL), file_(file), address_(address), modified_(false),
19      own_data_(false), extended_(false) {
20  if (address.num_blocks() > 1)
21    extended_ = true;
22  DCHECK(!address.is_initialized() || sizeof(*data_) == address.BlockSize());
23}
24
25template<typename T> StorageBlock<T>::~StorageBlock() {
26  if (modified_)
27    Store();
28  DeleteData();
29}
30
31template<typename T> void* StorageBlock<T>::buffer() const {
32  return data_;
33}
34
35template<typename T> size_t StorageBlock<T>::size() const {
36  if (!extended_)
37    return sizeof(*data_);
38  return address_.num_blocks() * sizeof(*data_);
39}
40
41template<typename T> int StorageBlock<T>::offset() const {
42  return address_.start_block() * address_.BlockSize();
43}
44
45template<typename T> bool StorageBlock<T>::LazyInit(MappedFile* file,
46                                                    Addr address) {
47  if (file_ || address_.is_initialized()) {
48    NOTREACHED();
49    return false;
50  }
51  file_ = file;
52  address_.set_value(address.value());
53  if (address.num_blocks() > 1)
54    extended_ = true;
55
56  DCHECK(sizeof(*data_) == address.BlockSize());
57  return true;
58}
59
60template<typename T> void StorageBlock<T>::SetData(T* other) {
61  DCHECK(!modified_);
62  DeleteData();
63  data_ = other;
64}
65
66template<typename T> void  StorageBlock<T>::Discard() {
67  if (!data_)
68    return;
69  if (!own_data_) {
70    NOTREACHED();
71    return;
72  }
73  DeleteData();
74  data_ = NULL;
75  modified_ = false;
76  extended_ = false;
77}
78
79template<typename T> void  StorageBlock<T>::StopSharingData() {
80  if (!data_ || own_data_)
81    return;
82  DCHECK(!modified_);
83  data_ = NULL;
84}
85
86template<typename T> void StorageBlock<T>::set_modified() {
87  DCHECK(data_);
88  modified_ = true;
89}
90
91template<typename T> void StorageBlock<T>::clear_modified() {
92  modified_ = false;
93}
94
95template<typename T> T* StorageBlock<T>::Data() {
96  if (!data_)
97    AllocateData();
98  return data_;
99}
100
101template<typename T> bool StorageBlock<T>::HasData() const {
102  return (NULL != data_);
103}
104
105template<typename T> bool StorageBlock<T>::VerifyHash() const {
106  uint32 hash = CalculateHash();
107  return (!data_->self_hash || data_->self_hash == hash);
108}
109
110template<typename T> bool StorageBlock<T>::own_data() const {
111  return own_data_;
112}
113
114template<typename T> const Addr StorageBlock<T>::address() const {
115  return address_;
116}
117
118template<typename T> bool StorageBlock<T>::Load() {
119  if (file_) {
120    if (!data_)
121      AllocateData();
122
123    if (file_->Load(this)) {
124      modified_ = false;
125      return true;
126    }
127  }
128  LOG(WARNING) << "Failed data load.";
129  Trace("Failed data load.");
130  return false;
131}
132
133template<typename T> bool StorageBlock<T>::Store() {
134  if (file_ && data_) {
135    data_->self_hash = CalculateHash();
136    if (file_->Store(this)) {
137      modified_ = false;
138      return true;
139    }
140  }
141  LOG(ERROR) << "Failed data store.";
142  Trace("Failed data store.");
143  return false;
144}
145
146template<typename T> bool StorageBlock<T>::Load(FileIOCallback* callback,
147                                                bool* completed) {
148  if (file_) {
149    if (!data_)
150      AllocateData();
151
152    if (file_->Load(this, callback, completed)) {
153      modified_ = false;
154      return true;
155    }
156  }
157  LOG(WARNING) << "Failed data load.";
158  Trace("Failed data load.");
159  return false;
160}
161
162template<typename T> bool StorageBlock<T>::Store(FileIOCallback* callback,
163                                                 bool* completed) {
164  if (file_ && data_) {
165    data_->self_hash = CalculateHash();
166    if (file_->Store(this, callback, completed)) {
167      modified_ = false;
168      return true;
169    }
170  }
171  LOG(ERROR) << "Failed data store.";
172  Trace("Failed data store.");
173  return false;
174}
175
176template<typename T> void StorageBlock<T>::AllocateData() {
177  DCHECK(!data_);
178  if (!extended_) {
179    data_ = new T;
180  } else {
181    void* buffer = new char[address_.num_blocks() * sizeof(*data_)];
182    data_ = new(buffer) T;
183  }
184  own_data_ = true;
185}
186
187template<typename T> void StorageBlock<T>::DeleteData() {
188  if (own_data_) {
189    if (!extended_) {
190      delete data_;
191    } else {
192      data_->~T();
193      delete[] reinterpret_cast<char*>(data_);
194    }
195    own_data_ = false;
196  }
197}
198
199template<typename T> uint32 StorageBlock<T>::CalculateHash() const {
200  return base::Hash(reinterpret_cast<char*>(data_), offsetof(T, self_hash));
201}
202
203}  // namespace disk_cache
204
205#endif  // NET_DISK_CACHE_BLOCKFILE_STORAGE_BLOCK_INL_H_
206