2016-12-08 1 views
0

Ich versuche, die Funktionalität von sendfile(2) in einer asynchronen Art und Weise mit aio_read(3) und aio_write(3) imitieren.aio_write auf große Dateien

Alles scheint gut zu funktionieren, mit Ausnahme des Testens von großen (> 150k) Dateien.

Ich habe eine einfache struct io_request ich den Überblick über die Transfers zu halten bin mit:

struct io_request { 
    int status; 
    struct aiocb *aiocbp; 
    int sfd; 
}; 

Zuerst habe ich beim Aufbau der aio_read() Aufruf:

struct io_request * ioreq = malloc(sizeof(struct io_request)); 
ioreq->status = EINPROGRESS; 
ioreq->sfd = sfd; 

struct aiocb * aiocbreq = malloc(sizeof(struct aiocb)); 
memset(aiocbreq, 0, sizeof(struct aiocb)); 

ioreq->aiocbp = aiocbreq; 

ioreq->aiocbp->aio_fildes = ffd; 

if (ioreq->aiocbp->aio_fildes == -1) { 
    perror("aio_fildes"); 
} 

ioreq->aiocbp->aio_buf = malloc(st.st_size); 
if (ioreq->aiocbp->aio_buf == NULL) { 
    perror("aio_buf malloc"); 
} 

ioreq->aiocbp->aio_nbytes = st.st_size; 
ioreq->aiocbp->aio_reqprio = 0; 
ioreq->aiocbp->aio_offset = 0; 
ioreq->aiocbp->aio_sigevent.sigev_signo = IO_READ_SIGNAL; 
ioreq->aiocbp->aio_sigevent.sigev_value.sival_ptr = ioreq; 
if (aio_read(ioreq->aiocbp) == -1) { 
    perror("aio_read"); 
} 

, die später dann in einem IO_READ_SIGNAL Handler erfasst :

static void 
aio_read_handler(int sig, siginfo_t *si, void *ucontext) 
{ 
    if (si->si_code == SI_ASYNCIO) { 
     struct io_request *ioreq = si->si_value.sival_ptr; 

     // Build the AIO write request 
     struct aiocb aiocbreq; 
     memset(&aiocbreq, 0, sizeof(struct aiocb)); 
     aiocbreq.aio_fildes = ioreq->sfd; 
     aiocbreq.aio_buf = ioreq->aiocbp->aio_buf; 
     aiocbreq.aio_nbytes = ioreq->aiocbp->aio_nbytes; 
     aiocbreq.aio_sigevent.sigev_signo = IO_WRITE_SIGNAL; 
     aiocbreq.aio_sigevent.sigev_value.sival_ptr = ioreq; 

     if (aio_write((void *) &aiocbreq) == -1) { 
      perror("aio_write"); 
     } 
    } 
} 

ich ca n Vergewissern Sie sich, dass der Inhalt von ioreq->aiocbp->aio_buf im Handler auch für große Dateien vollständig und vollständig ist.

Später wird die aio_write() in einem IO_WRITE_SIGNAL Handler erfasst:

static void 
aio_write_handler(int sig, siginfo_t *si, void *ucontext) 
{ 
    if (si->si_code == SI_ASYNCIO) { 
     struct io_request *ioreq = si->si_value.sival_ptr; 

     ssize_t bytes_written = aio_return(ioreq->aiocbp); 
     printf("Wrote %zu of %zu bytes\n", bytes_written, ioreq->aiocbp->aio_nbytes); 
     //free(ioreq->aiocbp); 
     //free(ioreq); 

     if (aio_error(ioreq->aiocbp) != 0) { 
      perror("aio_write_handler"); 
     } 
    } 
} 

An dieser Stelle aio_write() abgeschlossen werden sollte. Ich überprüfe die Rückgabewerte und handle entsprechend. Beide Aufrufe melden, dass die entsprechende Anzahl an Bytes geschrieben wurde und während des Schreibens keine Fehler aufgetreten sind.

Die größere Anwendung ist ein HTTP-Server. Ich spekuliere, dass dieses Problem auftritt, weil der Remote-Client nicht schnell genug lesen kann, um mit der aio_write() Schritt zu halten. Als ich eine sendfile() Implementierung von diesem hatte, musste ich sendfile() mehrfach aufrufen, um die Dateiübertragung abzuschließen.

Mehr direkte Fragen:

  • Warum aio_return() und aio_error() keine Probleme melden?
  • Wie kann ich dieses Verhalten beheben?
  • Gibt es Möglichkeiten, aio_write() zu puffern? Ich dachte über n_bytes in struct aiocbaio_write()aio_write() übergeben aio_write() von innen aio_write_handler().

Vielen Dank für Ihre Hilfe!

+0

James, ich habe das schon mehrmals gelesen, und ich bin mir immer noch nicht sicher, was das Problem ist, das Sie erleben. Vielleicht ist es in einer Bearbeitung verloren gegangen? Vielleicht würde es helfen, etwas von der Ausgabe von 'aio_write_handler' miteinzubeziehen? –

Antwort

0

Wenn ich richtig verstehe, verwenden Sie aio_return vor aio_error. Die aio_return Manpage sagt,

Diese Funktion sollte nur einmal für jede gegebene Anforderung aufgerufen werden, nachdem aio_error (3) etwas anderes als EINPROGRESS zurückgibt.