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