Skip to content

Commit 7555405

Browse files
Add libsniper HTTP client/server library (#5646)
* libsniper is a small, very fast C++ library for writing highload HTTP services (f.e. RTB services) * Add request routing
1 parent 9732b70 commit 7555405

File tree

10 files changed

+358
-0
lines changed

10 files changed

+358
-0
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ env:
2525
- "TESTDIR=C++/wt"
2626
- "TESTDIR=C++/drogon"
2727
- "TESTDIR=C++/oatpp"
28+
- "TESTDIR=C++/libsniper"
2829
- "TESTLANG=Clojure"
2930
- "TESTLANG=Crystal"
3031
- "TESTLANG=D"

frameworks/C++/libsniper/README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# [libsniper](https://gitlab.com/rtbtech/libs/libsniper) (C++) Benchmarking Test
2+
3+
## Description
4+
5+
libsniper is a small, very fast C++ library for writing highload HTTP services (f.e. RTB services)
6+
7+
## Features
8+
9+
* Supported HTTP/1.x protocol with HTTP pipelining
10+
* Keep-alive and slow requests handling
11+
* Support WaitGroup inspired by Go
12+
* Client/Server library
13+
* Graceful server shutdown
14+
15+
### Test Type Implementation Source Code
16+
17+
* [PLAINTEXT](libsniper_bench/src/main.cpp)
18+
19+
## Test URLs
20+
### PLAINTEXT
21+
22+
http://localhost:8090/plaintext
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"framework": "libsniper",
3+
"tests": [
4+
{
5+
"default": {
6+
"plaintext_url": "/plaintext",
7+
"port": 8090,
8+
"approach": "Realistic",
9+
"classification": "Platform",
10+
"database": "None",
11+
"framework": "None",
12+
"language": "C++",
13+
"flavor": "None",
14+
"orm": "None",
15+
"platform": "None",
16+
"webserver": "None",
17+
"os": "Linux",
18+
"database_os": "Linux",
19+
"display_name": "libsniper",
20+
"notes": "",
21+
"versus": "None"
22+
}
23+
}
24+
]
25+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
FROM ubuntu:20.04
2+
3+
4+
ENV DEBIAN_FRONTEND noninteractive
5+
6+
RUN apt-get -qq -y update
7+
8+
RUN apt-get -qq -y install --no-install-recommends git cmake libev-dev libgoogle-perftools-dev libfmt-dev make gcc-9 g++-9 libre2-dev libboost-stacktrace-dev
9+
10+
RUN update-alternatives --quiet --remove-all gcc \
11+
; update-alternatives --quiet --remove-all g++ \
12+
; update-alternatives --quiet --remove-all cc \
13+
; update-alternatives --quiet --remove-all cpp \
14+
; update-alternatives --quiet --install /usr/bin/gcc gcc /usr/bin/gcc-9 20 \
15+
; update-alternatives --quiet --install /usr/bin/cc cc /usr/bin/gcc-9 20 \
16+
; update-alternatives --quiet --install /usr/bin/g++ g++ /usr/bin/g++-9 20 \
17+
; update-alternatives --quiet --install /usr/bin/cpp cpp /usr/bin/g++-9 20 \
18+
; update-alternatives --quiet --config gcc \
19+
; update-alternatives --quiet --config cc \
20+
; update-alternatives --quiet --config g++ \
21+
; update-alternatives --quiet --config cpp
22+
23+
24+
COPY ./libsniper_bench /libsniper_bench
25+
26+
WORKDIR /libsniper_bench
27+
28+
RUN git config --global http.sslverify false
29+
30+
RUN git clone https://gitlab.com/rtbtech/libs/libsniper.git libs/core
31+
32+
RUN cd libs/core && git checkout 75f5cee4dcdc604d74703f5255e6f4cca20f50ce
33+
34+
RUN mkdir build && cd /libsniper_bench/build && cmake -DCMAKE_BUILD_TYPE=Release -S .. && make --jobs=`nproc`
35+
36+
ARG BENCHMARK_ENV
37+
38+
EXPOSE 8090
39+
40+
CMD ./build/bin/libsniper_bench
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
2+
3+
project(libsniper_bench LANGUAGES C CXX)
4+
5+
if (NOT CMAKE_BUILD_TYPE)
6+
message(STATUS "No build type selected, default is Release")
7+
set(CMAKE_BUILD_TYPE "Release")
8+
endif ()
9+
10+
if (NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
11+
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
12+
endif ()
13+
14+
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
15+
include(cpp)
16+
include(flags)
17+
18+
add_definitions(-DBOOST_STACKTRACE_USE_BACKTRACE)
19+
20+
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
21+
set(Boost_USE_STATIC_LIBS ON)
22+
set(Boost_USE_MULTITHREADED ON)
23+
find_package(Boost REQUIRED)
24+
find_package(Threads REQUIRED)
25+
find_package(fmt REQUIRED)
26+
27+
include_directories(SYSTEM ${BOOST_INCLUDE_DIRS})
28+
29+
set(libsniper "std" "log" "cache" "xxhash" "net" "strings" "pico" "http" "event")
30+
31+
add_subdirectory(libs)
32+
add_subdirectory(src)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
set(CMAKE_CXX_STANDARD 20)
2+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
3+
set(CMAKE_CXX_EXTENSIONS ON)
4+
5+
set(CMAKE_C_STANDARD 11)
6+
set(CMAKE_C_STANDARD_REQUIRED ON)
7+
set(CMAKE_C_EXTENSIONS ON)
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
set(COMMON_FLAGS "\
2+
-march=corei7-avx \
3+
-pipe \
4+
-m64 \
5+
-msse \
6+
-msse2 \
7+
-msse3 \
8+
-mssse3 \
9+
-msse4 \
10+
-msse4.1 \
11+
-msse4.2 \
12+
-mavx \
13+
-Wall \
14+
-Wextra \
15+
-Werror \
16+
-Wpedantic \
17+
-Wformat-security \
18+
-fno-builtin-malloc \
19+
-fno-builtin-calloc \
20+
-fno-builtin-realloc \
21+
-fno-builtin-free \
22+
-Wno-unused-parameter \
23+
-Wno-unused-but-set-variable \
24+
")
25+
26+
27+
set(COMMON_FLAGS_DEBUG "\
28+
-Og \
29+
-g \
30+
-rdynamic \
31+
")
32+
33+
set(COMMON_FLAGS_RELWITHDEBINFO "\
34+
-g \
35+
-DNDEBUG \
36+
-Ofast \
37+
-rdynamic \
38+
-funroll-loops \
39+
-fomit-frame-pointer \
40+
-Wno-misleading-indentation \
41+
")
42+
43+
44+
set(COMMON_FLAGS_RELEASE "\
45+
-DNDEBUG \
46+
-Ofast \
47+
-s \
48+
-funroll-loops \
49+
-fomit-frame-pointer \
50+
-Wno-misleading-indentation \
51+
")
52+
53+
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
54+
set(COMMON_FLAGS "\
55+
${COMMON_FLAGS} \
56+
-pthread \
57+
")
58+
59+
set(COMMON_FLAGS_DEBUG "\
60+
${COMMON_FLAGS_DEBUG} \
61+
-fsanitize=address \
62+
-fsanitize=undefined \
63+
-fsanitize=leak \
64+
-fstack-protector \
65+
-fuse-ld=gold \
66+
")
67+
68+
endif ()
69+
70+
if (UNIX AND !APPLE)
71+
message("USE LTO")
72+
include(CheckIPOSupported)
73+
check_ipo_supported(RESULT supported OUTPUT error)
74+
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
75+
endif ()
76+
77+
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COMMON_FLAGS}")
78+
set(CMAKE_C_FLAGS_DEBUG "${COMMON_FLAGS_DEBUG}")
79+
set(CMAKE_C_FLAGS_RELEASE "${COMMON_FLAGS_RELEASE}")
80+
81+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COMMON_FLAGS} -Wno-class-memaccess")
82+
set(CMAKE_CXX_FLAGS_DEBUG "${COMMON_FLAGS_DEBUG}")
83+
set(CMAKE_CXX_FLAGS_RELEASE "${COMMON_FLAGS_RELEASE}")
84+
85+
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${COMMON_FLAGS_RELWITHDEBINFO}")
86+
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${COMMON_FLAGS_RELWITHDEBINFO}")
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
set(SNIPER_INCLUDE_DIRS "" CACHE INTERNAL "sniper_include_dirs")
2+
set(SNIPER_LIBRARIES "" CACHE INTERNAL "sniper_libraries")
3+
4+
# add all subfolders
5+
file(GLOB children RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*)
6+
foreach(child ${children})
7+
if(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${child})
8+
set(SNIPER_INCLUDE_DIRS ${SNIPER_INCLUDE_DIRS} "${CMAKE_CURRENT_SOURCE_DIR}/${child}" CACHE INTERNAL "sniper_include_dirs")
9+
endif()
10+
endforeach()
11+
12+
include_directories(BEFORE ${SNIPER_INCLUDE_DIRS})
13+
14+
file(GLOB children RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*)
15+
foreach(child ${children})
16+
if(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${child})
17+
add_subdirectory(${child})
18+
endif()
19+
endforeach()
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
include_directories(.)
2+
include_directories(${SNIPER_INCLUDE_DIRS})
3+
4+
set(PROJECT_LIBS
5+
${CMAKE_THREAD_LIBS_INIT}
6+
${BOOST_LIBRARIES}
7+
backtrace dl
8+
fmt::fmt
9+
stdc++fs.a
10+
tcmalloc
11+
)
12+
13+
set(PROJECT_SRC
14+
main.cpp
15+
)
16+
17+
add_executable(${PROJECT_NAME} ${PROJECT_SRC})
18+
target_link_libraries(${PROJECT_NAME} ${SNIPER_LIBRARIES} ${PROJECT_LIBS})
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*
2+
* Copyright (c) 2020, RTBtech, MediaSniper, Oleg Romanenko ([email protected])
3+
*/
4+
5+
#include <sniper/event/Loop.h>
6+
#include <sniper/event/Timer.h>
7+
#include <sniper/http/Server.h>
8+
#include <sniper/log/log.h>
9+
#include <sniper/std/check.h>
10+
#include <sniper/std/vector.h>
11+
#include <sniper/threads/Stop.h>
12+
#include <thread>
13+
14+
using namespace sniper;
15+
16+
class Server
17+
{
18+
public:
19+
explicit Server()
20+
{
21+
for (unsigned i = 0; i < std::thread::hardware_concurrency(); i++)
22+
_workers.emplace_back(&Server::worker_noexcept, this, i);
23+
}
24+
25+
~Server()
26+
{
27+
for (auto& w : _workers)
28+
if (w.joinable())
29+
w.join();
30+
}
31+
32+
private:
33+
void worker_noexcept(unsigned int thread_num) noexcept
34+
{
35+
try {
36+
worker(thread_num);
37+
}
38+
catch (std::exception& e) {
39+
log_err(e.what());
40+
}
41+
catch (...) {
42+
log_err("[Server] non std::exception occured");
43+
}
44+
}
45+
46+
static string gen_date()
47+
{
48+
return fmt::format("Date: {:%a, %d %b %Y %H:%M:%S} GMT\r\n", fmt::gmtime(time(nullptr)));
49+
}
50+
51+
void worker(unsigned thread_num)
52+
{
53+
auto loop = event::make_loop();
54+
check(loop, "[Server] cannot init event loop");
55+
56+
http::server::Config config;
57+
config.max_conns = 100000;
58+
config.connection.keep_alive_timeout = 10min;
59+
config.connection.request_read_timeout = 10s;
60+
61+
http::Server http_server(loop, config);
62+
check(http_server.bind("", 8090), "[Server] cannot bind to localhost:8090");
63+
64+
string date = gen_date();
65+
http_server.set_cb_request([&, this](const auto& conn, const auto& req, const auto& resp) {
66+
resp->add_header_nocopy("Server: libsniper\r\n");
67+
resp->add_header_copy(date);
68+
69+
if (req->path() == "/plaintext") {
70+
resp->code = http::ResponseStatus::OK;
71+
resp->add_header_nocopy("Content-Type: text/plain; charset=UTF-8\r\n");
72+
resp->set_data_nocopy("Hello, World!");
73+
conn->send(resp);
74+
return;
75+
}
76+
77+
resp->code = http::ResponseStatus::NO_CONTENT;
78+
conn->send(resp);
79+
});
80+
81+
event::TimerRepeat timer_stop(loop, 1s, [&loop] {
82+
if (threads::Stop::get().is_stopped())
83+
loop->break_loop(ev::ALL);
84+
});
85+
86+
event::TimerRepeat timer_update_time(loop, 1s, [&date] { date = gen_date(); });
87+
88+
loop->run();
89+
}
90+
91+
vector<std::thread> _workers;
92+
};
93+
94+
int main(int argc, char** argv)
95+
{
96+
auto loop = event::make_loop();
97+
if (!loop) {
98+
log_err("Main: cannot init event loop");
99+
return EXIT_FAILURE;
100+
}
101+
102+
signal(SIGPIPE, SIG_IGN);
103+
104+
Server server;
105+
loop->run();
106+
107+
return EXIT_SUCCESS;
108+
}

0 commit comments

Comments
 (0)