| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <algorithm> |
| |
| #include "base/logging.h" |
| #include "net/disk_cache/flash/format.h" |
| #include "net/disk_cache/flash/segment.h" |
| #include "net/disk_cache/flash/storage.h" |
| |
| namespace disk_cache { |
| |
| Segment::Segment(int32 index, bool read_only, Storage* storage) |
| : index_(index), |
| num_users_(0), |
| read_only_(read_only), |
| init_(false), |
| storage_(storage), |
| offset_(index * kFlashSegmentSize), |
| summary_offset_(offset_ + kFlashSegmentSize - kFlashSummarySize), |
| write_offset_(offset_) { |
| DCHECK(storage); |
| DCHECK(storage->size() % kFlashSegmentSize == 0); |
| } |
| |
| Segment::~Segment() { |
| DCHECK(!init_ || read_only_); |
| if (num_users_ != 0) |
| LOG(WARNING) << "Users exist, but we don't care? " << num_users_; |
| } |
| |
| bool Segment::HaveOffset(int32 offset) const { |
| DCHECK(init_); |
| return std::binary_search(offsets_.begin(), offsets_.end(), offset); |
| } |
| |
| void Segment::AddUser() { |
| DCHECK(init_); |
| ++num_users_; |
| } |
| |
| void Segment::ReleaseUser() { |
| DCHECK(init_); |
| --num_users_; |
| } |
| |
| bool Segment::HasNoUsers() const { |
| DCHECK(init_); |
| return num_users_ == 0; |
| } |
| |
| bool Segment::Init() { |
| DCHECK(!init_); |
| |
| if (offset_ < 0 || offset_ + kFlashSegmentSize > storage_->size()) |
| return false; |
| |
| if (!read_only_) { |
| init_ = true; |
| return true; |
| } |
| |
| int32 summary[kFlashMaxEntryCount + 1]; |
| if (!storage_->Read(summary, kFlashSummarySize, summary_offset_)) |
| return false; |
| |
| size_t entry_count = summary[0]; |
| DCHECK_LE(entry_count, kFlashMaxEntryCount); |
| |
| std::vector<int32> tmp(summary + 1, summary + 1 + entry_count); |
| offsets_.swap(tmp); |
| init_ = true; |
| return true; |
| } |
| |
| bool Segment::WriteData(const void* buffer, int32 size) { |
| DCHECK(init_ && !read_only_); |
| DCHECK(write_offset_ + size <= summary_offset_); |
| if (!storage_->Write(buffer, size, write_offset_)) |
| return false; |
| write_offset_ += size; |
| return true; |
| } |
| |
| void Segment::StoreOffset(int32 offset) { |
| DCHECK(init_ && !read_only_); |
| DCHECK(offsets_.size() < kFlashMaxEntryCount); |
| offsets_.push_back(offset); |
| } |
| |
| bool Segment::ReadData(void* buffer, int32 size, int32 offset) const { |
| DCHECK(init_); |
| DCHECK(offset >= offset_ && offset + size <= offset_ + kFlashSegmentSize); |
| return storage_->Read(buffer, size, offset); |
| } |
| |
| bool Segment::Close() { |
| DCHECK(init_); |
| if (read_only_) |
| return true; |
| |
| DCHECK(offsets_.size() <= kFlashMaxEntryCount); |
| |
| int32 summary[kFlashMaxEntryCount + 1]; |
| memset(summary, 0, kFlashSummarySize); |
| summary[0] = offsets_.size(); |
| std::copy(offsets_.begin(), offsets_.end(), summary + 1); |
| if (!storage_->Write(summary, kFlashSummarySize, summary_offset_)) |
| return false; |
| |
| read_only_ = true; |
| return true; |
| } |
| |
| bool Segment::CanHold(int32 size) const { |
| DCHECK(init_); |
| return offsets_.size() < kFlashMaxEntryCount && |
| write_offset_ + size <= summary_offset_; |
| } |
| |
| } // namespace disk_cache |