Home | History | Annotate | Download | only in src
      1 // Copyright 2008 Google Inc. All Rights Reserved.
      2 
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 
      7 //      http://www.apache.org/licenses/LICENSE-2.0
      8 
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 // Interface for a thread-safe container of disk blocks
     16 
     17 #ifndef STRESSAPPTEST_DISK_BLOCKS_H_
     18 #define STRESSAPPTEST_DISK_BLOCKS_H_
     19 
     20 #include <sys/types.h>
     21 #include <pthread.h>
     22 #include <time.h>
     23 #include <sys/time.h>
     24 #include <errno.h>
     25 #include <map>
     26 #include <vector>
     27 #include <string>
     28 
     29 #include "sattypes.h"
     30 
     31 class Pattern;
     32 
     33 // Data about a block written to disk so that it can be verified later.
     34 // Thread-unsafe, must be used with locks on non-const methods,
     35 // except for initialized accessor/mutator, which are thread-safe
     36 // (and in fact, is the only method supposed to be accessed from
     37 // someone which is not the thread-safe DiskBlockTable).
     38 class BlockData {
     39  public:
     40   BlockData();
     41   ~BlockData();
     42 
     43   // These are reference counters used to control how many
     44   // threads currently have a copy of this particular block.
     45   void IncreaseReferenceCounter() { references_++; }
     46   void DecreaseReferenceCounter() { references_--; }
     47   int GetReferenceCounter() const { return references_; }
     48 
     49   // Controls whether the block was written on disk or not.
     50   // Once written, you cannot "un-written" then without destroying
     51   // this object.
     52   void set_initialized();
     53   bool initialized() const;
     54 
     55   // Accessor methods for some data related to blocks.
     56   void set_address(uint64 address) { address_ = address; }
     57   uint64 address() const { return address_; }
     58   void set_size(uint64 size) { size_ = size; }
     59   uint64 size() const { return size_; }
     60   void set_pattern(Pattern *p) { pattern_ = p; }
     61   Pattern *pattern() { return pattern_; }
     62  private:
     63   uint64 address_;  // Address of first sector in block
     64   uint64 size_;  // Size of block
     65   int references_;  // Reference counter
     66   bool initialized_;  // Flag indicating the block was written on disk
     67   Pattern *pattern_;
     68   mutable pthread_mutex_t data_mutex_;
     69   DISALLOW_COPY_AND_ASSIGN(BlockData);
     70 };
     71 
     72 // A thread-safe table used to store block data and control access
     73 // to these blocks, letting several threads read and write blocks on
     74 // disk.
     75 class DiskBlockTable {
     76  public:
     77   DiskBlockTable();
     78   virtual ~DiskBlockTable();
     79 
     80   // Returns number of elements stored on table.
     81   uint64 Size();
     82 
     83   // Sets all initial parameters. Assumes all existent data is
     84   // invalid and, therefore, must be removed.
     85   void SetParameters(int sector_size, int write_block_size,
     86                      int64 device_sectors,
     87                      int64 segment_size,
     88                      const string& device_name);
     89 
     90   // During the regular execution, there will be 2 types of threads:
     91   // - Write thread:  gets a large number of blocks using GetUnusedBlock,
     92   //                  writes them on disk (if on destructive mode),
     93   //                  reads block content ONCE from disk and them removes
     94   //                  the block from queue with RemoveBlock. After a removal a
     95   //                  block is not available for read threads, but it is
     96   //                  only removed from memory if there is no reference for
     97   //                  this block. Note that a write thread also counts as
     98   //                  a reference.
     99   // - Read threads:  get one block at a time (if available) with
    100   //                  GetRandomBlock, reads its content from disk,
    101   //                  checking whether it is correct or not, and releases
    102   //                  (Using ReleaseBlock) the block to be erased by the
    103   //                  write threads. Since several read threads are allowed
    104   //                  to read the same block, a reference counter is used to
    105   //                  control when the block can be REALLY erased from
    106   //                  memory, and all memory management is made by a
    107   //                  DiskBlockTable instance.
    108 
    109   // Returns a new block in a unused address. Does not
    110   // grant ownership of the pointer to the caller
    111   // (use RemoveBlock to delete the block from memory instead).
    112   BlockData *GetUnusedBlock(int64 segment);
    113 
    114   // Removes block from structure (called by write threads). Returns
    115   // 1 if successful, 0 otherwise.
    116   int RemoveBlock(BlockData *block);
    117 
    118   // Gets a random block from the list. Only returns if an element
    119   // is available (a write thread has got this block, written it on disk,
    120   // and set this block as initialized). Does not grant ownership of the
    121   // pointer to the caller (use RemoveBlock to delete the block from
    122   // memory instead).
    123   BlockData *GetRandomBlock();
    124 
    125   // Releases block to be erased (called by random threads). Returns
    126   // 1 if successful, 0 otherwise.
    127   int ReleaseBlock(BlockData *block);
    128 
    129  protected:
    130   struct StorageData {
    131     BlockData *block;
    132     int pos;
    133   };
    134   typedef map<int64, StorageData*> AddrToBlockMap;
    135   typedef vector<int64> PosToAddrVector;
    136 
    137   // Inserts block in structure, used in tests and by other methods.
    138   void InsertOnStructure(BlockData *block);
    139 
    140   // Generates a random 64-bit integer.
    141   // Virtual method so it can be overridden by the tests.
    142   virtual int64 Random64();
    143 
    144   // Accessor methods for testing.
    145   const PosToAddrVector& pos_to_addr() const { return pos_to_addr_; }
    146   const AddrToBlockMap& addr_to_block() const { return addr_to_block_; }
    147 
    148   int sector_size() const { return sector_size_; }
    149   int write_block_size() const { return write_block_size_; }
    150   const string& device_name() const { return device_name_; }
    151   int64 device_sectors() const { return device_sectors_; }
    152   int64 segment_size() const { return segment_size_; }
    153 
    154  private:
    155   // Number of retries to allocate sectors.
    156   static const int kBlockRetry = 100;
    157   // Actual tables.
    158   PosToAddrVector pos_to_addr_;
    159   AddrToBlockMap addr_to_block_;
    160 
    161   // Configuration parameters for block selection
    162   int sector_size_;  // Sector size, in bytes
    163   int write_block_size_;  // Block size, in bytes
    164   string device_name_;  // Device name
    165   int64 device_sectors_;  // Number of sectors in device
    166   int64 segment_size_;  // Segment size in bytes
    167   uint64 size_;  // Number of elements on table
    168   pthread_mutex_t data_mutex_;
    169   pthread_cond_t data_condition_;
    170   pthread_mutex_t parameter_mutex_;
    171   DISALLOW_COPY_AND_ASSIGN(DiskBlockTable);
    172 };
    173 
    174 #endif  // STRESSAPPTEST_BLOCKS_H_
    175