Skip to content

Instantly share code, notes, and snippets.

@thoughtpolice
Created May 5, 2010 01:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thoughtpolice/390266 to your computer and use it in GitHub Desktop.
Save thoughtpolice/390266 to your computer and use it in GitHub Desktop.
#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