mirror of
https://github.com/cuberite/libevent.git
synced 2025-09-14 14:54:49 -04:00
Make evbuffer_file_segment_types adaptable
Instead of having a file segment born as one type and stay that way forever, let them start out unmapped, but map themselves as needed if they need to get written out on a non-drains_to_fd evbuffer.
This commit is contained in:
parent
8358877768
commit
c6bbbf1b67
87
buffer.c
87
buffer.c
@ -149,6 +149,8 @@ static struct evbuffer_chain *evbuffer_expand_singlechain(struct evbuffer *buf,
|
|||||||
size_t datlen);
|
size_t datlen);
|
||||||
static int evbuffer_ptr_subtract(struct evbuffer *buf, struct evbuffer_ptr *pos,
|
static int evbuffer_ptr_subtract(struct evbuffer *buf, struct evbuffer_ptr *pos,
|
||||||
size_t howfar);
|
size_t howfar);
|
||||||
|
static int evbuffer_file_segment_materialize(struct evbuffer_file_segment *seg);
|
||||||
|
|
||||||
|
|
||||||
static struct evbuffer_chain *
|
static struct evbuffer_chain *
|
||||||
evbuffer_chain_new(size_t size)
|
evbuffer_chain_new(size_t size)
|
||||||
@ -204,7 +206,7 @@ evbuffer_chain_free(struct evbuffer_chain *chain)
|
|||||||
chain);
|
chain);
|
||||||
if (info->segment) {
|
if (info->segment) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (info->segment->type == EVBUF_FS_MMAP)
|
if (info->segment->is_mapping)
|
||||||
UnmapViewOfFile(chain->buffer);
|
UnmapViewOfFile(chain->buffer);
|
||||||
#endif
|
#endif
|
||||||
evbuffer_file_segment_free(info->segment);
|
evbuffer_file_segment_free(info->segment);
|
||||||
@ -2680,6 +2682,7 @@ evbuffer_file_segment_new(
|
|||||||
seg->refcnt = 1;
|
seg->refcnt = 1;
|
||||||
seg->fd = fd;
|
seg->fd = fd;
|
||||||
seg->flags = flags;
|
seg->flags = flags;
|
||||||
|
seg->file_offset = offset;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define lseek _lseeki64
|
#define lseek _lseeki64
|
||||||
@ -2696,11 +2699,37 @@ evbuffer_file_segment_new(
|
|||||||
|
|
||||||
#if defined(USE_SENDFILE)
|
#if defined(USE_SENDFILE)
|
||||||
if (!(flags & EVBUF_FS_DISABLE_SENDFILE)) {
|
if (!(flags & EVBUF_FS_DISABLE_SENDFILE)) {
|
||||||
seg->offset = offset;
|
seg->can_sendfile = 1;
|
||||||
seg->type = EVBUF_FS_SENDFILE;
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (evbuffer_file_segment_materialize(seg)<0)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (!(flags & EVBUF_FS_DISABLE_LOCKING)) {
|
||||||
|
EVTHREAD_ALLOC_LOCK(seg->lock, 0);
|
||||||
|
}
|
||||||
|
return seg;
|
||||||
|
err:
|
||||||
|
mm_free(seg);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DOCDOC */
|
||||||
|
/* Requires lock */
|
||||||
|
static int
|
||||||
|
evbuffer_file_segment_materialize(struct evbuffer_file_segment *seg)
|
||||||
|
{
|
||||||
|
const unsigned flags = seg->flags;
|
||||||
|
const int fd = seg->fd;
|
||||||
|
const ev_off_t length = seg->length;
|
||||||
|
const ev_off_t offset = seg->file_offset;
|
||||||
|
|
||||||
|
if (seg->contents)
|
||||||
|
return 0; /* already materialized */
|
||||||
|
|
||||||
#if defined(_EVENT_HAVE_MMAP)
|
#if defined(_EVENT_HAVE_MMAP)
|
||||||
if (!(flags & EVBUF_FS_DISABLE_MMAP)) {
|
if (!(flags & EVBUF_FS_DISABLE_MMAP)) {
|
||||||
off_t offset_rounded = 0, offset_leftover = 0;
|
off_t offset_rounded = 0, offset_leftover = 0;
|
||||||
@ -2736,8 +2765,8 @@ evbuffer_file_segment_new(
|
|||||||
} else {
|
} else {
|
||||||
seg->mapping = mapped;
|
seg->mapping = mapped;
|
||||||
seg->contents = (char*)mapped+offset_leftover;
|
seg->contents = (char*)mapped+offset_leftover;
|
||||||
seg->offset = 0;
|
seg->mmap_offset = 0;
|
||||||
seg->type = EVBUF_FS_MMAP;
|
seg->is_mapping = 1;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2754,8 +2783,8 @@ evbuffer_file_segment_new(
|
|||||||
NULL);
|
NULL);
|
||||||
if (m != INVALID_HANDLE_VALUE) { /* Does h leak? */
|
if (m != INVALID_HANDLE_VALUE) { /* Does h leak? */
|
||||||
seg->mapping_handle = m;
|
seg->mapping_handle = m;
|
||||||
seg->offset = offset;
|
seg->mmap_offset = offset;
|
||||||
seg->type = EVBUF_FS_MMAP;
|
seg->is_mapping = 1;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2795,17 +2824,12 @@ evbuffer_file_segment_new(
|
|||||||
}
|
}
|
||||||
|
|
||||||
seg->contents = mem;
|
seg->contents = mem;
|
||||||
seg->type = EVBUF_FS_IO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
if (!(flags & EVBUF_FS_DISABLE_LOCKING)) {
|
return 0;
|
||||||
EVTHREAD_ALLOC_LOCK(seg->lock, 0);
|
|
||||||
}
|
|
||||||
return seg;
|
|
||||||
err:
|
err:
|
||||||
mm_free(seg);
|
return -1;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -2819,17 +2843,14 @@ evbuffer_file_segment_free(struct evbuffer_file_segment *seg)
|
|||||||
return;
|
return;
|
||||||
EVUTIL_ASSERT(refcnt == 0);
|
EVUTIL_ASSERT(refcnt == 0);
|
||||||
|
|
||||||
if (seg->type == EVBUF_FS_SENDFILE) {
|
if (seg->is_mapping) {
|
||||||
;
|
|
||||||
} else if (seg->type == EVBUF_FS_MMAP) {
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
CloseHandle(seg->mapping_handle);
|
CloseHandle(seg->mapping_handle);
|
||||||
#elif defined (_EVENT_HAVE_MMAP)
|
#elif defined (_EVENT_HAVE_MMAP)
|
||||||
if (munmap(seg->mapping, seg->length) == -1)
|
if (munmap(seg->mapping, seg->length) == -1)
|
||||||
event_warn("%s: munmap failed", __func__);
|
event_warn("%s: munmap failed", __func__);
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else if (seg->contents) {
|
||||||
EVUTIL_ASSERT(seg->type == EVBUF_FS_IO);
|
|
||||||
mm_free(seg->contents);
|
mm_free(seg->contents);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2847,12 +2868,23 @@ evbuffer_add_file_segment(struct evbuffer *buf,
|
|||||||
{
|
{
|
||||||
struct evbuffer_chain *chain;
|
struct evbuffer_chain *chain;
|
||||||
struct evbuffer_chain_file_segment *extra;
|
struct evbuffer_chain_file_segment *extra;
|
||||||
|
int can_use_sendfile = 0;
|
||||||
EVLOCK_LOCK(seg->lock, 0);
|
|
||||||
++seg->refcnt;
|
|
||||||
EVLOCK_UNLOCK(seg->lock, 0);
|
|
||||||
|
|
||||||
EVBUFFER_LOCK(buf);
|
EVBUFFER_LOCK(buf);
|
||||||
|
EVLOCK_LOCK(seg->lock, 0);
|
||||||
|
if (buf->flags & EVBUFFER_FLAG_DRAINS_TO_FD) {
|
||||||
|
can_use_sendfile = 1;
|
||||||
|
} else {
|
||||||
|
if (!seg->contents) {
|
||||||
|
if (evbuffer_file_segment_materialize(seg)<0) {
|
||||||
|
EVLOCK_UNLOCK(seg->lock, 0);
|
||||||
|
EVBUFFER_UNLOCK(buf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++seg->refcnt;
|
||||||
|
EVLOCK_UNLOCK(seg->lock, 0);
|
||||||
|
|
||||||
if (buf->freeze_end)
|
if (buf->freeze_end)
|
||||||
goto err;
|
goto err;
|
||||||
@ -2873,14 +2905,14 @@ evbuffer_add_file_segment(struct evbuffer *buf,
|
|||||||
extra = EVBUFFER_CHAIN_EXTRA(struct evbuffer_chain_file_segment, chain);
|
extra = EVBUFFER_CHAIN_EXTRA(struct evbuffer_chain_file_segment, chain);
|
||||||
|
|
||||||
chain->flags |= EVBUFFER_IMMUTABLE|EVBUFFER_FILESEGMENT;
|
chain->flags |= EVBUFFER_IMMUTABLE|EVBUFFER_FILESEGMENT;
|
||||||
if (seg->type == EVBUF_FS_SENDFILE) {
|
if (can_use_sendfile && seg->can_sendfile) {
|
||||||
chain->flags |= EVBUFFER_SENDFILE;
|
chain->flags |= EVBUFFER_SENDFILE;
|
||||||
chain->misalign = seg->offset + offset;
|
chain->misalign = seg->file_offset + offset;
|
||||||
chain->off = length;
|
chain->off = length;
|
||||||
chain->buffer_len = chain->misalign + length;
|
chain->buffer_len = chain->misalign + length;
|
||||||
} else if (seg->type == EVBUF_FS_MMAP) {
|
} else if (seg->is_mapping) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
ev_uint64_t total_offset = seg->offset+offset;
|
ev_uint64_t total_offset = seg->mmap_offset+offset;
|
||||||
ev_uint64_t offset_rounded=0, offset_remaining=0;
|
ev_uint64_t offset_rounded=0, offset_remaining=0;
|
||||||
LPVOID data;
|
LPVOID data;
|
||||||
if (total_offset) {
|
if (total_offset) {
|
||||||
@ -2910,7 +2942,6 @@ evbuffer_add_file_segment(struct evbuffer *buf,
|
|||||||
chain->off = length;
|
chain->off = length;
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
EVUTIL_ASSERT(seg->type == EVBUF_FS_IO);
|
|
||||||
chain->buffer = (unsigned char*)(seg->contents + offset);
|
chain->buffer = (unsigned char*)(seg->contents + offset);
|
||||||
chain->buffer_len = length;
|
chain->buffer_len = length;
|
||||||
chain->off = length;
|
chain->off = length;
|
||||||
|
@ -220,7 +220,8 @@ struct evbuffer_file_segment {
|
|||||||
unsigned flags; /**< combination of EVBUF_FS_* flags */
|
unsigned flags; /**< combination of EVBUF_FS_* flags */
|
||||||
|
|
||||||
/** What kind of file segment is this? */
|
/** What kind of file segment is this? */
|
||||||
enum {EVBUF_FS_MMAP, EVBUF_FS_SENDFILE, EVBUF_FS_IO} type;
|
unsigned can_sendfile : 1;
|
||||||
|
unsigned is_mapping : 1;
|
||||||
|
|
||||||
/** The fd that we read the data from. */
|
/** The fd that we read the data from. */
|
||||||
int fd;
|
int fd;
|
||||||
@ -233,11 +234,11 @@ struct evbuffer_file_segment {
|
|||||||
/** If we're using mmap or IO, this is the content of the file
|
/** If we're using mmap or IO, this is the content of the file
|
||||||
* segment. */
|
* segment. */
|
||||||
char *contents;
|
char *contents;
|
||||||
|
/** Position of this segment within the file. */
|
||||||
|
ev_off_t file_offset;
|
||||||
/** If we're using mmap, this is the offset within 'mapping' where
|
/** If we're using mmap, this is the offset within 'mapping' where
|
||||||
* this data segment begins. If we're using sendfile, this is the
|
* this data segment begins. */
|
||||||
* offset within the file where this data begins. If we're using IO,
|
ev_off_t mmap_offset;
|
||||||
* this is 0. */
|
|
||||||
ev_off_t offset;
|
|
||||||
/** The length of this segment. */
|
/** The length of this segment. */
|
||||||
ev_off_t length;
|
ev_off_t length;
|
||||||
};
|
};
|
||||||
|
@ -652,7 +652,7 @@ test_evbuffer_add_file(void *ptr)
|
|||||||
size_t datalen, expect_len;
|
size_t datalen, expect_len;
|
||||||
const char *compare;
|
const char *compare;
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
int want_type = 0;
|
int want_ismapping = -1, want_cansendfile = -1;
|
||||||
unsigned flags = 0;
|
unsigned flags = 0;
|
||||||
int use_segment = 1, use_bigfile = 0, map_from_offset = 0,
|
int use_segment = 1, use_bigfile = 0, map_from_offset = 0,
|
||||||
view_from_offset = 0;
|
view_from_offset = 0;
|
||||||
@ -692,17 +692,20 @@ test_evbuffer_add_file(void *ptr)
|
|||||||
/* If sendfile is set, we try to use a sendfile/splice style
|
/* If sendfile is set, we try to use a sendfile/splice style
|
||||||
* backend. */
|
* backend. */
|
||||||
flags = EVBUF_FS_DISABLE_MMAP;
|
flags = EVBUF_FS_DISABLE_MMAP;
|
||||||
want_type = EVBUF_FS_SENDFILE;
|
want_cansendfile = 1;
|
||||||
|
want_ismapping = 0;
|
||||||
} else if (strstr(impl, "mmap")) {
|
} else if (strstr(impl, "mmap")) {
|
||||||
/* If sendfile is set, we try to use a mmap/CreateFileMapping
|
/* If sendfile is set, we try to use a mmap/CreateFileMapping
|
||||||
* style backend. */
|
* style backend. */
|
||||||
flags = EVBUF_FS_DISABLE_SENDFILE;
|
flags = EVBUF_FS_DISABLE_SENDFILE;
|
||||||
want_type = EVBUF_FS_MMAP;
|
want_ismapping = 1;
|
||||||
|
want_cansendfile = 0;
|
||||||
} else if (strstr(impl, "linear")) {
|
} else if (strstr(impl, "linear")) {
|
||||||
/* If linear is set, we try to use a read-the-whole-thing
|
/* If linear is set, we try to use a read-the-whole-thing
|
||||||
* backend. */
|
* backend. */
|
||||||
flags = EVBUF_FS_DISABLE_SENDFILE|EVBUF_FS_DISABLE_MMAP;
|
flags = EVBUF_FS_DISABLE_SENDFILE|EVBUF_FS_DISABLE_MMAP;
|
||||||
want_type = EVBUF_FS_IO;
|
want_ismapping = 0;
|
||||||
|
want_cansendfile = 0;
|
||||||
} else if (strstr(impl, "default")) {
|
} else if (strstr(impl, "default")) {
|
||||||
/* The caller doesn't care which backend we use. */
|
/* The caller doesn't care which backend we use. */
|
||||||
;
|
;
|
||||||
@ -747,8 +750,14 @@ test_evbuffer_add_file(void *ptr)
|
|||||||
seg = evbuffer_file_segment_new(fd, starting_offset,
|
seg = evbuffer_file_segment_new(fd, starting_offset,
|
||||||
mapping_len, flags);
|
mapping_len, flags);
|
||||||
tt_assert(seg);
|
tt_assert(seg);
|
||||||
if ((int)seg->type != (int)want_type)
|
if (want_ismapping >= 0) {
|
||||||
tt_skip();
|
if (seg->is_mapping != (unsigned)want_ismapping)
|
||||||
|
tt_skip();
|
||||||
|
}
|
||||||
|
if (want_cansendfile >= 0) {
|
||||||
|
if (seg->can_sendfile != (unsigned)want_cansendfile)
|
||||||
|
tt_skip();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Say that it drains to a fd so that we can use sendfile. */
|
/* Say that it drains to a fd so that we can use sendfile. */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user