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()
undaio_error()
keine Probleme melden? - Wie kann ich dieses Verhalten beheben?
- Gibt es Möglichkeiten,
aio_write()
zu puffern? Ich dachte übern_bytes
instruct aiocb
aio_write()
aio_write()
übergebenaio_write()
von innenaio_write_handler()
.
Vielen Dank für Ihre Hilfe!
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? –