This repository has been archived on 2025-09-14. You can view files and clone it, but cannot push or open issues or pull requests.
Files
doris-doris-dispatch/client/doris_client_transfer.cpp

382 lines
12 KiB
C++
Raw Normal View History

2021-07-16 16:06:59 +08:00
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include <sys/time.h>
#include <time.h>
#include <string.h>
#include <openssl/md5.h>
#include "doris_client_http.h"
#include "doris_client_transfer.h"
#include "nirvana_conhash.h"
void doris_http_ctx_reset(struct doris_http_ctx *ctx, struct doris_http_callback *cb)
{
struct doris_curl_multihd *multidata=ctx->multidata;
struct doris_http_instance *instance=ctx->instance;
if(ctx->curl != NULL)
{
curl_multi_remove_handle(ctx->multidata->multi_hd, ctx->curl);
curl_easy_cleanup(ctx->curl);
ctx->curl = NULL;
}
if(ctx->headers != NULL)
{
curl_slist_free_all(ctx->headers);
}
memset(ctx, 0, sizeof(struct doris_http_ctx));
ctx->multidata = multidata;
ctx->instance = instance;
ctx->cb = *cb;
}
void doris_http_ctx_destroy(struct doris_http_ctx *ctx)
{
if(ctx->curl != NULL)
{
curl_multi_remove_handle(ctx->multidata->multi_hd, ctx->curl);
curl_easy_cleanup(ctx->curl);
}
if(ctx->headers != NULL)
{
curl_slist_free_all(ctx->headers);
}
free(ctx);
}
struct doris_http_ctx *doris_http_ctx_new(struct doris_http_instance *instance,
struct doris_http_callback *cb, u_int64_t balance_seed, char *host, int32_t size)
2021-07-16 16:06:59 +08:00
{
struct doris_http_ctx *ctx;
struct doris_curl_multihd *multidata;
struct conhash_bucket result;
if(CONHASH_OK != conhash_lookup_bucket_int(instance->param->conhash, balance_seed, &result))
{
return NULL;
}
assert(instance->server_hosts->find(result.bucket_id) != instance->server_hosts->end());
multidata = instance->server_hosts->find(result.bucket_id)->second;
snprintf(host, size, multidata->host->srvaddr);
2021-07-16 16:06:59 +08:00
ctx = (struct doris_http_ctx *)calloc(1, sizeof(struct doris_http_ctx));
ctx->instance = instance;
ctx->multidata = multidata;
ctx->cb = *cb;
return ctx;
}
long long caculate_http_sessions_sum(const struct doris_http_instance *instance)
{
map<u_int32_t, doris_curl_multihd*>::iterator iter;
long long sessions = 0;
if(instance == NULL) return 0;
for(iter=instance->server_hosts->begin(); iter!=instance->server_hosts->end(); iter++)
{
sessions += iter->second->sessions;
}
return sessions;
}
static inline void curl_set_common_options(CURL *curl, long transfer_timeout, char *errorbuf)
{
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorbuf);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, 1000L);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, transfer_timeout); //<2F><><EFBFBD>Է<EFBFBD><D4B7>ֶ<EFBFBD><D6B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ij<EFBFBD><C4B3><EFBFBD>ӽ<EFBFBD><D3BD>տ<EFBFBD>ס<EFBFBD><D7A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
//ctx->error="Operation too slow. Less than 100 bytes/sec transferred the last 10 seconds"
curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, 10L);
curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 100L);
curl_easy_setopt(curl, CURLOPT_USERAGENT, "Doris Client Linux X64");
}
static size_t curl_response_write_cb(void *ptr, size_t size, size_t count, void *userp)
{
struct doris_http_ctx *ctx = (struct doris_http_ctx *)userp;
CURLcode code=CURLE_OK;
if(ctx->res_code == 0) //<2F>״<EFBFBD>Ӧ<EFBFBD><D3A6>ʱ<EFBFBD>ȿ<EFBFBD>Ӧ<EFBFBD><D3A6><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD>200
{
code = curl_easy_getinfo(ctx->curl, CURLINFO_RESPONSE_CODE, &ctx->res_code);
}
if(ctx->cb.write_cb != NULL)
{
ctx->cb.write_cb((const char*)ptr, size*count, code, ctx->res_code, ctx->cb.userp);
}
return size*count;
}
static size_t curl_response_header_cb(void *ptr, size_t size, size_t count, void *userp)
{
struct doris_http_ctx *ctx = (struct doris_http_ctx *)userp;
size_t len=size*count;
CURLcode code=CURLE_OK;
if(ctx->res_code == 0) //<2F>״<EFBFBD>Ӧ<EFBFBD><D3A6>ʱ<EFBFBD>ȿ<EFBFBD>Ӧ<EFBFBD><D3A6><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD>200
{
code = curl_easy_getinfo(ctx->curl, CURLINFO_RESPONSE_CODE, &ctx->res_code);
}
if(ctx->cb.header_cb != NULL)
{
ctx->cb.header_cb((const char*)ptr, len, code, ctx->res_code, ctx->cb.userp);
}
return len;
}
void doris_http_ctx_add_header(struct doris_http_ctx *ctx, const char *header)
{
ctx->headers = curl_slist_append(ctx->headers, header);
}
int doris_http_launch_get_request(struct doris_http_ctx *ctx, const char *uri)
{
char minio_url[2048];
assert(ctx->curl == NULL);
if(NULL == (ctx->curl=curl_easy_init()))
{
return -1;
}
if(ctx->instance->param->ssl_connection)
{
snprintf(minio_url, sizeof(minio_url), "https://%s/%s", ctx->multidata->host->srvaddr, uri);
curl_easy_setopt(ctx->curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(ctx->curl, CURLOPT_SSL_VERIFYHOST, 0L);
}
else
{
snprintf(minio_url, sizeof(minio_url), "http://%s/%s", ctx->multidata->host->srvaddr, uri);
}
curl_easy_setopt(ctx->curl, CURLOPT_URL, minio_url);
if(ctx->headers != NULL) //LOSFģʽ<C4A3><CABD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģʽ<C4A3>°<EFBFBD><C2B0><EFBFBD>Range<67><65>ȡ
{
curl_easy_setopt(ctx->curl, CURLOPT_HTTPHEADER, ctx->headers);
}
curl_easy_setopt(ctx->curl, CURLOPT_HEADERFUNCTION, curl_response_header_cb);
curl_easy_setopt(ctx->curl, CURLOPT_HEADERDATA, ctx);
curl_easy_setopt(ctx->curl, CURLOPT_WRITEFUNCTION, curl_response_write_cb);
curl_easy_setopt(ctx->curl, CURLOPT_WRITEDATA, ctx);
curl_easy_setopt(ctx->curl, CURLOPT_PRIVATE, ctx);
curl_set_common_options(ctx->curl, ctx->instance->param->transfer_timeout, ctx->error);
if(CURLM_OK != curl_multi_add_handle(ctx->multidata->multi_hd, ctx->curl))
{
assert(0);
return -2;
}
ctx->transfering = 1;
return 0;
}
int doris_http_launch_post_request(struct doris_http_ctx *ctx, const char *uri, const char *data, size_t data_len)
{
char minio_url[2048];
assert(ctx->curl == NULL);
if(NULL == (ctx->curl=curl_easy_init()))
{
return -1;
}
doris_http_ctx_add_header(ctx, "Expect:"); //ע<><D7A2>POST<53><54><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Expect<63><74>ϵ<EFBFBD><CFB5>Ҫ<EFBFBD><D2AA>ȷ<EFBFBD><C8B7><EFBFBD><EFBFBD>CURLOPT_POSTFIELDSIZE
if(ctx->instance->param->ssl_connection)
{
snprintf(minio_url, sizeof(minio_url), "https://%s/%s", ctx->multidata->host->srvaddr, uri);
curl_easy_setopt(ctx->curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(ctx->curl, CURLOPT_SSL_VERIFYHOST, 0L);
}
else
{
snprintf(minio_url, sizeof(minio_url), "http://%s/%s", ctx->multidata->host->srvaddr, uri);
}
curl_easy_setopt(ctx->curl, CURLOPT_POST, 1L);
curl_easy_setopt(ctx->curl, CURLOPT_URL, minio_url);
curl_easy_setopt(ctx->curl, CURLOPT_POSTFIELDSIZE, data_len); //<2F><><EFBFBD><EFBFBD>Content-Length<74><68><EFBFBD><EFBFBD>CURLOPT_COPYPOSTFIELDS֮ǰ<D6AE><C7B0><EFBFBD><EFBFBD>
if(data_len > 0)
{
curl_easy_setopt(ctx->curl, CURLOPT_COPYPOSTFIELDS, data);
}
curl_easy_setopt(ctx->curl, CURLOPT_HTTPHEADER, ctx->headers);
curl_easy_setopt(ctx->curl, CURLOPT_WRITEFUNCTION, curl_response_write_cb);
curl_easy_setopt(ctx->curl, CURLOPT_WRITEDATA, ctx);
if(ctx->cb.header_cb != NULL)
{
curl_easy_setopt(ctx->curl, CURLOPT_HEADERFUNCTION, curl_response_header_cb);
curl_easy_setopt(ctx->curl, CURLOPT_HEADERDATA, ctx);
}
curl_easy_setopt(ctx->curl, CURLOPT_PRIVATE, ctx);
curl_set_common_options(ctx->curl, ctx->instance->param->transfer_timeout, ctx->error);
if(CURLM_OK != curl_multi_add_handle(ctx->multidata->multi_hd, ctx->curl))
{
assert(0);
return -2;
}
ctx->transfering = 1;
return 0;
}
static void check_multi_info(CURLM *multi)
{
CURLMsg *msg;
int msgs_left;
struct doris_http_ctx *ctx;
CURL *easy;
CURLcode res;
while((msg = curl_multi_info_read(multi, &msgs_left)))
{
if(msg->msg != CURLMSG_DONE)
{
continue;
}
easy = msg->easy_handle;
res = msg->data.result;
curl_easy_getinfo(easy, CURLINFO_PRIVATE, &ctx);
curl_easy_getinfo(easy, CURLINFO_RESPONSE_CODE, &ctx->res_code);
curl_multi_remove_handle(multi, easy);
curl_easy_cleanup(easy);
ctx->curl = NULL;
ctx->transfering = 0;
ctx->res = res;
ctx->cb.transfer_done_cb(ctx->res, ctx->res_code, ctx->error, ctx->cb.userp);
}
}
/* Called by libevent when we get action on a multi socket */
static void libevent_socket_event_cb(int fd, short action, void *userp)
{
struct doris_curl_multihd *multidata = (struct doris_curl_multihd *)userp; //from event_assign
CURLMcode rc;
int what, still_running;
what = ((action&EV_READ)?CURL_CSELECT_IN:0) | ((action & EV_WRITE)?CURL_CSELECT_OUT:0);
rc = curl_multi_socket_action(multidata->multi_hd, fd, what, &still_running);
multidata->sessions = still_running;
assert(rc==CURLM_OK);
check_multi_info(multidata->multi_hd);
if(still_running<=0 && evtimer_pending(&multidata->timer_event, NULL))
{
evtimer_del(&multidata->timer_event);
}
}
/* Called by libevent when our timeout expires */
static void libevent_timer_event_cb(int fd, short kind, void *userp)
{
struct doris_curl_multihd *multidata = (struct doris_curl_multihd *)userp;
CURLMcode rc;
int still_running;
rc = curl_multi_socket_action(multidata->multi_hd, CURL_SOCKET_TIMEOUT, 0, &still_running);
multidata->sessions = still_running;
assert(rc==CURLM_OK);
check_multi_info(multidata->multi_hd);
}
static int curl_socket_function_cb(CURL *curl, curl_socket_t sockfd, int what, void *userp, void *sockp)
{
struct doris_curl_multihd *multidata = (struct doris_curl_multihd *)userp;
struct curl_socket_data *sockinfo = (struct curl_socket_data *)sockp; //curl_multi_assign, for socket
int action;
if(what == CURL_POLL_REMOVE)
{
if(sockinfo != NULL)
{
event_del(&sockinfo->sock_event);
free(sockinfo);
}
}
else
{
if(sockinfo == NULL)
{
sockinfo = (struct curl_socket_data *)calloc(1, sizeof(struct curl_socket_data));
curl_multi_assign(multidata->multi_hd, sockfd, sockinfo);
}
else
{
event_del(&sockinfo->sock_event);
}
action = (what&CURL_POLL_IN?EV_READ:0)|(what&CURL_POLL_OUT?EV_WRITE:0)|EV_PERSIST;
event_assign(&sockinfo->sock_event, multidata->evbase, sockfd, action, libevent_socket_event_cb, multidata);
event_add(&sockinfo->sock_event, NULL);
}
return 0;
}
static int curl_timer_function_cb(CURLM *multi, long timeout_ms, void *userp)
{
struct doris_curl_multihd *multidata = (struct doris_curl_multihd *)userp;
struct timeval timeout;
CURLMcode rc;
int still_running;
timeout.tv_sec = timeout_ms/1000;
timeout.tv_usec = (timeout_ms%1000)*1000;
if(timeout_ms == 0)
{
//timeout_ms is 0 means we should call curl_multi_socket_action/curl_multi_perform at once.
//To initiate the whole process(inform CURLMOPT_SOCKETFUNCTION callback) or when timeout occurs.
rc = curl_multi_socket_action(multi, CURL_SOCKET_TIMEOUT, 0, &still_running);
multidata->sessions = still_running;
assert(rc==CURLM_OK);
}
else if(timeout_ms == -1) //timeout_ms is -1 means we should delete the timer.
{
//call curl_multi_socket_action to update multidata->sessions, otherwise it will not be updated to 0
//when all transfers complete in some occasions(eg, GET, some objects hited while others miss).
rc = curl_multi_socket_action(multi, CURL_SOCKET_TIMEOUT, 0, &still_running);
multidata->sessions = still_running;
evtimer_del(&multidata->timer_event);
}
else //update the timer to the new value.
{
evtimer_add(&multidata->timer_event, &timeout);
}
return 0; //0-success; -1-error
}
//Ϊÿ<CEAA><C3BF>Minio Host<73><74><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ե<EFBFBD>curl multi handle
struct doris_curl_multihd *doris_initialize_multihd_for_host(struct doris_http_instance *instance, struct dst_host_cnn_balance *host)
{
struct doris_curl_multihd *multidata;
multidata = (struct doris_curl_multihd *)calloc(1, sizeof(struct doris_curl_multihd));
multidata->multi_hd = curl_multi_init();
multidata->evbase = instance->evbase;
multidata->host = host;
curl_multi_setopt(multidata->multi_hd, CURLMOPT_PIPELINING, CURLPIPE_HTTP1 | CURLPIPE_MULTIPLEX);
curl_multi_setopt(multidata->multi_hd, CURLMOPT_MAX_HOST_CONNECTIONS, instance->param->maximum_host_cnns);
curl_multi_setopt(multidata->multi_hd, CURLMOPT_MAX_PIPELINE_LENGTH, instance->param->maximum_pipelines);
curl_multi_setopt(multidata->multi_hd, CURLMOPT_SOCKETFUNCTION, curl_socket_function_cb);
curl_multi_setopt(multidata->multi_hd, CURLMOPT_SOCKETDATA, multidata); //curl_socket_function_cb *userp
curl_multi_setopt(multidata->multi_hd, CURLMOPT_TIMERFUNCTION, curl_timer_function_cb);
curl_multi_setopt(multidata->multi_hd, CURLMOPT_TIMERDATA, multidata);
evtimer_assign(&multidata->timer_event, instance->evbase, libevent_timer_event_cb, multidata);
return multidata;
}