experimental io_batch implementation
parent
eb554a0ceb
commit
4c2fb93a53
@ -0,0 +1,15 @@
|
|||||||
|
#include "iob_internal.h"
|
||||||
|
|
||||||
|
int iob_addbuf(io_batch* b,void* buf,uint64 n) {
|
||||||
|
io_entry* e=array_allocate(&b->b,sizeof(io_entry),
|
||||||
|
array_length(&b->b,sizeof(io_entry)));
|
||||||
|
if (!e) return 0;
|
||||||
|
e->type=FROMBUF;
|
||||||
|
e->fd=-1;
|
||||||
|
e->buf=buf;
|
||||||
|
e->n=n;
|
||||||
|
e->offset=0;
|
||||||
|
b->bytesleft+=n;
|
||||||
|
++b->bufs;
|
||||||
|
return 1;
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
#include "iob_internal.h"
|
||||||
|
|
||||||
|
int iob_addfile(io_batch* b,int64 fd,uint64 off,uint64 n) {
|
||||||
|
io_entry* e=array_allocate(&b->b,sizeof(io_entry),
|
||||||
|
array_length(&b->b,sizeof(io_entry)));
|
||||||
|
if (!e) return 0;
|
||||||
|
e->type=FROMFILE;
|
||||||
|
e->fd=fd;
|
||||||
|
e->buf=0;
|
||||||
|
e->n=n;
|
||||||
|
e->offset=off;
|
||||||
|
b->bytesleft+=n;
|
||||||
|
++b->files;
|
||||||
|
return 1;
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include "iob_internal.h"
|
||||||
|
|
||||||
|
io_batch* iob_new(int hint_entries) {
|
||||||
|
io_batch* b=(io_batch*)malloc(sizeof(io_batch));
|
||||||
|
if (!b) return 0;
|
||||||
|
if (hint_entries) {
|
||||||
|
if (!array_allocate(&b->b,sizeof(io_entry),hint_entries)) {
|
||||||
|
free(b);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
array_trunc(&b->b);
|
||||||
|
}
|
||||||
|
b->next=b->bufs=b->files=0;
|
||||||
|
b->bytesleft=0;
|
||||||
|
return b;
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include "iob_internal.h"
|
||||||
|
|
||||||
|
void iob_reset(io_batch* b) {
|
||||||
|
array_reset(&b->b);
|
||||||
|
free(b);
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
|
||||||
|
#define BSD_SENDFILE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <alloca.h>
|
||||||
|
|
||||||
|
#include "iob_internal.h"
|
||||||
|
|
||||||
|
int64 iob_send(int64 s,io_batch* b) {
|
||||||
|
io_entry* e,* last;
|
||||||
|
struct iovec* v;
|
||||||
|
int64 sent;
|
||||||
|
long i;
|
||||||
|
long headers;
|
||||||
|
#ifdef BSD_SENDFILE
|
||||||
|
long trailers;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (b->bytesleft==0) return 0;
|
||||||
|
last=array_start(&b->b)+array_bytes(&b->b);
|
||||||
|
if (!(e=array_get(&b->b,sizeof(io_entry),b->next)))
|
||||||
|
return -1; /* can't happen error */
|
||||||
|
v=alloca(b->bufs*sizeof(struct iovec));
|
||||||
|
#ifdef BSD_SENDFILE
|
||||||
|
/* BSD sendfile can send headers and trailers. If we run on BSD, we
|
||||||
|
* should try to exploit this. */
|
||||||
|
headers=trailers=0;
|
||||||
|
#endif
|
||||||
|
for (i=0; e+i<last; ++i) {
|
||||||
|
if (e[i].type==FROMFILE) break;
|
||||||
|
v[i].iov_base=e[i].buf+e[i].offset;
|
||||||
|
v[i].iov_len=e[i].n-e[i].offset;
|
||||||
|
}
|
||||||
|
headers=i;
|
||||||
|
#ifdef BSD_SENDFILE
|
||||||
|
if (e[i].type==FROMFILE) {
|
||||||
|
off_t sbytes;
|
||||||
|
struct sf_hdtr hdr;
|
||||||
|
int r;
|
||||||
|
for (++i; e+i<last; ++i) {
|
||||||
|
if (e[i].type==FROMFILE) break;
|
||||||
|
v[i-1].iov_base=e[i].buf+e[i].offset;
|
||||||
|
v[i-1].iov_len=e[i].n-e[i].offset;
|
||||||
|
++trailers;
|
||||||
|
}
|
||||||
|
hdr.headers=v; hdr.hdr_cnt=headers;
|
||||||
|
hdr.trailers=v+headers; hdr.trl_cnt=trailers;
|
||||||
|
r=sendfile(e[headers].fd,s,e[headers].off,nbytes,&hdr,&sbytes,0);
|
||||||
|
if (r==0)
|
||||||
|
sent=b->bytesleft;
|
||||||
|
else if (r==-1 && errno==EAGAIN)
|
||||||
|
sent=sbytes;
|
||||||
|
else
|
||||||
|
sent=-1;
|
||||||
|
} else
|
||||||
|
sent=writev(s,v,headers);
|
||||||
|
#else
|
||||||
|
if (headers)
|
||||||
|
sent=writev(s,v,headers);
|
||||||
|
else
|
||||||
|
sent=io_sendfile(s,e->fd,e->offset,e->n);
|
||||||
|
#endif
|
||||||
|
if (sent==b->bytesleft)
|
||||||
|
b->bytesleft=0;
|
||||||
|
else if (sent>0) {
|
||||||
|
int64 rest=sent;
|
||||||
|
b->bytesleft-=rest;
|
||||||
|
for (i=0; e+i<last; ++i) {
|
||||||
|
if (e[i].n-e[i].offset<rest) {
|
||||||
|
rest-=e[i].n-e[i].offset;
|
||||||
|
++b->next;
|
||||||
|
} else {
|
||||||
|
e[i].offset+=rest;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sent;
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef _IOB_H
|
||||||
|
#define _IOB_H
|
||||||
|
|
||||||
|
#include "io.h"
|
||||||
|
|
||||||
|
typedef struct io_batch io_batch;
|
||||||
|
|
||||||
|
io_batch* iob_new(int hint_entries);
|
||||||
|
int iob_addbuf(io_batch* b,void* buf,uint64 n);
|
||||||
|
int iob_addfile(io_batch* b,int64 fd,uint64 off,uint64 n);
|
||||||
|
int64 iob_send(int64 s,io_batch* b);
|
||||||
|
void iob_reset(io_batch* b);
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,15 @@
|
|||||||
|
#include "iob.h"
|
||||||
|
#include "array.h"
|
||||||
|
|
||||||
|
struct io_batch {
|
||||||
|
array b;
|
||||||
|
uint64 bytesleft;
|
||||||
|
long next,bufs,files;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct io_entry {
|
||||||
|
enum { FROMBUF, FROMFILE } type;
|
||||||
|
int64 fd;
|
||||||
|
char* buf;
|
||||||
|
uint64 offset,n;
|
||||||
|
} io_entry;
|
Loading…
Reference in New Issue