Краш системы при read_aio

Модератор: Fastman

Правила форума
Убедительная просьба юзать теги [code] при оформлении листингов.
Сообщения не оформленные должным образом имеют все шансы быть незамеченными.
EugenOS
проходил мимо
Сообщения: 4
Зарегистрирован: 2015-10-30 16:44:14

Краш системы при read_aio

Непрочитанное сообщение EugenOS » 2015-10-30 17:22:25

Система вылетает с крашем, где-то на 10-15-м чтении aio_read().

Перевожу работающий проект на асинхронный доступ к файлам. Пока, так скажем, в режиме "эмуляции блокирующего доступа". Т.к. не имел с этим дела нигде кроме 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;       

а если вот такой, то через 10-15 чтений система перегружается с крашем.

Код: Выделить всё

          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 работал нормально? Или это я его не правильно использую?

EugenOS
проходил мимо
Сообщения: 4
Зарегистрирован: 2015-10-30 16:44:14

Краш системы при read_aio

Непрочитанное сообщение EugenOS » 2015-11-04 9:14:04

Решено

Neus
капитан
Сообщения: 1718
Зарегистрирован: 2008-09-08 21:59:56

Краш системы при read_aio

Непрочитанное сообщение Neus » 2015-11-04 18:40:24

Как?

EugenOS
проходил мимо
Сообщения: 4
Зарегистрирован: 2015-10-30 16:44:14

Краш системы при read_aio

Непрочитанное сообщение EugenOS » 2015-11-07 9:31:07

как обычно. устранение последствий копипаста.


Вернуться в «C/C++»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость