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. IncreaseReferenceCounter()45 void IncreaseReferenceCounter() { references_++; } DecreaseReferenceCounter()46 void DecreaseReferenceCounter() { references_--; } GetReferenceCounter()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. set_address(uint64 address)56 void set_address(uint64 address) { address_ = address; } address()57 uint64 address() const { return address_; } set_size(uint64 size)58 void set_size(uint64 size) { size_ = size; } size()59 uint64 size() const { return size_; } set_pattern(Pattern * p)60 void set_pattern(Pattern *p) { pattern_ = p; } pattern()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. pos_to_addr()145 const PosToAddrVector& pos_to_addr() const { return pos_to_addr_; } addr_to_block()146 const AddrToBlockMap& addr_to_block() const { return addr_to_block_; } 147 sector_size()148 int sector_size() const { return sector_size_; } write_block_size()149 int write_block_size() const { return write_block_size_; } device_name()150 const string& device_name() const { return device_name_; } device_sectors()151 int64 device_sectors() const { return device_sectors_; } segment_size()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