Home | History | Annotate | Download | only in flash
      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 #include "base/logging.h"
      6 #include "base/memory/scoped_ptr.h"
      7 #include "base/stl_util.h"
      8 #include "net/disk_cache/flash/format.h"
      9 #include "net/disk_cache/flash/log_store.h"
     10 #include "net/disk_cache/flash/segment.h"
     11 #include "net/disk_cache/flash/storage.h"
     12 
     13 namespace disk_cache {
     14 
     15 LogStore::LogStore(const base::FilePath& path, int32 size)
     16     : storage_(path, size),
     17       num_segments_(size / kFlashSegmentSize),
     18       open_segments_(num_segments_),
     19       write_index_(0),
     20       current_entry_id_(-1),
     21       current_entry_num_bytes_left_to_write_(0),
     22       init_(false),
     23       closed_(false) {
     24   DCHECK(size % kFlashSegmentSize == 0);
     25 }
     26 
     27 LogStore::~LogStore() {
     28   DCHECK(!init_ || closed_);
     29   STLDeleteElements(&open_segments_);
     30 }
     31 
     32 bool LogStore::Init() {
     33   DCHECK(!init_);
     34   if (!storage_.Init())
     35     return false;
     36 
     37   // TODO(agayev): Once we start persisting segment metadata to disk, we will
     38   // start from where we left off during the last shutdown.
     39   scoped_ptr<Segment> segment(new Segment(write_index_, false, &storage_));
     40   if (!segment->Init())
     41     return false;
     42 
     43   segment->AddUser();
     44   open_segments_[write_index_] = segment.release();
     45   init_ = true;
     46   return true;
     47 }
     48 
     49 bool LogStore::Close() {
     50   DCHECK(init_ && !closed_);
     51   open_segments_[write_index_]->ReleaseUser();
     52   if (!open_segments_[write_index_]->Close())
     53     return false;
     54   closed_ = true;
     55   return true;
     56   // TODO(agayev): persist metadata to disk.
     57 }
     58 
     59 bool LogStore::CreateEntry(int32 size, int32* id) {
     60   DCHECK(init_ && !closed_);
     61   DCHECK(current_entry_id_ == -1 && size <= disk_cache::kFlashSegmentFreeSpace);
     62 
     63   // TODO(agayev): Avoid large entries from leaving the segments almost empty.
     64   if (!open_segments_[write_index_]->CanHold(size)) {
     65     if (!open_segments_[write_index_]->Close())
     66       return false;
     67 
     68     open_segments_[write_index_]->ReleaseUser();
     69     if (open_segments_[write_index_]->HasNoUsers()) {
     70       delete open_segments_[write_index_];
     71       open_segments_[write_index_] = NULL;
     72     }
     73 
     74     write_index_ = GetNextSegmentIndex();
     75     scoped_ptr<Segment> segment(new Segment(write_index_, false, &storage_));
     76     if (!segment->Init())
     77       return false;
     78 
     79     segment->AddUser();
     80     open_segments_[write_index_] = segment.release();
     81   }
     82 
     83   *id = open_segments_[write_index_]->write_offset();
     84   open_segments_[write_index_]->StoreOffset(*id);
     85   current_entry_id_ = *id;
     86   current_entry_num_bytes_left_to_write_ = size;
     87   open_entries_.insert(current_entry_id_);
     88   return true;
     89 }
     90 
     91 void LogStore::DeleteEntry(int32 id, int32 size) {
     92   DCHECK(init_ && !closed_);
     93   DCHECK(open_entries_.find(id) == open_entries_.end());
     94   // TODO(agayev): Increment the number of dead bytes in the segment metadata
     95   // for the segment identified by |index|.
     96 }
     97 
     98 bool LogStore::WriteData(const void* buffer, int32 size) {
     99   DCHECK(init_ && !closed_);
    100   DCHECK(current_entry_id_ != -1 &&
    101          size <= current_entry_num_bytes_left_to_write_);
    102   if (open_segments_[write_index_]->WriteData(buffer, size)) {
    103     current_entry_num_bytes_left_to_write_ -= size;
    104     return true;
    105   }
    106   return false;
    107 }
    108 
    109 bool LogStore::OpenEntry(int32 id) {
    110   DCHECK(init_ && !closed_);
    111   if (open_entries_.find(id) != open_entries_.end())
    112     return false;
    113 
    114   // Segment is already open.
    115   int32 index = id / disk_cache::kFlashSegmentSize;
    116   if (open_segments_[index]) {
    117     if (!open_segments_[index]->HaveOffset(id))
    118       return false;
    119     open_segments_[index]->AddUser();
    120     open_entries_.insert(id);
    121     return true;
    122   }
    123 
    124   // Segment is not open.
    125   scoped_ptr<Segment> segment(new Segment(index, true, &storage_));
    126   if (!segment->Init() || !segment->HaveOffset(id))
    127     return false;
    128 
    129   segment->AddUser();
    130   open_segments_[index] = segment.release();
    131   open_entries_.insert(id);
    132   return true;
    133 }
    134 
    135 bool LogStore::ReadData(int32 id, void* buffer, int32 size,
    136                                   int32 offset) const {
    137   DCHECK(init_ && !closed_);
    138   DCHECK(open_entries_.find(id) != open_entries_.end());
    139 
    140   int32 index = id / disk_cache::kFlashSegmentSize;
    141   DCHECK(open_segments_[index] && open_segments_[index]->HaveOffset(id));
    142   return open_segments_[index]->ReadData(buffer, size, id + offset);
    143 }
    144 
    145 void LogStore::CloseEntry(int32 id) {
    146   DCHECK(init_ && !closed_);
    147   std::set<int32>::iterator entry_iter = open_entries_.find(id);
    148   DCHECK(entry_iter != open_entries_.end());
    149 
    150   if (current_entry_id_ != -1) {
    151     DCHECK(id == current_entry_id_ && !current_entry_num_bytes_left_to_write_);
    152     open_entries_.erase(entry_iter);
    153     current_entry_id_ = -1;
    154     return;
    155   }
    156 
    157   int32 index = id / disk_cache::kFlashSegmentSize;
    158   DCHECK(open_segments_[index]);
    159   open_entries_.erase(entry_iter);
    160 
    161   open_segments_[index]->ReleaseUser();
    162   if (open_segments_[index]->HasNoUsers()) {
    163     delete open_segments_[index];
    164     open_segments_[index] = NULL;
    165   }
    166 }
    167 
    168 int32 LogStore::GetNextSegmentIndex() {
    169   DCHECK(init_ && !closed_);
    170   int32 next_index = (write_index_ + 1) % num_segments_;
    171 
    172   while (InUse(next_index)) {
    173     next_index = (next_index + 1) % num_segments_;
    174     DCHECK_NE(next_index, write_index_);
    175   }
    176   return next_index;
    177 }
    178 
    179 bool LogStore::InUse(int32 index) const {
    180   DCHECK(init_ && !closed_);
    181   DCHECK(index >= 0 && index < num_segments_);
    182   return open_segments_[index] != NULL;
    183 }
    184 
    185 }  // namespace disk_cache
    186