Skip to content

Commit 7664dcc

Browse files
committed
Merge branch 'http-range-header' of https://github.com/sfc-gh-rnarubin/fio
* 'http-range-header' of https://github.com/sfc-gh-rnarubin/fio: engines/http: Add support for range reads
2 parents fef6410 + bd42e45 commit 7664dcc

File tree

3 files changed

+107
-14
lines changed

3 files changed

+107
-14
lines changed

HOWTO.rst

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3058,6 +3058,24 @@ with the caveat that when used on the command line, they must come after the
30583058
turns on verbose logging from libcurl, 2 additionally enables
30593059
HTTP IO tracing. Default is **0**
30603060

3061+
.. option:: http_object_mode=str : [http]
3062+
3063+
How to structure objects for HTTP IO: *block* or *range*.
3064+
Default is **block**.
3065+
3066+
In *block* mode, one object is created for every block. The HTTP engine
3067+
treats :option:`blocksize` as the size of the object to read or write,
3068+
and appends the block start/end offsets to the :option:`filename` to
3069+
create the target object path. Reads and writes operate on whole
3070+
objects at a time.
3071+
3072+
In *range* mode, one object is created for every file. The object path
3073+
is the filename directly for both read and write I/O. For read
3074+
requests, the :option:`blocksize` and :option:`offset` will be used to
3075+
set the "Range" header on read requests to issue partial reads of the
3076+
object. For write requests, blocksize is used to set the size of the
3077+
object, the same as in *block* mode.
3078+
30613079
.. option:: uri=str : [nbd]
30623080

30633081
Specify the NBD URI of the server to test. The string

engines/http.c

Lines changed: 69 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,16 @@
3535
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
3636

3737
enum {
38-
FIO_HTTP_WEBDAV = 0,
39-
FIO_HTTP_S3 = 1,
40-
FIO_HTTP_SWIFT = 2,
38+
FIO_HTTP_WEBDAV = 0,
39+
FIO_HTTP_S3 = 1,
40+
FIO_HTTP_SWIFT = 2,
4141

42-
FIO_HTTPS_OFF = 0,
43-
FIO_HTTPS_ON = 1,
44-
FIO_HTTPS_INSECURE = 2,
42+
FIO_HTTPS_OFF = 0,
43+
FIO_HTTPS_ON = 1,
44+
FIO_HTTPS_INSECURE = 2,
45+
46+
FIO_HTTP_OBJECT_BLOCK = 0,
47+
FIO_HTTP_OBJECT_RANGE = 1,
4548
};
4649

4750
struct http_data {
@@ -64,6 +67,7 @@ struct http_options {
6467
char *swift_auth_token;
6568
int verbose;
6669
unsigned int mode;
70+
unsigned int object_mode;
6771
};
6872

6973
struct http_curl_stream {
@@ -239,6 +243,26 @@ static struct fio_option options[] = {
239243
.category = FIO_OPT_C_ENGINE,
240244
.group = FIO_OPT_G_HTTP,
241245
},
246+
{
247+
.name = "http_object_mode",
248+
.lname = "Object mode to use",
249+
.type = FIO_OPT_STR,
250+
.help = "How to structure objects when issuing HTTP requests",
251+
.off1 = offsetof(struct http_options, object_mode),
252+
.def = "block",
253+
.posval = {
254+
{ .ival = "block",
255+
.oval = FIO_HTTP_OBJECT_BLOCK,
256+
.help = "One object per block",
257+
},
258+
{ .ival = "range",
259+
.oval = FIO_HTTP_OBJECT_RANGE,
260+
.help = "One object per file, range reads per block",
261+
},
262+
},
263+
.category = FIO_OPT_C_ENGINE,
264+
.group = FIO_OPT_G_HTTP,
265+
},
242266
{
243267
.name = NULL,
244268
},
@@ -611,6 +635,26 @@ static void _add_swift_header(CURL *curl, struct curl_slist *slist, struct http_
611635
free(dsha);
612636
}
613637

638+
static struct curl_slist* _append_range_header(struct curl_slist *slist, unsigned long long offset, unsigned long long length, unsigned long long file_size)
639+
{
640+
char s[256];
641+
unsigned long long end_byte;
642+
643+
/* Don't request beyond end of file */
644+
if (offset >= file_size) {
645+
return slist;
646+
}
647+
648+
/* Calculate end byte, but cap it at file size - 1 because end range is inclusive */
649+
end_byte = offset + length - 1;
650+
if (end_byte >= file_size) {
651+
end_byte = file_size - 1;
652+
}
653+
654+
snprintf(s, sizeof(s), "Range: bytes=%llu-%llu", offset, end_byte);
655+
return curl_slist_append(slist, s);
656+
}
657+
614658
static void fio_http_cleanup(struct thread_data *td)
615659
{
616660
struct http_data *http = td->io_ops_data;
@@ -667,30 +711,39 @@ static enum fio_q_status fio_http_queue(struct thread_data *td,
667711
struct http_options *o = td->eo;
668712
struct http_curl_stream _curl_stream;
669713
struct curl_slist *slist = NULL;
670-
char object[512];
714+
char object_path_buf[512];
715+
char *object_path;
671716
char url[1024];
672717
long status;
673718
CURLcode res;
674719

675720
fio_ro_check(td, io_u);
676721
memset(&_curl_stream, 0, sizeof(_curl_stream));
677-
snprintf(object, sizeof(object), "%s_%llu_%llu", io_u->file->file_name,
678-
io_u->offset, io_u->xfer_buflen);
722+
if (o->object_mode == FIO_HTTP_OBJECT_BLOCK) {
723+
snprintf(object_path_buf, sizeof(object_path_buf), "%s_%llu_%llu", io_u->file->file_name,
724+
io_u->offset, io_u->xfer_buflen);
725+
object_path = object_path_buf;
726+
} else
727+
object_path = io_u->file->file_name;
679728
if (o->https == FIO_HTTPS_OFF)
680-
snprintf(url, sizeof(url), "http://%s%s", o->host, object);
729+
snprintf(url, sizeof(url), "http://%s%s", o->host, object_path);
681730
else
682-
snprintf(url, sizeof(url), "https://%s%s", o->host, object);
731+
snprintf(url, sizeof(url), "https://%s%s", o->host, object_path);
732+
683733
curl_easy_setopt(http->curl, CURLOPT_URL, url);
684734
_curl_stream.buf = io_u->xfer_buf;
685735
_curl_stream.max = io_u->xfer_buflen;
686736
curl_easy_setopt(http->curl, CURLOPT_SEEKDATA, &_curl_stream);
687737
curl_easy_setopt(http->curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)io_u->xfer_buflen);
688738

739+
if (io_u->ddir == DDIR_READ && o->object_mode == FIO_HTTP_OBJECT_RANGE)
740+
slist = _append_range_header(slist, io_u->offset, io_u->xfer_buflen, io_u->file->real_file_size);
741+
689742
if (o->mode == FIO_HTTP_S3)
690-
_add_aws_auth_header(http->curl, slist, o, io_u->ddir, object,
743+
_add_aws_auth_header(http->curl, slist, o, io_u->ddir, object_path,
691744
io_u->xfer_buf, io_u->xfer_buflen);
692745
else if (o->mode == FIO_HTTP_SWIFT)
693-
_add_swift_header(http->curl, slist, o, io_u->ddir, object,
746+
_add_swift_header(http->curl, slist, o, io_u->ddir, object_path,
694747
io_u->xfer_buf, io_u->xfer_buflen);
695748

696749
if (io_u->ddir == DDIR_WRITE) {
@@ -712,7 +765,9 @@ static enum fio_q_status fio_http_queue(struct thread_data *td,
712765
res = curl_easy_perform(http->curl);
713766
if (res == CURLE_OK) {
714767
curl_easy_getinfo(http->curl, CURLINFO_RESPONSE_CODE, &status);
715-
if (status == 200)
768+
/* 206 "Partial Content" means success when using the
769+
* Range header */
770+
if (status == 200 || (o->object_mode == FIO_HTTP_OBJECT_RANGE && status == 206))
716771
goto out;
717772
else if (status == 404) {
718773
/* Object doesn't exist. Pretend we read

fio.1

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2648,6 +2648,26 @@ Enable verbose requests from libcurl. Useful for debugging. 1 turns on
26482648
verbose logging from libcurl, 2 additionally enables HTTP IO tracing.
26492649
Default is \fB0\fR
26502650
.TP
2651+
.BI (http)http_object_mode \fR=\fPstr
2652+
How to structure objects for HTTP IO: block or range. Default is \fBblock\fR.
2653+
.RS
2654+
.RS
2655+
.TP
2656+
.B block
2657+
One object is created for every block. The HTTP engine treats \fBblocksize\fR
2658+
as the size of the object to read or write, and appends the block start/end
2659+
offsets to the \fBfilename\fR to create the target object path. Reads and
2660+
writes operate on whole objects at a time.
2661+
.TP
2662+
.B range
2663+
One object is created for every file. The object path is the filename directly
2664+
for both read and write I/O. For read requests, the \fBblocksize\fR and
2665+
\fBoffset\fR will be used to set the "Range" header on read requests to issue
2666+
partial reads of the object. For write requests, blocksize is used to set the
2667+
size of the object, the same as in \fBblock\fR mode.
2668+
.RE
2669+
.RE
2670+
.TP
26512671
.BI (mtd)skip_bad \fR=\fPbool
26522672
Skip operations against known bad blocks.
26532673
.TP

0 commit comments

Comments
 (0)