Перевожу работающий проект на асинхронный доступ к файлам. Пока, так скажем, в режиме "эмуляции блокирующего доступа". Т.к. не имел с этим дела нигде кроме Win. Заработает - буду менять алгоритм. Все данные в файлах обрабатываются блоками по 4К. (изначально использовали RAW доступ к разделам. чтобы исключить системное кеширование, и использовали свое. Здесь используется обычная freebsd-ufs и файлы в ней. ).
в общем имею класс:
Код: Выделить всё
class FileDB {
public:
...
void read( int key ); // блокирующее чтение
void read_aio( int key ); // асинхронное чтение
void getLastKeyData(uint32_t* buffer); // получение данных после блокирующего чтения
void getLastKeyData_aio(uint32_t* buffer); // получение данных после асинхронного чтения
int getLastKeyRecordCount(){ return count; }; // кол-во считанных записей, в процессе последнего чтения.
private:
int fd;
bool volatile asyncOpInProgress;
int sectorSize;
uint64_t currentIdxSector;
uint64_t currentDataSector;
uint32_t* tmpIdx;
uint64_t* dataSectorBuf;
uint64_t lastDataPos;
int rdOffs;
int rdSize;
std::string aFileName;
int count; // кол-во записей, указанных в индексе последнего чтения.
struct aiocb aio;
struct aiocb *cblist[1];
int err_r;
}
Код: Выделить всё
void FileDB::read( int key )
{
.....
if (currentDataSector != sectorNum)
{ // если этот сектор данных еще не читали, читаем
lseek( fd, sectorNum * sectorSize, SEEK_SET );
rdSize_l = (rdSize_l > sectorSize) ? sectorSize * 2 : sectorSize;
::read( fd, dataSectorBuf, rdSize_l );
currentDataSector = sectorNum;
}
}
void FileDB::read_aio( int key )
{
.....
memset(&aio, 0, sizeof( aio ));
if (currentDataSector != sectorNum)
{ // если этот сектор данных еще не читали, читаем
aio.aio_fildes = fd;
aio.aio_offset = sectorSize * sectorNum;
aio.aio_buf = (char*)tmpIdx;
rdSize_l = (rdSize_l > sectorSize) ? sectorSize * 2 : sectorSize;
aio.aio_nbytes = rdSize_l;
aio_read(&aio);
currentDataSector = sectorNum;
asyncOpInProgress = true;// возводим флаг, чтобы функция получения дождалась конца операции.
}
}
// получение данных
void FileDB::getLastKeyData(uint32_t* buffer)
{
memcpy( buffer, ((char*)dataSectorBuf)+rdOffs, rdSize );
// .. тут далее обработка данных. ее мы опускаем
}
void FileDB::getLastKeyData_aio(uint32_t* buffer)
{
if( asyncOpInProgress ) // если было чтение с диска - дожидаемся конца операции.
{
while( (err_r = aio_error(&aio)) == EINPROGRESS )
{
cblist[0] = &aio;
aio_suspend( cblist, 1, NULL );
}
if (err_r == 0)
{
aio_return(&aio);
}
// вариант с тем, что не прочиталось игнорируем пока...в крайнем случае получим ранее прочитанные данные.
// исходный буфер чтения-то не пересоздается...
asyncOpInProgress = false; // сброс флага асинхронной операции
}
memcpy( buffer, ((char*)dataSectorBuf)+rdOffs, rdSize );
// .. тут далее обработка данных. ее мы опускаем
}
Код: Выделить всё
FileDB db = new FileDB(); //
uint32_t* tmpbuf = uint32_t[2048]; // 2k*4 = 2 "сектора"
...
for(...){
....
db->read(currIdx);
db->getLastKeyData(tmpbuf);
recCnt = db->getLastKeyRecordCount();
.....
}
delete db;
delete []tmpbuf;
Код: Выделить всё
FileDB db = new FileDB(); //
uint32_t* tmpbuf = uint32_t[2048]; // 2k*4 = 2 "сектора"
...
for(...){
db->read_aio(currIdx);
db->getLastKeyData_aio(tmpbuf);
recCnt = db->getLastKeyRecordCount();
....
}
delete db;
delete []tmpbuf;
из настроек. в boot/loader.conf включил aio_load="YES". С остальным решил разбираться позже (я все же новичок в UNIX-like системах. и пока не заработает с минимальными изменениями, стараюсь не трогать лишнего.) может еще чего-то нужно в обязательном порядке настраивать, чтоб AIO работал нормально? Или это я его не правильно использую?