35
35
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
36
36
37
37
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 ,
41
41
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 ,
45
48
};
46
49
47
50
struct http_data {
@@ -64,6 +67,7 @@ struct http_options {
64
67
char * swift_auth_token ;
65
68
int verbose ;
66
69
unsigned int mode ;
70
+ unsigned int object_mode ;
67
71
};
68
72
69
73
struct http_curl_stream {
@@ -239,6 +243,26 @@ static struct fio_option options[] = {
239
243
.category = FIO_OPT_C_ENGINE ,
240
244
.group = FIO_OPT_G_HTTP ,
241
245
},
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
+ },
242
266
{
243
267
.name = NULL ,
244
268
},
@@ -611,6 +635,26 @@ static void _add_swift_header(CURL *curl, struct curl_slist *slist, struct http_
611
635
free (dsha );
612
636
}
613
637
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
+
614
658
static void fio_http_cleanup (struct thread_data * td )
615
659
{
616
660
struct http_data * http = td -> io_ops_data ;
@@ -667,30 +711,39 @@ static enum fio_q_status fio_http_queue(struct thread_data *td,
667
711
struct http_options * o = td -> eo ;
668
712
struct http_curl_stream _curl_stream ;
669
713
struct curl_slist * slist = NULL ;
670
- char object [512 ];
714
+ char object_path_buf [512 ];
715
+ char * object_path ;
671
716
char url [1024 ];
672
717
long status ;
673
718
CURLcode res ;
674
719
675
720
fio_ro_check (td , io_u );
676
721
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 ;
679
728
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 );
681
730
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
+
683
733
curl_easy_setopt (http -> curl , CURLOPT_URL , url );
684
734
_curl_stream .buf = io_u -> xfer_buf ;
685
735
_curl_stream .max = io_u -> xfer_buflen ;
686
736
curl_easy_setopt (http -> curl , CURLOPT_SEEKDATA , & _curl_stream );
687
737
curl_easy_setopt (http -> curl , CURLOPT_INFILESIZE_LARGE , (curl_off_t )io_u -> xfer_buflen );
688
738
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
+
689
742
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 ,
691
744
io_u -> xfer_buf , io_u -> xfer_buflen );
692
745
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 ,
694
747
io_u -> xfer_buf , io_u -> xfer_buflen );
695
748
696
749
if (io_u -> ddir == DDIR_WRITE ) {
@@ -712,7 +765,9 @@ static enum fio_q_status fio_http_queue(struct thread_data *td,
712
765
res = curl_easy_perform (http -> curl );
713
766
if (res == CURLE_OK ) {
714
767
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 ))
716
771
goto out ;
717
772
else if (status == 404 ) {
718
773
/* Object doesn't exist. Pretend we read
0 commit comments