1b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Copyright 2008 Google Inc. All Rights Reserved. 2b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson 3b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Licensed under the Apache License, Version 2.0 (the "License"); 4b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// you may not use this file except in compliance with the License. 5b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// You may obtain a copy of the License at 6b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson 7b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// http://www.apache.org/licenses/LICENSE-2.0 8b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson 9b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Unless required by applicable law or agreed to in writing, software 10b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// distributed under the License is distributed on an "AS IS" BASIS, 11b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// See the License for the specific language governing permissions and 13b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// limitations under the License. 14b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson 15b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Interface for a thread-safe container of disk blocks 16b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson 17b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#ifndef STRESSAPPTEST_DISK_BLOCKS_H_ 18b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#define STRESSAPPTEST_DISK_BLOCKS_H_ 19b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson 20b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include <sys/types.h> 21b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include <pthread.h> 22b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include <time.h> 23b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include <sys/time.h> 24b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include <errno.h> 25b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include <map> 26b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include <vector> 27b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#include <string> 28241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders 29241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders#include "sattypes.h" 30241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders 31241f33a3e958842e3db803c03300764bd2ee9c19Nick Sandersclass Pattern; 32b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson 33b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson// Data about a block written to disk so that it can be verified later. 34241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders// Thread-unsafe, must be used with locks on non-const methods, 35241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders// except for initialized accessor/mutator, which are thread-safe 36241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders// (and in fact, is the only method supposed to be accessed from 37241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders// someone which is not the thread-safe DiskBlockTable). 38b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonclass BlockData { 39b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson public: 40b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson BlockData(); 41b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson ~BlockData(); 42241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders 43241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // These are reference counters used to control how many 44241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // threads currently have a copy of this particular block. 45241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders void IncreaseReferenceCounter() { references_++; } 46241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders void DecreaseReferenceCounter() { references_--; } 47241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders int GetReferenceCounter() const { return references_; } 48241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders 49241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // Controls whether the block was written on disk or not. 50241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // Once written, you cannot "un-written" then without destroying 51241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // this object. 52241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders void set_initialized(); 53241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders bool initialized() const; 54241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders 55241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // Accessor methods for some data related to blocks. 56241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders void set_address(uint64 address) { address_ = address; } 57241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders uint64 address() const { return address_; } 58241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders void set_size(uint64 size) { size_ = size; } 59241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders uint64 size() const { return size_; } 60241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders void set_pattern(Pattern *p) { pattern_ = p; } 61241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders Pattern *pattern() { return pattern_; } 62241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders private: 63241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders uint64 address_; // Address of first sector in block 64241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders uint64 size_; // Size of block 65241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders int references_; // Reference counter 66241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders bool initialized_; // Flag indicating the block was written on disk 67b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson Pattern *pattern_; 68241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders mutable pthread_mutex_t data_mutex_; 69b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson DISALLOW_COPY_AND_ASSIGN(BlockData); 70b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}; 71b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson 72241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders// A thread-safe table used to store block data and control access 73241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders// to these blocks, letting several threads read and write blocks on 74241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders// disk. 75b0114cb9f332db144f65291211ae65f7f0e814e6Scott Andersonclass DiskBlockTable { 76b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson public: 77b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson DiskBlockTable(); 78b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson virtual ~DiskBlockTable(); 79b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson 80241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // Returns number of elements stored on table. 81241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders uint64 Size(); 82241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders 83241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // Sets all initial parameters. Assumes all existent data is 84b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson // invalid and, therefore, must be removed. 85b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson void SetParameters(int sector_size, int write_block_size, 86b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson int64 device_sectors, 87b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson int64 segment_size, 88241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders const string& device_name); 89241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders 90241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // During the regular execution, there will be 2 types of threads: 91241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // - Write thread: gets a large number of blocks using GetUnusedBlock, 92241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // writes them on disk (if on destructive mode), 93241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // reads block content ONCE from disk and them removes 94241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // the block from queue with RemoveBlock. After a removal a 95241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // block is not available for read threads, but it is 96241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // only removed from memory if there is no reference for 97241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // this block. Note that a write thread also counts as 98241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // a reference. 99241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // - Read threads: get one block at a time (if available) with 100241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // GetRandomBlock, reads its content from disk, 101241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // checking whether it is correct or not, and releases 102241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // (Using ReleaseBlock) the block to be erased by the 103241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // write threads. Since several read threads are allowed 104241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // to read the same block, a reference counter is used to 105241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // control when the block can be REALLY erased from 106241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // memory, and all memory management is made by a 107241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // DiskBlockTable instance. 108241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders 109241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // Returns a new block in a unused address. Does not 110241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // grant ownership of the pointer to the caller 111241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // (use RemoveBlock to delete the block from memory instead). 112b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson BlockData *GetUnusedBlock(int64 segment); 113241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders 114241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // Removes block from structure (called by write threads). Returns 115241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // 1 if successful, 0 otherwise. 116b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson int RemoveBlock(BlockData *block); 117b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson 118241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // Gets a random block from the list. Only returns if an element 119241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // is available (a write thread has got this block, written it on disk, 120241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // and set this block as initialized). Does not grant ownership of the 121241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // pointer to the caller (use RemoveBlock to delete the block from 122241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // memory instead). 123241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders BlockData *GetRandomBlock(); 124b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson 125241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // Releases block to be erased (called by random threads). Returns 126241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // 1 if successful, 0 otherwise. 127241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders int ReleaseBlock(BlockData *block); 128b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson 129241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders protected: 130b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson struct StorageData { 131b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson BlockData *block; 132b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson int pos; 133b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson }; 134b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson typedef map<int64, StorageData*> AddrToBlockMap; 135b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson typedef vector<int64> PosToAddrVector; 136241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders 137241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // Inserts block in structure, used in tests and by other methods. 138241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders void InsertOnStructure(BlockData *block); 139241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders 140241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // Generates a random 64-bit integer. 141241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // Virtual method so it can be overridden by the tests. 142241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders virtual int64 Random64(); 143241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders 144241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // Accessor methods for testing. 145241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders const PosToAddrVector& pos_to_addr() const { return pos_to_addr_; } 146241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders const AddrToBlockMap& addr_to_block() const { return addr_to_block_; } 147241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders 148241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders int sector_size() const { return sector_size_; } 149241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders int write_block_size() const { return write_block_size_; } 150241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders const string& device_name() const { return device_name_; } 151241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders int64 device_sectors() const { return device_sectors_; } 152241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders int64 segment_size() const { return segment_size_; } 153241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders 154241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders private: 155241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // Number of retries to allocate sectors. 156241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders static const int kBlockRetry = 100; 157241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // Actual tables. 158b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson PosToAddrVector pos_to_addr_; 159b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson AddrToBlockMap addr_to_block_; 160241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders 161241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders // Configuration parameters for block selection 162241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders int sector_size_; // Sector size, in bytes 163241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders int write_block_size_; // Block size, in bytes 164241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders string device_name_; // Device name 165241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders int64 device_sectors_; // Number of sectors in device 166241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders int64 segment_size_; // Segment size in bytes 167241f33a3e958842e3db803c03300764bd2ee9c19Nick Sanders uint64 size_; // Number of elements on table 168b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson pthread_mutex_t data_mutex_; 169b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson pthread_cond_t data_condition_; 170b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson pthread_mutex_t parameter_mutex_; 171b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson DISALLOW_COPY_AND_ASSIGN(DiskBlockTable); 172b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson}; 173b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson 174b0114cb9f332db144f65291211ae65f7f0e814e6Scott Anderson#endif // STRESSAPPTEST_BLOCKS_H_ 175