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/server/doris_server_http.cpp
linuxrc@163.com 26b1a08500 创建
2021-07-16 16:06:59 +08:00

278 lines
9.5 KiB
C++

#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <sys/prctl.h>
#include <poll.h>
#include "doris_server_main.h"
#include "doris_server_http.h"
extern struct nirvana_global_info g_doris_server_info;
static inline void set_sockopt_keepalive(int sd, int keepidle, int keepintvl, int keepcnt)
{
int keepalive = 1;
setsockopt(sd, SOL_SOCKET, SO_KEEPALIVE, (void*)&keepalive, sizeof(keepalive));
setsockopt(sd, SOL_TCP, TCP_KEEPIDLE, (void*)&keepidle, sizeof(keepidle));
setsockopt(sd, SOL_TCP, TCP_KEEPINTVL, (void*)&keepintvl, sizeof(keepintvl));
setsockopt(sd, SOL_TCP, TCP_KEEPCNT, (void*)&keepcnt, sizeof(keepcnt));
}
static inline void set_listen_sockopt(int sd)
{
if(g_doris_server_info.sock_recv_bufsize > 0)
{
setsockopt(sd, SOL_SOCKET, SO_RCVBUF, &g_doris_server_info.sock_recv_bufsize, sizeof(u_int32_t));
}
}
int doris_create_listen_socket(int bind_port)
{
evutil_socket_t listener;
struct sockaddr_in sin;
listener = socket(AF_INET, SOCK_STREAM, 0);
if(listener < 0)
{
MESA_RUNTIME_LOGV3(g_doris_server_info.log_runtime, RLOG_LV_FATAL, "create socket error!\n");
return -1;
}
set_sockopt_keepalive(listener, 300, 10, 2);
set_listen_sockopt(listener);
evutil_make_listen_socket_reuseable(listener);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr=htonl(INADDR_ANY);
sin.sin_port = htons(bind_port);
if (bind(listener, (struct sockaddr *)&sin, sizeof(sin)) < 0)
{
printf("bind socket to port: %d error: %s!\n", bind_port, strerror(errno));
MESA_RUNTIME_LOGV3(g_doris_server_info.log_runtime, RLOG_LV_FATAL, "bind socket to port: %d error: %s!\n", bind_port, strerror(errno));
assert(0);return -2;
}
if (listen(listener, 1024)<0)
{
MESA_RUNTIME_LOGV3(g_doris_server_info.log_runtime, RLOG_LV_FATAL, "listen socket 1024 error!\n");
return -3;
}
evutil_make_socket_nonblocking(listener);
return listener;
}
void doris_http_server_meta_cb(struct evhttp_request *req, void *arg)
{
struct worker_statistic_info *statistic=(struct worker_statistic_info *)arg;
struct evkeyvalq params;
const char *version;
int64_t verlong;
char *endptr=NULL, length[64];
struct version_list_node *vernode;
struct evbuffer *evbuf;
statistic->statistic.field[DRS_FSSTAT_CLIENT_META_REQ] += 1;
if(evhttp_parse_query(evhttp_request_get_uri(req), &params))
{
statistic->statistic.field[DRS_FSSTAT_CLIENT_INVALID_REQ] += 1;
evhttp_send_error(req, HTTP_BADREQUEST, "Parameters invalid");
return;
}
if(NULL == (version = evhttp_find_header(&params, "version")))
{
statistic->statistic.field[DRS_FSSTAT_CLIENT_INVALID_REQ] += 1;
evhttp_send_error(req, HTTP_BADREQUEST, "Parameters invalid, no version found");
return;
}
if(0==(verlong = strtol(version, &endptr, 10)) || *endptr!='\0')
{
statistic->statistic.field[DRS_FSSTAT_CLIENT_INVALID_REQ] += 1;
evhttp_send_error(req, HTTP_BADREQUEST, "Parameter version invalid");
return;
}
pthread_rwlock_rdlock(&g_doris_server_info.rwlock);
if(verlong > g_doris_server_info.cfgver_head->latest_version)
{
pthread_rwlock_unlock(&g_doris_server_info.rwlock);
statistic->statistic.field[DRS_FSSTAT_SEND_META_NONEW] += 1;
evhttp_send_error(req, HTTP_NOTMODIFIED, "No new configs found");
return;
}
vernode = TAILQ_FIRST(&g_doris_server_info.cfgver_head->version_head);
while(vernode->version < verlong)
{
vernode = TAILQ_NEXT(vernode, version_node);
}
evbuf = evbuffer_new();
evbuffer_add(evbuf, vernode->metacont, vernode->metalen);
sprintf(length, "%u", vernode->metalen);
pthread_rwlock_unlock(&g_doris_server_info.rwlock);
statistic->statistic.field[DRS_FSSTAT_SEND_META_RES] += 1;
evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "application/json");
evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "keep-alive");
evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Length", length);
evhttp_send_reply(req, HTTP_OK, "OK", evbuf);
evbuffer_free(evbuf);
}
void doris_response_file_range(struct evhttp_request *req, const char *tablename,
int64_t verlong, size_t start, size_t end, bool range, struct worker_statistic_info *statistic)
{
struct version_list_node *vernode;
struct table_list_node *tablenode;
struct cont_frag_node *fragnode;
struct evbuffer *evbuf;
char length[128];
size_t filesize, res_length=0, copy_len, offset=start;
pthread_rwlock_rdlock(&g_doris_server_info.rwlock);
if(verlong > g_doris_server_info.cfgver_head->latest_version)
{
pthread_rwlock_unlock(&g_doris_server_info.rwlock);
statistic->statistic.field[DRS_FSSTAT_SEND_FILE_RES_404] += 1;
evhttp_send_error(req, HTTP_NOTFOUND, "Version too old");
return;
}
vernode = TAILQ_FIRST(&g_doris_server_info.cfgver_head->version_head);
while(vernode->version < verlong)
{
vernode = TAILQ_NEXT(vernode, version_node);
}
tablenode = TAILQ_FIRST(&vernode->table_head);
while(tablenode!=NULL && strcmp(tablename, tablenode->tablename))
{
tablenode = TAILQ_NEXT(tablenode, table_node);
}
if(tablenode==NULL || start>tablenode->filesize)
{
pthread_rwlock_unlock(&g_doris_server_info.rwlock);
statistic->statistic.field[DRS_FSSTAT_SEND_FILE_RES_404] += 1;
evhttp_send_error(req, HTTP_NOTFOUND, "No valid content found");
return;
}
filesize = tablenode->filesize;
if(end==0 || end >= tablenode->filesize)
{
end = tablenode->filesize - 1;
}
evbuf = evbuffer_new();
for(fragnode=TAILQ_FIRST(&tablenode->frag_head); fragnode!=NULL && fragnode->start<=end; fragnode=TAILQ_NEXT(fragnode, frag_node))
{
if(offset > fragnode->end)
{
continue;
}
copy_len = (end>fragnode->end)?(fragnode->end-offset + 1):(end-offset + 1);
evbuffer_add(evbuf, fragnode->content+(offset-fragnode->start), copy_len);
offset += copy_len;
res_length += copy_len;
}
pthread_rwlock_unlock(&g_doris_server_info.rwlock);
assert(res_length == end + 1 - start);
sprintf(length, "%lu", res_length);
statistic->statistic.field[DRS_FSSTAT_SEND_FILE_RES] += 1;
statistic->statistic.field[DRS_FSSTAT_SEND_FILE_BYTES] += res_length;
evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Length", length);
if(range)
{
sprintf(length, "bytes %lu-%lu/%lu", start, end, filesize);
evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Range", length);
}
evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "application/stream");
evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "keep-alive");
evhttp_send_reply(req, HTTP_OK, "OK", evbuf);
}
void doris_http_server_file_cb(struct evhttp_request *req, void *arg)
{
struct worker_statistic_info *statistic=(struct worker_statistic_info *)arg;
struct evkeyvalq params;
const char *version, *tablename, *content_range;
int64_t verlong;
char *endptr=NULL;
size_t req_start=0, req_end=0;
statistic->statistic.field[DRS_FSSTAT_CLIENT_FILE_REQ] += 1;
if(evhttp_parse_query(evhttp_request_get_uri(req), &params))
{
statistic->statistic.field[DRS_FSSTAT_CLIENT_INVALID_REQ] += 1;
evhttp_send_error(req, HTTP_BADREQUEST, "Parameters invalid");
return;
}
if(NULL==(version=evhttp_find_header(&params, "version")) || NULL==(tablename=evhttp_find_header(&params, "tablename")))
{
statistic->statistic.field[DRS_FSSTAT_CLIENT_INVALID_REQ] += 1;
evhttp_send_error(req, HTTP_BADREQUEST, "Parameters invalid, no version/tablename found");
return;
}
if(0==(verlong = strtol(version, &endptr, 10)) || *endptr!='\0')
{
statistic->statistic.field[DRS_FSSTAT_CLIENT_INVALID_REQ] += 1;
evhttp_send_error(req, HTTP_BADREQUEST, "Parameter version invalid");
return;
}
if(NULL!=(content_range = evhttp_find_header(evhttp_request_get_input_headers(req), "Range")) &&
sscanf(content_range, "%*[^0-9]%lu-%lu", &req_start, &req_end)<1)
{
statistic->statistic.field[DRS_FSSTAT_CLIENT_INVALID_REQ] += 1;
evhttp_send_error(req, HTTP_BADREQUEST, "Header Range invalid");
return;
}
doris_response_file_range(req, tablename, verlong, req_start, req_end, (content_range==NULL)?false:true, statistic);
}
void doris_http_server_generic_cb(struct evhttp_request *req, void *arg)
{
evhttp_send_error(req, HTTP_BADREQUEST, "Not Supported.");
}
void* thread_doris_http_server(void *arg)
{
struct event_base *worker_evbase;
struct evhttp *worker_http;
struct worker_statistic_info statistic;
struct timeval tv;
prctl(PR_SET_NAME, "http_server");
memset(&statistic, 0, sizeof(struct worker_statistic_info));
worker_evbase = event_base_new();
worker_http = evhttp_new(worker_evbase);
evhttp_set_cb(worker_http, "/configmeta", doris_http_server_meta_cb, &statistic);
evhttp_set_cb(worker_http, "/configfile", doris_http_server_file_cb, &statistic);
evhttp_set_gencb(worker_http, doris_http_server_generic_cb, &statistic);
evhttp_set_allowed_methods(worker_http, EVHTTP_REQ_GET|EVHTTP_REQ_HEAD);
if(evhttp_accept_socket(worker_http, g_doris_server_info.listener))
{
printf("evhttp_accept_socket %d error!\n", g_doris_server_info.listener);
assert(0); return NULL;
}
evtimer_assign(&statistic.timer_statistic, worker_evbase, doris_worker_statistic_timer_cb, &statistic);
tv.tv_sec = g_doris_server_info.fsstat_period;
tv.tv_usec = 0;
evtimer_add(&statistic.timer_statistic, &tv);
event_base_dispatch(worker_evbase);
printf("Libevent dispath error, should not run here.\n");
MESA_RUNTIME_LOGV3(g_doris_server_info.log_runtime, RLOG_LV_FATAL, "Libevent dispath error, should not run here.");
return NULL;
}