Created
May 5, 2010 01:44
-
-
Save thoughtpolice/390266 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <assert.h> | |
#include <sys/vfs.h> | |
#include <boost/asio.hpp> | |
#include <boost/asio/posix/random_access_descriptor.hpp> | |
#include <boost/iostreams/device/file_descriptor.hpp> | |
#include <boost/system/error_code.hpp> | |
#include <boost/bind.hpp> | |
#define READ_CHUNK_SIZE 16 | |
#define EXT3_SUPER_MAGIC 0xEF53 | |
using namespace std; | |
using namespace boost; | |
typedef asio::posix::random_access_descriptor handle_type; | |
typedef iostreams::file_descriptor fd_type; | |
// asynchronous block reader | |
class block_reader | |
{ | |
public: | |
block_reader(asio::io_service& io, string device_path, string mountpoint) | |
: device_path_(device_path) | |
, fd_(device_path, ios_base::in) | |
, hdl_(io, fd_.handle()) | |
{ | |
struct statfs fs_stat; | |
int ret = ::statfs(mountpoint.c_str(), &fs_stat); | |
if(ret != 0) | |
throw system::system_error(errno, system::system_category); | |
//assert(fs_stat.f_type == EXT3_SUPER_MAGIC); | |
blk_size_ = fs_stat.f_bsize; | |
blk_count_ = fs_stat.f_blocks; | |
chunk_size_ = READ_CHUNK_SIZE * blk_size_; | |
blk_chunk_ = (char*)::calloc(READ_CHUNK_SIZE, blk_size_); | |
read_offset_ = 0; | |
finished_ = false; | |
cout << "device " << device_path_ << ":\n\t"; | |
cout << "blk size: " << blk_size_ << ", blk count: " << blk_count_ << "\n\t"; | |
cout << "chunk size: " << chunk_size_ << endl; | |
} | |
~block_reader() | |
{ | |
fd_.close(); | |
//hdl_.close(); | |
::free(blk_chunk_); | |
} | |
bool finished() | |
{ | |
return finished_; | |
} | |
void issue_reads(long num_of_reads) | |
{ | |
// TODO: READ_CHUNK_SIZE trick here in checking offset is a nasty hack | |
if((read_offset_ <= (blk_count_ - READ_CHUNK_SIZE)) && !finished_) { | |
for(long i=0; i < num_of_reads; ++i) { | |
cout << "Issuing async read #" << i << " for blocks in range " | |
<< read_offset_ << " to " << (read_offset_ + READ_CHUNK_SIZE -1) << endl; | |
asio::async_read_at(hdl_, | |
read_offset_*chunk_size_, | |
asio::buffer(blk_chunk_, chunk_size_), | |
bind(&block_reader::read_finished, | |
this, | |
read_offset_, | |
asio::placeholders::error, | |
asio::placeholders::bytes_transferred)); | |
read_offset_ += READ_CHUNK_SIZE; | |
} | |
} else { | |
cout << "Done issuing reads for block device" << endl; | |
finished_ = true; | |
} | |
} | |
// callback for finishing a read | |
void read_finished(long block_range_start, const system::error_code& e, size_t dataread) | |
{ | |
int block_range_end = block_range_start + READ_CHUNK_SIZE - 1; | |
if(e != system::errc::success) { | |
cerr << "Error doing async read in range " | |
<< block_range_start << " to " << block_range_end | |
<< ", message: " << e.message() << endl; | |
} else { | |
/* | |
cout << "Read " << dataread << " bytes in range " | |
<< block_range_start << " to " << block_range_end << endl; | |
*/ | |
} | |
} | |
private: | |
string device_path_; // path to the device we're opening | |
fd_type fd_; // fd wrapped in an iostream | |
handle_type hdl_; // descriptor we're using for async reads | |
long blk_size_; // size of a single block on the device | |
long blk_count_; // total # of blocks | |
long chunk_size_; // chunk size of how much to read at once | |
char *blk_chunk_; // chunk of data we currently have | |
long read_offset_; // how far into the device we are, IN *BLOCKS* | |
bool finished_; // are we done reading? | |
}; | |
int main() | |
{ | |
asio::io_service io; | |
block_reader blk_reader(io, "/dev/sda1", "/"); | |
int num_iterations = 3; | |
do { | |
/* NOTE BIG TIME PROBLEM: if this is 8 we get errors | |
if we replace the following line with: | |
blk_reader.issue_reads(4); | |
then it succeeds | |
*/ | |
blk_reader.issue_reads(8); | |
io.run(); // gogogogo | |
io.reset(); | |
} while(!blk_reader.finished() && (--num_iterations != 0)); | |
return 0; | |
} | |
/* RESULTS: | |
$ sudo ./asio_blkreader | |
device /dev/sda1: | |
blk size: 4096, blk count: 36988327 | |
chunk size: 65536 | |
Issuing async read #0 for blocks in range 0 to 15 | |
Issuing async read #1 for blocks in range 16 to 31 | |
Issuing async read #2 for blocks in range 32 to 47 | |
Issuing async read #3 for blocks in range 48 to 63 | |
Issuing async read #4 for blocks in range 64 to 79 | |
Issuing async read #5 for blocks in range 80 to 95 | |
Issuing async read #6 for blocks in range 96 to 111 | |
Issuing async read #7 for blocks in range 112 to 127 | |
Issuing async read #0 for blocks in range 128 to 143 | |
Issuing async read #1 for blocks in range 144 to 159 | |
Issuing async read #2 for blocks in range 160 to 175 | |
Issuing async read #3 for blocks in range 176 to 191 | |
Issuing async read #4 for blocks in range 192 to 207 | |
Issuing async read #5 for blocks in range 208 to 223 | |
Issuing async read #6 for blocks in range 224 to 239 | |
Issuing async read #7 for blocks in range 240 to 255 | |
Error doing async read in range 144 to 159, message: Invalid argument | |
Error doing async read in range 160 to 175, message: Invalid argument | |
Error doing async read in range 176 to 191, message: Invalid argument | |
Error doing async read in range 192 to 207, message: Invalid argument | |
Error doing async read in range 208 to 223, message: Invalid argument | |
Error doing async read in range 224 to 239, message: Invalid argument | |
Error doing async read in range 240 to 255, message: Invalid argument | |
Issuing async read #0 for blocks in range 256 to 271 | |
Issuing async read #1 for blocks in range 272 to 287 | |
Issuing async read #2 for blocks in range 288 to 303 | |
Issuing async read #3 for blocks in range 304 to 319 | |
Issuing async read #4 for blocks in range 320 to 335 | |
Issuing async read #5 for blocks in range 336 to 351 | |
Issuing async read #6 for blocks in range 352 to 367 | |
Issuing async read #7 for blocks in range 368 to 383 | |
Error doing async read in range 272 to 287, message: Invalid argument | |
Error doing async read in range 288 to 303, message: Invalid argument | |
Error doing async read in range 304 to 319, message: Invalid argument | |
Error doing async read in range 320 to 335, message: Invalid argument | |
Error doing async read in range 336 to 351, message: Invalid argument | |
Error doing async read in range 352 to 367, message: Invalid argument | |
Error doing async read in range 368 to 383, message: Invalid argument | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment