// 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. #ifndef NET_DISK_CACHE_FLASH_SEGMENT_H_ #define NET_DISK_CACHE_FLASH_SEGMENT_H_ #include <vector> #include "base/basictypes.h" #include "base/gtest_prod_util.h" #include "net/base/net_export.h" namespace disk_cache { class Storage; // The underlying storage represented by Storage class, is divided into fixed // size logical segments, represented by this class. Since segment size is // fixed, the storage size should be a multiple of segment size. The picture // below describes the relation between storage and segments: // // |-----------+-----------+-----+-------------+-----------| // | segment 0 | segment 1 | ... | segment n-1 | segment n | // |-----------+-----------+-----+-------------+-----------| // // |-------------------------------------------------------| // | storage | // |-------------------------------------------------------| // // A segment is constructed by taking its index within the storage, a flag // indicating whether it is a read-only segment and a pointer to the storage on // which it resides. It provides an API for reading/writing entries residing on // it. Init() function must be called right after the construction of a segment // and one should proceed to calling other functions only if Init() has // succeeded. After a successful initialization, one may proceed to call // non-mutating functions; mutating functions can be called if the segment is // not read-only. Finally, Close() function must be called right before the // destruction. Calling Close() makes the segment immutable, which means // mutating functions cannot be called on the object after that. // // Segment can only be used as a log, i.e. all writes are laid out sequentially // on a segment. As a result, WriteData() function does not take an offset. // Current write offset can be learned by calling write_offset(). // // Once the entries are written to the Segment and Close() called on it and the // object destroyed, we should later be able to instantiate a read-only Segment // object and recreate all the entries that were previously written to it. To // achieve this, a tiny region of Segment is used for its metadata and Segment // provides two calls for interacting with metadata: StoreOffset() and // GetOffsets(). The former can be used to store an offset that was returned by // write_offset() and the latter can be used to retrieve all the offsets that // were stored in the Segment. Before attempting to write an entry, the client // should call CanHold() to make sure that there is enough space in the segment. // // ReadData can be called over the range that was previously written with // WriteData. Reading from area that was not written will fail. class NET_EXPORT_PRIVATE Segment { public: // |index| is the index of this segment on |storage|. If the storage size is // X and the segment size is Y, where X >> Y and X % Y == 0, then the valid // values for the index are integers within the range [0, X/Y). Thus, if // |index| is given value Z, then it covers bytes on storage starting at the // offset Z*Y and ending at the offset Z*Y+Y-1. Segment(int32 index, bool read_only, Storage* storage); ~Segment(); int32 index() const { return index_; } int32 write_offset() const { return write_offset_; } bool HaveOffset(int32 offset) const; std::vector<int32> GetOffsets() const { return offsets_; } // Manage the number of users of this segment. void AddUser(); void ReleaseUser(); bool HasNoUsers() const; // Performs segment initialization. Must be the first function called on the // segment and further calls should be made only if it is successful. bool Init(); // Writes |size| bytes of data from |buffer| to segment, returns false if // fails and true if succeeds. Can block for a long time. bool WriteData(const void* buffer, int32 size); // Reads |size| bytes of data living at |offset| into |buffer| returns true on // success and false on failure. bool ReadData(void* buffer, int32 size, int32 offset) const; // Stores the offset in the metadata. void StoreOffset(int32 offset); // Closes the segment, returns true on success and false on failure. Closing // a segment makes it immutable. bool Close(); // Returns true if segment can accommodate an entry of |size| bytes. bool CanHold(int32 size) const; private: int32 index_; int32 num_users_; bool read_only_; // Indicates whether the segment can be written to. bool init_; // Indicates whether segment was initialized. Storage* storage_; // Storage on which the segment resides. const int32 offset_; // Offset of the segment on |storage_|. const int32 summary_offset_; // Offset of the segment summary. int32 write_offset_; // Current write offset. std::vector<int32> offsets_; DISALLOW_COPY_AND_ASSIGN(Segment); }; } // namespace disk_cache #endif // NET_DISK_CACHE_FLASH_SEGMENT_H_