chiark / gitweb /
PORT 22
[stressapptest] / src / disk_blocks.h
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_