// Copyright 2008 Google Inc. All Rights Reserved.
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
// Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
// limitations under the License.
|
|
// Interface for a thread-safe container of disk blocks
|
|
#ifndef STRESSAPPTEST_DISK_BLOCKS_H_
|
#define STRESSAPPTEST_DISK_BLOCKS_H_
|
|
#include <sys/types.h>
|
#include <pthread.h>
|
#include <time.h>
|
#include <sys/time.h>
|
#include <errno.h>
|
#include <map>
|
#include <vector>
|
#include <string>
|
|
#include "sattypes.h"
|
|
class Pattern;
|
|
// Data about a block written to disk so that it can be verified later.
|
// Thread-unsafe, must be used with locks on non-const methods,
|
// except for initialized accessor/mutator, which are thread-safe
|
// (and in fact, is the only method supposed to be accessed from
|
// someone which is not the thread-safe DiskBlockTable).
|
class BlockData {
|
public:
|
BlockData();
|
~BlockData();
|
|
// These are reference counters used to control how many
|
// threads currently have a copy of this particular block.
|
void IncreaseReferenceCounter() { references_++; }
|
void DecreaseReferenceCounter() { references_--; }
|
int GetReferenceCounter() const { return references_; }
|
|
// Controls whether the block was written on disk or not.
|
// Once written, you cannot "un-written" then without destroying
|
// this object.
|
void set_initialized();
|
bool initialized() const;
|
|
// Accessor methods for some data related to blocks.
|
void set_address(uint64 address) { address_ = address; }
|
uint64 address() const { return address_; }
|
void set_size(uint64 size) { size_ = size; }
|
uint64 size() const { return size_; }
|
void set_pattern(Pattern *p) { pattern_ = p; }
|
Pattern *pattern() { return pattern_; }
|
private:
|
uint64 address_; // Address of first sector in block
|
uint64 size_; // Size of block
|
int references_; // Reference counter
|
bool initialized_; // Flag indicating the block was written on disk
|
Pattern *pattern_;
|
mutable pthread_mutex_t data_mutex_;
|
DISALLOW_COPY_AND_ASSIGN(BlockData);
|
};
|
|
// A thread-safe table used to store block data and control access
|
// to these blocks, letting several threads read and write blocks on
|
// disk.
|
class DiskBlockTable {
|
public:
|
DiskBlockTable();
|
virtual ~DiskBlockTable();
|
|
// Returns number of elements stored on table.
|
uint64 Size();
|
|
// Sets all initial parameters. Assumes all existent data is
|
// invalid and, therefore, must be removed.
|
void SetParameters(int sector_size, int write_block_size,
|
int64 device_sectors,
|
int64 segment_size,
|
const string& device_name);
|
|
// During the regular execution, there will be 2 types of threads:
|
// - Write thread: gets a large number of blocks using GetUnusedBlock,
|
// writes them on disk (if on destructive mode),
|
// reads block content ONCE from disk and them removes
|
// the block from queue with RemoveBlock. After a removal a
|
// block is not available for read threads, but it is
|
// only removed from memory if there is no reference for
|
// this block. Note that a write thread also counts as
|
// a reference.
|
// - Read threads: get one block at a time (if available) with
|
// GetRandomBlock, reads its content from disk,
|
// checking whether it is correct or not, and releases
|
// (Using ReleaseBlock) the block to be erased by the
|
// write threads. Since several read threads are allowed
|
// to read the same block, a reference counter is used to
|
// control when the block can be REALLY erased from
|
// memory, and all memory management is made by a
|
// DiskBlockTable instance.
|
|
// Returns a new block in a unused address. Does not
|
// grant ownership of the pointer to the caller
|
// (use RemoveBlock to delete the block from memory instead).
|
BlockData *GetUnusedBlock(int64 segment);
|
|
// Removes block from structure (called by write threads). Returns
|
// 1 if successful, 0 otherwise.
|
int RemoveBlock(BlockData *block);
|
|
// Gets a random block from the list. Only returns if an element
|
// is available (a write thread has got this block, written it on disk,
|
// and set this block as initialized). Does not grant ownership of the
|
// pointer to the caller (use RemoveBlock to delete the block from
|
// memory instead).
|
BlockData *GetRandomBlock();
|
|
// Releases block to be erased (called by random threads). Returns
|
// 1 if successful, 0 otherwise.
|
int ReleaseBlock(BlockData *block);
|
|
protected:
|
struct StorageData {
|
BlockData *block;
|
int pos;
|
};
|
typedef map<int64, StorageData*> AddrToBlockMap;
|
typedef vector<int64> PosToAddrVector;
|
|
// Inserts block in structure, used in tests and by other methods.
|
void InsertOnStructure(BlockData *block);
|
|
// Generates a random 64-bit integer.
|
// Virtual method so it can be overridden by the tests.
|
virtual int64 Random64();
|
|
// Accessor methods for testing.
|
const PosToAddrVector& pos_to_addr() const { return pos_to_addr_; }
|
const AddrToBlockMap& addr_to_block() const { return addr_to_block_; }
|
|
int sector_size() const { return sector_size_; }
|
int write_block_size() const { return write_block_size_; }
|
const string& device_name() const { return device_name_; }
|
int64 device_sectors() const { return device_sectors_; }
|
int64 segment_size() const { return segment_size_; }
|
|
private:
|
// Number of retries to allocate sectors.
|
static const int kBlockRetry = 100;
|
// Actual tables.
|
PosToAddrVector pos_to_addr_;
|
AddrToBlockMap addr_to_block_;
|
|
// Configuration parameters for block selection
|
int sector_size_; // Sector size, in bytes
|
int write_block_size_; // Block size, in bytes
|
string device_name_; // Device name
|
int64 device_sectors_; // Number of sectors in device
|
int64 segment_size_; // Segment size in bytes
|
uint64 size_; // Number of elements on table
|
pthread_mutex_t data_mutex_;
|
pthread_cond_t data_condition_;
|
pthread_mutex_t parameter_mutex_;
|
DISALLOW_COPY_AND_ASSIGN(DiskBlockTable);
|
};
|
|
#endif // STRESSAPPTEST_BLOCKS_H_
|