xref: /aosp_15_r20/external/stressapptest/src/disk_blocks.cc (revision 424fb153c814cbcb3e8904974796228774b3229a)
1*424fb153SAndroid Build Coastguard Worker // Copyright 2008 Google Inc. All Rights Reserved.
2*424fb153SAndroid Build Coastguard Worker 
3*424fb153SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*424fb153SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*424fb153SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*424fb153SAndroid Build Coastguard Worker 
7*424fb153SAndroid Build Coastguard Worker //      http://www.apache.org/licenses/LICENSE-2.0
8*424fb153SAndroid Build Coastguard Worker 
9*424fb153SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*424fb153SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*424fb153SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*424fb153SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*424fb153SAndroid Build Coastguard Worker // limitations under the License.
14*424fb153SAndroid Build Coastguard Worker 
15*424fb153SAndroid Build Coastguard Worker // Thread-safe container of disk blocks
16*424fb153SAndroid Build Coastguard Worker 
17*424fb153SAndroid Build Coastguard Worker // This file must work with autoconf on its public version,
18*424fb153SAndroid Build Coastguard Worker // so these includes are correct.
19*424fb153SAndroid Build Coastguard Worker #include "disk_blocks.h"
20*424fb153SAndroid Build Coastguard Worker 
21*424fb153SAndroid Build Coastguard Worker #include <utility>
22*424fb153SAndroid Build Coastguard Worker 
23*424fb153SAndroid Build Coastguard Worker // BlockData
BlockData()24*424fb153SAndroid Build Coastguard Worker BlockData::BlockData() : address_(0), size_(0),
25*424fb153SAndroid Build Coastguard Worker                          references_(0), initialized_(false),
26*424fb153SAndroid Build Coastguard Worker                          pattern_(NULL) {
27*424fb153SAndroid Build Coastguard Worker   pthread_mutex_init(&data_mutex_, NULL);
28*424fb153SAndroid Build Coastguard Worker }
29*424fb153SAndroid Build Coastguard Worker 
~BlockData()30*424fb153SAndroid Build Coastguard Worker BlockData::~BlockData() {
31*424fb153SAndroid Build Coastguard Worker   pthread_mutex_destroy(&data_mutex_);
32*424fb153SAndroid Build Coastguard Worker }
33*424fb153SAndroid Build Coastguard Worker 
set_initialized()34*424fb153SAndroid Build Coastguard Worker void BlockData::set_initialized() {
35*424fb153SAndroid Build Coastguard Worker   pthread_mutex_lock(&data_mutex_);
36*424fb153SAndroid Build Coastguard Worker   initialized_ = true;
37*424fb153SAndroid Build Coastguard Worker   pthread_mutex_unlock(&data_mutex_);
38*424fb153SAndroid Build Coastguard Worker }
39*424fb153SAndroid Build Coastguard Worker 
initialized() const40*424fb153SAndroid Build Coastguard Worker bool BlockData::initialized() const {
41*424fb153SAndroid Build Coastguard Worker   pthread_mutex_lock(&data_mutex_);
42*424fb153SAndroid Build Coastguard Worker   bool initialized = initialized_;
43*424fb153SAndroid Build Coastguard Worker   pthread_mutex_unlock(&data_mutex_);
44*424fb153SAndroid Build Coastguard Worker   return initialized;
45*424fb153SAndroid Build Coastguard Worker }
46*424fb153SAndroid Build Coastguard Worker 
47*424fb153SAndroid Build Coastguard Worker // DiskBlockTable
DiskBlockTable()48*424fb153SAndroid Build Coastguard Worker DiskBlockTable::DiskBlockTable() : sector_size_(0), write_block_size_(0),
49*424fb153SAndroid Build Coastguard Worker                                    device_name_(""), device_sectors_(0),
50*424fb153SAndroid Build Coastguard Worker                                    segment_size_(0), size_(0) {
51*424fb153SAndroid Build Coastguard Worker   pthread_mutex_init(&data_mutex_, NULL);
52*424fb153SAndroid Build Coastguard Worker   pthread_mutex_init(&parameter_mutex_, NULL);
53*424fb153SAndroid Build Coastguard Worker   pthread_cond_init(&data_condition_, NULL);
54*424fb153SAndroid Build Coastguard Worker }
55*424fb153SAndroid Build Coastguard Worker 
~DiskBlockTable()56*424fb153SAndroid Build Coastguard Worker DiskBlockTable::~DiskBlockTable() {
57*424fb153SAndroid Build Coastguard Worker   pthread_mutex_destroy(&data_mutex_);
58*424fb153SAndroid Build Coastguard Worker   pthread_mutex_destroy(&parameter_mutex_);
59*424fb153SAndroid Build Coastguard Worker   pthread_cond_destroy(&data_condition_);
60*424fb153SAndroid Build Coastguard Worker }
61*424fb153SAndroid Build Coastguard Worker 
62*424fb153SAndroid Build Coastguard Worker // 64-bit non-negative random number generator.  Stolen from
63*424fb153SAndroid Build Coastguard Worker // depot/google3/base/tracecontext_unittest.cc.
Random64()64*424fb153SAndroid Build Coastguard Worker int64 DiskBlockTable::Random64() {
65*424fb153SAndroid Build Coastguard Worker   int64 x = random();
66*424fb153SAndroid Build Coastguard Worker   x = (x << 30) ^ random();
67*424fb153SAndroid Build Coastguard Worker   x = (x << 30) ^ random();
68*424fb153SAndroid Build Coastguard Worker   if (x >= 0)
69*424fb153SAndroid Build Coastguard Worker     return x;
70*424fb153SAndroid Build Coastguard Worker   else
71*424fb153SAndroid Build Coastguard Worker     return -x;
72*424fb153SAndroid Build Coastguard Worker }
73*424fb153SAndroid Build Coastguard Worker 
Size()74*424fb153SAndroid Build Coastguard Worker uint64 DiskBlockTable::Size() {
75*424fb153SAndroid Build Coastguard Worker   pthread_mutex_lock(&data_mutex_);
76*424fb153SAndroid Build Coastguard Worker   uint64 size = size_;
77*424fb153SAndroid Build Coastguard Worker   pthread_mutex_unlock(&data_mutex_);
78*424fb153SAndroid Build Coastguard Worker   return size;
79*424fb153SAndroid Build Coastguard Worker }
80*424fb153SAndroid Build Coastguard Worker 
InsertOnStructure(BlockData * block)81*424fb153SAndroid Build Coastguard Worker void DiskBlockTable::InsertOnStructure(BlockData *block) {
82*424fb153SAndroid Build Coastguard Worker   int64 address = block->address();
83*424fb153SAndroid Build Coastguard Worker   StorageData *sd = new StorageData();
84*424fb153SAndroid Build Coastguard Worker   sd->block = block;
85*424fb153SAndroid Build Coastguard Worker   sd->pos = size_;
86*424fb153SAndroid Build Coastguard Worker   // Creating new block ...
87*424fb153SAndroid Build Coastguard Worker   pthread_mutex_lock(&data_mutex_);
88*424fb153SAndroid Build Coastguard Worker   if (pos_to_addr_.size() <= size_) {
89*424fb153SAndroid Build Coastguard Worker     pos_to_addr_.insert(pos_to_addr_.end(), address);
90*424fb153SAndroid Build Coastguard Worker   } else {
91*424fb153SAndroid Build Coastguard Worker     pos_to_addr_[size_] = address;
92*424fb153SAndroid Build Coastguard Worker   }
93*424fb153SAndroid Build Coastguard Worker   addr_to_block_[address] = sd;
94*424fb153SAndroid Build Coastguard Worker   size_++;
95*424fb153SAndroid Build Coastguard Worker   pthread_cond_broadcast(&data_condition_);
96*424fb153SAndroid Build Coastguard Worker   pthread_mutex_unlock(&data_mutex_);
97*424fb153SAndroid Build Coastguard Worker }
98*424fb153SAndroid Build Coastguard Worker 
RemoveBlock(BlockData * block)99*424fb153SAndroid Build Coastguard Worker int DiskBlockTable::RemoveBlock(BlockData *block) {
100*424fb153SAndroid Build Coastguard Worker   // For write threads, check the reference counter and remove
101*424fb153SAndroid Build Coastguard Worker   // it from the structure.
102*424fb153SAndroid Build Coastguard Worker   int64 address = block->address();
103*424fb153SAndroid Build Coastguard Worker   AddrToBlockMap::iterator it = addr_to_block_.find(address);
104*424fb153SAndroid Build Coastguard Worker   int ret = 1;
105*424fb153SAndroid Build Coastguard Worker   if (it != addr_to_block_.end()) {
106*424fb153SAndroid Build Coastguard Worker     int curr_pos = it->second->pos;
107*424fb153SAndroid Build Coastguard Worker     int last_pos = size_ - 1;
108*424fb153SAndroid Build Coastguard Worker     AddrToBlockMap::iterator last_it = addr_to_block_.find(
109*424fb153SAndroid Build Coastguard Worker         pos_to_addr_[last_pos]);
110*424fb153SAndroid Build Coastguard Worker     sat_assert(size_ > 0);
111*424fb153SAndroid Build Coastguard Worker     sat_assert(last_it != addr_to_block_.end());
112*424fb153SAndroid Build Coastguard Worker     // Everything is fine, removing block from table.
113*424fb153SAndroid Build Coastguard Worker     pthread_mutex_lock(&data_mutex_);
114*424fb153SAndroid Build Coastguard Worker     pos_to_addr_[curr_pos] = pos_to_addr_[last_pos];
115*424fb153SAndroid Build Coastguard Worker     last_it->second->pos = curr_pos;
116*424fb153SAndroid Build Coastguard Worker     delete it->second;
117*424fb153SAndroid Build Coastguard Worker     addr_to_block_.erase(it);
118*424fb153SAndroid Build Coastguard Worker     size_--;
119*424fb153SAndroid Build Coastguard Worker     block->DecreaseReferenceCounter();
120*424fb153SAndroid Build Coastguard Worker     if (block->GetReferenceCounter() == 0)
121*424fb153SAndroid Build Coastguard Worker       delete block;
122*424fb153SAndroid Build Coastguard Worker     else if (block->GetReferenceCounter() < 0)
123*424fb153SAndroid Build Coastguard Worker       ret = 0;
124*424fb153SAndroid Build Coastguard Worker     pthread_cond_broadcast(&data_condition_);
125*424fb153SAndroid Build Coastguard Worker     pthread_mutex_unlock(&data_mutex_);
126*424fb153SAndroid Build Coastguard Worker   } else {
127*424fb153SAndroid Build Coastguard Worker     ret = 0;
128*424fb153SAndroid Build Coastguard Worker   }
129*424fb153SAndroid Build Coastguard Worker   return ret;
130*424fb153SAndroid Build Coastguard Worker }
131*424fb153SAndroid Build Coastguard Worker 
ReleaseBlock(BlockData * block)132*424fb153SAndroid Build Coastguard Worker int DiskBlockTable::ReleaseBlock(BlockData *block) {
133*424fb153SAndroid Build Coastguard Worker   // If caller is a random thread, just check the reference counter.
134*424fb153SAndroid Build Coastguard Worker   int ret = 1;
135*424fb153SAndroid Build Coastguard Worker   pthread_mutex_lock(&data_mutex_);
136*424fb153SAndroid Build Coastguard Worker   int references = block->GetReferenceCounter();
137*424fb153SAndroid Build Coastguard Worker   if (references == 1)
138*424fb153SAndroid Build Coastguard Worker     delete block;
139*424fb153SAndroid Build Coastguard Worker   else if (references > 0)
140*424fb153SAndroid Build Coastguard Worker     block->DecreaseReferenceCounter();
141*424fb153SAndroid Build Coastguard Worker   else
142*424fb153SAndroid Build Coastguard Worker     ret = 0;
143*424fb153SAndroid Build Coastguard Worker   pthread_mutex_unlock(&data_mutex_);
144*424fb153SAndroid Build Coastguard Worker   return ret;
145*424fb153SAndroid Build Coastguard Worker }
146*424fb153SAndroid Build Coastguard Worker 
GetRandomBlock()147*424fb153SAndroid Build Coastguard Worker BlockData *DiskBlockTable::GetRandomBlock() {
148*424fb153SAndroid Build Coastguard Worker   struct timespec ts;
149*424fb153SAndroid Build Coastguard Worker   struct timeval tp;
150*424fb153SAndroid Build Coastguard Worker   gettimeofday(&tp, NULL);
151*424fb153SAndroid Build Coastguard Worker   ts.tv_sec  = tp.tv_sec;
152*424fb153SAndroid Build Coastguard Worker   ts.tv_nsec = tp.tv_usec * 1000;
153*424fb153SAndroid Build Coastguard Worker   ts.tv_sec += 2;  // Wait for 2 seconds.
154*424fb153SAndroid Build Coastguard Worker   int result = 0;
155*424fb153SAndroid Build Coastguard Worker   pthread_mutex_lock(&data_mutex_);
156*424fb153SAndroid Build Coastguard Worker   while (!size_ && result != ETIMEDOUT) {
157*424fb153SAndroid Build Coastguard Worker     result = pthread_cond_timedwait(&data_condition_, &data_mutex_, &ts);
158*424fb153SAndroid Build Coastguard Worker   }
159*424fb153SAndroid Build Coastguard Worker   if (result == ETIMEDOUT) {
160*424fb153SAndroid Build Coastguard Worker     pthread_mutex_unlock(&data_mutex_);
161*424fb153SAndroid Build Coastguard Worker     return NULL;
162*424fb153SAndroid Build Coastguard Worker   } else {
163*424fb153SAndroid Build Coastguard Worker     int64 random_number = Random64();
164*424fb153SAndroid Build Coastguard Worker     int64 random_pos = random_number % size_;
165*424fb153SAndroid Build Coastguard Worker     int64 address = pos_to_addr_[random_pos];
166*424fb153SAndroid Build Coastguard Worker     AddrToBlockMap::const_iterator it = addr_to_block_.find(address);
167*424fb153SAndroid Build Coastguard Worker     sat_assert(it != addr_to_block_.end());
168*424fb153SAndroid Build Coastguard Worker     BlockData *b = it->second->block;
169*424fb153SAndroid Build Coastguard Worker     // A block is returned only if its content is written on disk.
170*424fb153SAndroid Build Coastguard Worker     if (b->initialized()) {
171*424fb153SAndroid Build Coastguard Worker       b->IncreaseReferenceCounter();
172*424fb153SAndroid Build Coastguard Worker     } else {
173*424fb153SAndroid Build Coastguard Worker       b = NULL;
174*424fb153SAndroid Build Coastguard Worker     }
175*424fb153SAndroid Build Coastguard Worker     pthread_mutex_unlock(&data_mutex_);
176*424fb153SAndroid Build Coastguard Worker     return b;
177*424fb153SAndroid Build Coastguard Worker   }
178*424fb153SAndroid Build Coastguard Worker }
179*424fb153SAndroid Build Coastguard Worker 
SetParameters(int sector_size,int write_block_size,int64 device_sectors,int64 segment_size,const string & device_name)180*424fb153SAndroid Build Coastguard Worker void DiskBlockTable::SetParameters(int sector_size,
181*424fb153SAndroid Build Coastguard Worker                                    int write_block_size,
182*424fb153SAndroid Build Coastguard Worker                                    int64 device_sectors,
183*424fb153SAndroid Build Coastguard Worker                                    int64 segment_size,
184*424fb153SAndroid Build Coastguard Worker                                    const string& device_name) {
185*424fb153SAndroid Build Coastguard Worker   sat_assert(size_ == 0);
186*424fb153SAndroid Build Coastguard Worker   pthread_mutex_lock(&parameter_mutex_);
187*424fb153SAndroid Build Coastguard Worker   sector_size_ = sector_size;
188*424fb153SAndroid Build Coastguard Worker   write_block_size_ = write_block_size;
189*424fb153SAndroid Build Coastguard Worker   device_sectors_ = device_sectors;
190*424fb153SAndroid Build Coastguard Worker   segment_size_ = segment_size;
191*424fb153SAndroid Build Coastguard Worker   device_name_ = device_name;
192*424fb153SAndroid Build Coastguard Worker   pthread_mutex_unlock(&parameter_mutex_);
193*424fb153SAndroid Build Coastguard Worker }
194*424fb153SAndroid Build Coastguard Worker 
GetUnusedBlock(int64 segment)195*424fb153SAndroid Build Coastguard Worker BlockData *DiskBlockTable::GetUnusedBlock(int64 segment) {
196*424fb153SAndroid Build Coastguard Worker   int64 sector = 0;
197*424fb153SAndroid Build Coastguard Worker   BlockData *block = new BlockData();
198*424fb153SAndroid Build Coastguard Worker   bool good_sequence = false;
199*424fb153SAndroid Build Coastguard Worker   if (block == NULL) {
200*424fb153SAndroid Build Coastguard Worker     logprintf(0, "Process Error: Unable to allocate memory "
201*424fb153SAndroid Build Coastguard Worker               "for sector data for disk %s.\n", device_name_.c_str());
202*424fb153SAndroid Build Coastguard Worker     return NULL;
203*424fb153SAndroid Build Coastguard Worker   }
204*424fb153SAndroid Build Coastguard Worker   pthread_mutex_lock(&parameter_mutex_);
205*424fb153SAndroid Build Coastguard Worker   sat_assert(device_sectors_ != 0);
206*424fb153SAndroid Build Coastguard Worker   // Align the first sector with the beginning of a write block
207*424fb153SAndroid Build Coastguard Worker   int num_sectors = write_block_size_ / sector_size_;
208*424fb153SAndroid Build Coastguard Worker   for (int i = 0; i < kBlockRetry && !good_sequence; i++) {
209*424fb153SAndroid Build Coastguard Worker     good_sequence = true;
210*424fb153SAndroid Build Coastguard Worker     // Use the entire disk or a small segment of the disk to allocate the first
211*424fb153SAndroid Build Coastguard Worker     // sector in the block from.
212*424fb153SAndroid Build Coastguard Worker     if (segment_size_ == -1) {
213*424fb153SAndroid Build Coastguard Worker       sector = (Random64() & 0x7FFFFFFFFFFFFFFFLL) % (
214*424fb153SAndroid Build Coastguard Worker           device_sectors_ / num_sectors);
215*424fb153SAndroid Build Coastguard Worker       sector *= num_sectors;
216*424fb153SAndroid Build Coastguard Worker     } else {
217*424fb153SAndroid Build Coastguard Worker       sector = (Random64() & 0x7FFFFFFFFFFFFFFFLL) % (
218*424fb153SAndroid Build Coastguard Worker           segment_size_ / num_sectors);
219*424fb153SAndroid Build Coastguard Worker       sector *= num_sectors;
220*424fb153SAndroid Build Coastguard Worker       sector += segment * segment_size_;
221*424fb153SAndroid Build Coastguard Worker       // Make sure the block is within the segment.
222*424fb153SAndroid Build Coastguard Worker       if (sector + num_sectors > (segment + 1) * segment_size_) {
223*424fb153SAndroid Build Coastguard Worker         good_sequence = false;
224*424fb153SAndroid Build Coastguard Worker         continue;
225*424fb153SAndroid Build Coastguard Worker       }
226*424fb153SAndroid Build Coastguard Worker     }
227*424fb153SAndroid Build Coastguard Worker     // Make sure the entire block is in range.
228*424fb153SAndroid Build Coastguard Worker     if (sector + num_sectors > device_sectors_) {
229*424fb153SAndroid Build Coastguard Worker       good_sequence = false;
230*424fb153SAndroid Build Coastguard Worker       continue;
231*424fb153SAndroid Build Coastguard Worker     }
232*424fb153SAndroid Build Coastguard Worker     // Check to see if the block is free. Since the blocks are
233*424fb153SAndroid Build Coastguard Worker     // now aligned to the write_block_size, it is not necessary
234*424fb153SAndroid Build Coastguard Worker     // to check each sector, just the first block (a sector
235*424fb153SAndroid Build Coastguard Worker     // overlap will never occur).
236*424fb153SAndroid Build Coastguard Worker     pthread_mutex_lock(&data_mutex_);
237*424fb153SAndroid Build Coastguard Worker     if (addr_to_block_.find(sector) != addr_to_block_.end()) {
238*424fb153SAndroid Build Coastguard Worker       good_sequence = false;
239*424fb153SAndroid Build Coastguard Worker     }
240*424fb153SAndroid Build Coastguard Worker     pthread_mutex_unlock(&data_mutex_);
241*424fb153SAndroid Build Coastguard Worker   }
242*424fb153SAndroid Build Coastguard Worker 
243*424fb153SAndroid Build Coastguard Worker   if (good_sequence) {
244*424fb153SAndroid Build Coastguard Worker     block->set_address(sector);
245*424fb153SAndroid Build Coastguard Worker     block->set_size(write_block_size_);
246*424fb153SAndroid Build Coastguard Worker     block->IncreaseReferenceCounter();
247*424fb153SAndroid Build Coastguard Worker     InsertOnStructure(block);
248*424fb153SAndroid Build Coastguard Worker   } else {
249*424fb153SAndroid Build Coastguard Worker     // No contiguous sequence of num_sectors sectors was found within
250*424fb153SAndroid Build Coastguard Worker     // kBlockRetry iterations so return an error value.
251*424fb153SAndroid Build Coastguard Worker     delete block;
252*424fb153SAndroid Build Coastguard Worker     block = NULL;
253*424fb153SAndroid Build Coastguard Worker   }
254*424fb153SAndroid Build Coastguard Worker   pthread_mutex_unlock(&parameter_mutex_);
255*424fb153SAndroid Build Coastguard Worker   return block;
256*424fb153SAndroid Build Coastguard Worker }
257