• Stars
    star
    1,743
  • Rank 26,709 (Top 0.6 %)
  • Language
    C++
  • License
    Apache License 2.0
  • Created almost 9 years ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Mirror of Apache Kudu

Kudu Developer Documentation

Building and installing Kudu

Follow the steps in the documentation to build and install Kudu from source

Building Kudu out of tree

A single Kudu source tree may be used for multiple builds, each with its own build directory. Build directories may be placed anywhere in the filesystem with the exception of the root directory of the source tree. The Kudu build is invoked with a working directory of the build directory itself, so you must ensure it exists (i.e. create it with mkdir -p). Itโ€™s recommended to place all build directories within the build subdirectory; build/latest will be symlinked to most recently created one.

The rest of this document assumes the build directory <root directory of kudu source tree>/build/debug.

Automatic rebuilding of dependencies

The script thirdparty/build-if-necessary.sh is invoked by cmake, so new thirdparty dependencies added by other developers will be downloaded and built automatically in subsequent builds if necessary.

To disable the automatic invocation of build-if-necessary.sh, set the NO_REBUILD_THIRDPARTY environment variable:

$ cd build/debug
$ NO_REBUILD_THIRDPARTY=1 cmake ../..

This can be particularly useful when trying to run tools like git bisect between two commits which may have different dependencies.

Building Kudu itself

# Add <root of kudu tree>/thirdparty/installed/common/bin to your $PATH
# before other parts of $PATH that may contain cmake, such as /usr/bin
# For example: "export PATH=$HOME/git/kudu/thirdparty/installed/common/bin:$PATH"
# if using bash.
$ mkdir -p build/debug
$ cd build/debug
$ cmake ../..
$ make -j8  # or whatever level of parallelism your machine can handle

The build artifacts, including the test binaries, will be stored in build/debug/bin/.

To omit the Kudu unit tests during the build, add -DNO_TESTS=1 to the invocation of cmake. For example:

$ cd build/debug
$ cmake -DNO_TESTS=1 ../..

Running unit/functional tests

To run the Kudu unit tests, you can use the ctest command from within the build/debug directory:

$ cd build/debug
$ ctest -j8

This command will report any tests that failed, and the test logs will be written to build/debug/test-logs.

Individual tests can be run by directly invoking the test binaries in build/debug/bin. Since Kudu uses the Google C++ Test Framework (gtest), specific test cases can be run with gtest flags:

# List all the tests within a test binary, then run a single test
$ build/debug/bin/tablet-test --gtest_list_tests
$ build/debug/bin/tablet-test --gtest_filter=TestTablet/9.TestFlush

gtest also allows more complex filtering patterns. See the upstream documentation for more details.

Running tests with the clang AddressSanitizer enabled

AddressSanitizer is a nice clang feature which can detect many types of memory errors. The Jenkins setup for kudu runs these tests automatically on a regular basis, but if you make large changes it can be a good idea to run it locally before pushing. To do so, youโ€™ll need to build using clang:

$ mkdir -p build/asan
$ cd build/asan
$ CC=../../thirdparty/clang-toolchain/bin/clang \
  CXX=../../thirdparty/clang-toolchain/bin/clang++ \
  ../../thirdparty/installed/common/bin/cmake \
  -DKUDU_USE_ASAN=1 ../..
$ make -j8
$ ctest -j8

The tests will run significantly slower than without ASAN enabled, and if any memory error occurs, the test that triggered it will fail. You can then use a command like:

$ cd build/asan
$ ctest -R failing-test

to run just the failed test.

Note
For more information on AddressSanitizer, please see the ASAN web page.

Running tests with the clang Undefined Behavior Sanitizer (UBSAN) enabled

Similar to the above, you can use a special set of clang flags to enable the Undefined Behavior Sanitizer. This will generate errors on certain pieces of code which may not themselves crash but rely on behavior which isnโ€™t defined by the C++ standard (and thus are likely bugs). To enable UBSAN, follow the same directions as for ASAN above, but pass the -DKUDU_USE_UBSAN=1 flag to the cmake invocation.

In order to get a stack trace from UBSan, you can use gdb on the failing test, and set a breakpoint as follows:

(gdb) b __ubsan::Diag::~Diag

Then, when the breakpoint fires, gather a backtrace as usual using the bt command.

Running tests with ThreadSanitizer enabled

ThreadSanitizer (TSAN) is a feature of recent Clang and GCC compilers which can detect improperly synchronized access to data along with many other threading bugs. To enable TSAN, pass -DKUDU_USE_TSAN=1 to the cmake invocation, recompile, and run tests. For example:

$ mkdir -p build/tsan
$ cd build/tsan
$ CC=../../thirdparty/clang-toolchain/bin/clang \
    CXX=../../thirdparty/clang-toolchain/bin/clang++ \
    ../../thirdparty/installed/common/bin/cmake \
    -DKUDU_USE_TSAN=1 ../..
$ make -j8
$ ctest -j8

TSAN may truncate a few lines of the stack trace when reporting where the error is. This can be bewildering. Itโ€™s documented for TSANv1 here: https://code.google.com/p/data-race-test/wiki/ThreadSanitizerAlgorithm It is not mentioned in the documentation for TSANv2, but has been observed. In order to find out what is really happening, set a breakpoint on the TSAN report in GDB using the following incantation:

$ gdb -ex 'set disable-randomization off' -ex 'b __tsan::PrintReport' ./some-test

Generating code coverage reports

In order to generate a code coverage report, you must use the following flags:

$ mkdir -p build/coverage
$ cd build/coverage
$ CC=../../thirdparty/clang-toolchain/bin/clang \
  CXX=../../thirdparty/clang-toolchain/bin/clang++ \
  cmake -DKUDU_GENERATE_COVERAGE=1 ../..
$ make -j4
$ ctest -j4

This will generate the code coverage files with extensions .gcno and .gcda. You can then use a tool like gcovr or llvm-cov gcov to visualize the results. For example, using gcovr:

$ cd build/coverage
$ mkdir cov_html
$ ../../thirdparty/installed/common/bin/gcovr \
      --gcov-executable=$(pwd)/../../build-support/llvm-gcov-wrapper \
      --html --html-details -o cov_html/coverage.html

Then open cov_html/coverage.html in your web browser.

Running lint checks

Kudu uses cpplint.py from Google to enforce coding style guidelines. You can run the lint checks via cmake using the ilint target:

$ make ilint

This will scan any file which is dirty in your working tree, or changed since the last gerrit-integrated upstream change in your git log. If you really want to do a full scan of the source tree, you may use the lint target instead.

Running clang-tidy checks

Kudu also uses the clang-tidy tool from LLVM to enforce coding style guidelines. You can run the tidy checks via cmake using the tidy target:

$ make tidy

This will scan any changes in the latest commit in the local tree. At the time of writing, it will not scan any changes that are not locally committed.

Running include-what-you-use (IWYU) checks

Kudu uses the IWYU tool to keep the set of headers in the C++ source files consistent. For more information on what consistent means, see Why IWYU.

You can run the IWYU checks via cmake using the iwyu target:

$ make iwyu

This will scan any file which is dirty in your working tree, or changed since the last gerrit-integrated upstream change in your git log.

If you want to run against a specific file, or against all files, you can use the iwyu.py script:

$ ./build-support/iwyu.py

See the output of iwyu.py --help for details on various modes of operation.

Building Kudu documentation

Kuduโ€™s documentation is written in asciidoc and lives in the docs subdirectory.

To build the documentation (this is primarily useful if you would like to inspect your changes before submitting them to Gerrit), use the docs target:

$ make docs

This will invoke docs/support/scripts/make_docs.sh, which requires asciidoctor to process the doc sources and produce the HTML documentation, emitted to build/docs. This script requires ruby and gem to be installed on the system path, and will attempt to install asciidoctor and other related dependencies into $HOME/.gems using bundler.

Some of the dependencies require a recent version of Ruby. To build the documentation on a system that comes with an older Ruby version (such as Ruby 2.0 on CentOS 7), it is easiest to use rbenv to install Ruby 2.7.

Warning
As the default values for some configuration options differ between Mac and Linux (e.g. file vs log block manager) and the configuration reference is generated by running the binaries with -help, the documentation MUST NOT be generated on Mac for publishing purposes, only for verification.
Note
Java API docs can only be built on Java 8 due to Javadoc compatibility issues.

Updating the Kudu web site documentation

To update the documentation that is integrated into the Kudu web site, including Java and C++ client API documentation, you may run the following command:

$ ./docs/support/scripts/make_site.sh

This script will use your local Git repository to check out a shallow clone of the 'gh-pages' branch and use make_docs.sh to generate the HTML documentation for the web site. It will also build the Javadoc and Doxygen documentation. These will be placed inside the checked-out web site, along with a tarball containing only the generated documentation (the docs/ and apidocs/ paths on the web site). Everything can be found in the build/site subdirectory.

To build the C++ Client API you need to have Doxygen 1.8.19 or later which is fairly new so you might need to build it from source. To build it on RHEL/CentOS youโ€™ll also need devtoolset as Doxygen uses C++14 since 1.8.17.

You can proceed to commit the changes in the pages repository and send a code review for your changes. In the future, this step may be automated whenever changes are checked into the main Kudu repository.

After making changes to the gh-pages branch, follow the instructions below when you want to deploy those changes to the live web site.

Warning
The site MUST NOT be built on Mac for publishing purposes, only for verification. See the warning in Building Kudu documentation for details.

Deploying changes to the Apache Kudu web site

When the documentation is updated on the gh-pages branch, or when other web site files on that branch are updated, the following procedure can be used to deploy the changes to the official Apache Kudu web site. Committers have permissions to publish changes to the live site.

git checkout gh-pages
git fetch origin
git merge --ff-only origin/gh-pages
./site_tool proof        # Check for broken links (takes a long time to run)
./site_tool publish      # Generate the static HTML for the site.
cd _publish && git push  # Update the live web site.
Note
sometimes, due to glitches with the ASF gitpubsub system, a large commit, such as a change to the docs, will not get mirrored to the live site. Adding an empty commit and doing another git push tends to fix the problem. See the git log for examples of people doing this in the past.

Improving build times

Caching build output

The kudu build is compatible with ccache. Simply install your distroโ€™s ccache package, prepend /usr/lib/ccache to your PATH, and watch your object files get cached. Link times wonโ€™t be affected, but you will see a noticeable improvement in compilation times. You may also want to increase the size of your cache using "ccache -M new_size".

Improving linker speed

One of the major time sinks in the Kudu build is linking. GNU ld is historically quite slow at linking large C++ applications. The alternative linker gold is much better at it. Itโ€™s part of the binutils package in modern distros (try binutils-gold in older ones). To enable it, simply repoint the /usr/bin/ld symlink from ld.bfd to ld.gold.

Note that gold doesnโ€™t handle weak symbol overrides properly (see this bug report for details). As such, it cannot be used with shared objects (see below) because itโ€™ll cause tcmallocโ€™s alternative malloc implementation to be ignored.

Building Kudu with dynamic linking

Kudu can be built into shared objects, which, when used with ccache, can result in a dramatic build time improvement in the steady state. Even after a make clean in the build tree, all object files can be served from ccache. By default, debug and fastdebug will use dynamic linking, while other build types will use static linking. To enable dynamic linking explicitly, run:

$ cmake -DKUDU_LINK=dynamic ../..

Subsequent builds will create shared objects instead of archives and use them when linking the kudu binaries and unit tests. The full range of options for KUDU_LINK are static, dynamic, and auto. The default is auto and only the first letter matters for the purpose of matching.

Note
Static linking is incompatible with TSAN.

Developing Kudu in Eclipse

Eclipse can be used as an IDE for Kudu. To generate Eclipse project files, run:

$ mkdir -p <sibling directory to source tree>
$ cd <sibling directory to source tree>
$ rm -rf CMakeCache.txt CMakeFiles/
$ cmake -G "Eclipse CDT4 - Unix Makefiles" -DCMAKE_CXX_COMPILER_ARG1=-std=c++17 <source tree>

When the Eclipse generator is run in a subdirectory of the source tree, the resulting project is incomplete. Thatโ€™s why itโ€™s recommended to use a directory thatโ€™s a sibling to the source tree. See [1] for more details.

Itโ€™s critical that CMakeCache.txt be removed prior to running the generator, otherwise the extra Eclipse generator logic (the CMakeFindEclipseCDT4.make module) wonโ€™t run and standard system includes will be missing from the generated project.

Thanks to [2], the Eclipse generator ignores the -std=c++17 definition and we must add it manually on the command line via CMAKE_CXX_COMPILER_ARG1.

By default, the Eclipse CDT indexer will index everything under the kudu/ source tree. It tends to choke on certain complicated source files within thirdparty. In CDT 8.7.0, the indexer will generate so many errors that itโ€™ll exit early, causing many spurious syntax errors to be highlighted. In older versions of CDT, itโ€™ll spin forever.

Either way, these complicated source files must be excluded from indexing. To do this, right click on the project in the Project Explorer and select Properties. In the dialog box, select "C/C++ Project Paths", select the Source tab, highlight "Exclusion filter: (None)", and click "Editโ€ฆโ€‹". In the new dialog box, click "Add Multipleโ€ฆโ€‹". Select every subdirectory inside thirdparty except installed. Click OK all the way out and rebuild the project index by right clicking the project in the Project Explorer and selecting Index โ†’ Rebuild.

With this exclusion, the only false positives (shown as "red squigglies") that CDT presents appear to be in atomicops functions (NoBarrier_CompareAndSwap for example).

Another way to approach enormous source code indexing in Ecplise is to get rid of unnecessary source code in "thirdparty/src" directory right after building code and before opening project in Eclipse. You can remove all source code except hadoop, hive and sentry directories. Additionally, if you encounter red squigglies in code editor due to Eclipseโ€™s poor macro discovery, you may need to provide Eclipse with preprocessor macros values, which it could not extract during auto-discovery. Go to "Project Explorer" โ†’ "Properties" โ†’ "C/C General" -> "Preprocessor Include Paths, Macros, etc" -> "Entries" tab -> Language "GNU C" โ†’ Setting Entries "CDT User Setting Entries" โ†’ button "Add" โ†’ choose "Preprocessor Macro" [3]

Another Eclipse annoyance stems from the "[Targets]" linked resource that Eclipse generates for each unit test. These are probably used for building within Eclipse, but one side effect is that nearly every source file appears in the indexer twice: once via a target and once via the raw source file. To fix this, simply delete the [Targets] linked resource via the Project Explorer. Doing this should have no effect on writing code, though it may affect your ability to build from within Eclipse.

Export Control Notice

This distribution uses cryptographic software and may be subject to export controls. Please refer to docs/export_control.adoc for more information.

More Repositories

1

echarts

Apache ECharts is a powerful, interactive charting and data visualization library for browser
TypeScript
56,321
star
2

superset

Apache Superset is a Data Visualization and Data Exploration Platform
TypeScript
55,051
star
3

dubbo

The java implementation of Apache Dubbo. An RPC and microservice framework.
Java
40,333
star
4

spark

Apache Spark - A unified analytics engine for large-scale data processing
Scala
36,719
star
5

airflow

Apache Airflow - A platform to programmatically author, schedule, and monitor workflows
Python
36,241
star
6

kafka

Mirror of Apache Kafka
Java
28,624
star
7

incubator-seata

๐Ÿ”ฅ Seata is an easy-to-use, high-performance, open source distributed transaction solution.
Java
24,602
star
8

skywalking

APM, Application Performance Monitoring System
Java
22,610
star
9

flink

Apache Flink
Java
22,197
star
10

mxnet

Lightweight, Portable, Flexible Distributed/Mobile Deep Learning with Dynamic, Mutation-aware Dataflow Dep Scheduler; for Python, R, Julia, Scala, Go, Javascript and more
C++
20,572
star
11

shardingsphere

Distributed SQL transaction & query engine for data sharding, scaling, encryption, and more - on any database.
Java
19,710
star
12

rocketmq

Apache RocketMQ is a cloud native messaging and streaming platform, making it simple to build event-driven applications.
Java
18,578
star
13

arrow

Apache Arrow is the universal columnar format and multi-language toolbox for fast data interchange and in-memory analytics
C++
14,481
star
14

brpc

brpc is an Industrial-grade RPC framework using C++ Language, which is often used in high performance system such as Search, Storage, Machine learning, Advertisement, Recommendation etc. "brpc" means "better RPC".
C++
14,261
star
15

incubator-weex

Apache Weex (Incubating)
C++
13,884
star
16

hadoop

Apache Hadoop
Java
13,855
star
17

pulsar

Apache Pulsar - distributed pub-sub messaging system
Java
13,062
star
18

druid

Apache Druid: a high performance real-time analytics database.
Java
12,843
star
19

predictionio

PredictionIO, a machine learning server for developers and ML engineers.
Scala
12,556
star
20

doris

Apache Doris is an easy-to-use, high performance and unified analytics database.
Java
12,490
star
21

zookeeper

Apache ZooKeeper
Java
11,532
star
22

incubator-answer

A Q&A platform software for teams at any scales. Whether it's a community forum, help center, or knowledge management platform, you can always count on Apache Answer.
Go
11,487
star
23

apisix

The Cloud-Native API Gateway
Lua
11,031
star
24

thrift

Apache Thrift
C++
9,900
star
25

dolphinscheduler

Apache DolphinScheduler is the modern data workflow orchestration platform with powerful user interface, dedicated to solving complex task dependencies in the data pipeline and providing various types of jobs available `out of the box`
Java
9,619
star
26

cassandra

Mirror of Apache Cassandra
Java
8,187
star
27

shardingsphere-elasticjob

Distributed scheduled job
Java
7,965
star
28

seatunnel

SeaTunnel is a next-generation super high-performance, distributed, massive data integration tool.
Java
7,854
star
29

tvm

Open deep learning compiler stack for cpu, gpu and specialized accelerators
Python
7,828
star
30

beam

Apache Beam is a unified programming model for Batch and Streaming data processing.
Java
7,737
star
31

shenyu

Apache ShenYu is a Java native API Gateway for service proxy, protocol conversion and API governance.
Java
7,541
star
32

jmeter

Apache JMeter open-source load testing tool for analyzing and measuring the performance of a variety of services
Java
7,335
star
33

tomcat

Apache Tomcat
Java
6,926
star
34

storm

Apache Storm
Java
6,480
star
35

iceberg

Apache Iceberg
Java
6,271
star
36

zeppelin

Web-based notebook that enables data-driven, interactive data analytics and collaborative documents with SQL, Scala and more.
Java
6,162
star
37

openwhisk

Apache OpenWhisk is an open source serverless cloud platform
Scala
6,130
star
38

couchdb

Seamless multi-master syncing database with an intuitive HTTP/JSON API, designed for reliability
Erlang
5,810
star
39

iotdb

Apache IoTDB
Java
5,582
star
40

incubator-kie-drools

Drools is a rule engine, DMN engine and complex event processing (CEP) engine for Java.
Java
5,542
star
41

pinot

Apache Pinot - A realtime distributed OLAP datastore
Java
5,430
star
42

dubbo-spring-boot-project

Spring Boot Project for Apache Dubbo
Java
5,355
star
43

mesos

Apache Mesos
Java
5,111
star
44

hive

Apache Hive
Java
5,053
star
45

camel

Apache Camel is an open source integration framework that empowers you to quickly and easily integrate various systems consuming or producing data.
Java
5,042
star
46

groovy

Apache Groovy: A powerful multi-faceted programming language for the JVM platform
Java
4,977
star
47

hbase

Apache HBase
Java
4,971
star
48

incubator-weex-ui

๐Ÿ„ A rich interaction, lightweight, high performance UI library based on Weex.
Vue
4,788
star
49

ignite

Apache Ignite
Java
4,548
star
50

rocketmq-externals

Mirror of Apache RocketMQ (Incubating)
Java
4,474
star
51

incubator-pagespeed-ngx

Automatic PageSpeed optimization module for Nginx
C++
4,381
star
52

lucene-solr

Apache Lucene and Solr open-source search software
4,349
star
53

dubbo-go

Go Implementation For Apache Dubbo
Go
4,315
star
54

shiro

Apache Shiro
Java
4,164
star
55

calcite

Apache Calcite
Java
4,028
star
56

nifi

Apache NiFi
Java
4,006
star
57

maven

Apache Maven core
Java
3,836
star
58

hudi

Upserts, Deletes And Incremental Processing on Big Data.
Java
3,804
star
59

dubbo-admin

The ops and reference implementation for Apache Dubbo
Java
3,707
star
60

incubator-heron

Apache Heron (Incubating) is a realtime, distributed, fault-tolerant stream processing engine from Twitter
Java
3,646
star
61

cordova-android

Apache Cordova Android
JavaScript
3,539
star
62

kylin

Apache Kylin
Java
3,526
star
63

httpd

Mirror of Apache HTTP Server. Issues: http://issues.apache.org
C
3,510
star
64

linkis

Apache Linkis builds a computation middleware layer to facilitate connection, governance and orchestration between the upper applications and the underlying data engines.
Java
3,298
star
65

incubator-kie-optaplanner

AI constraint solver in Java to optimize the vehicle routing problem, employee rostering, task assignment, maintenance scheduling, conference scheduling and other planning problems.
Java
3,152
star
66

logging-log4j2

Apache Log4j 2 is a versatile, feature-rich, efficient logging API and backend for Java.
Java
3,151
star
67

fury

A blazingly fast multi-language serialization framework powered by JIT and zero-copy.
Java
3,000
star
68

arrow-datafusion

Apache Arrow DataFusion SQL Query Engine
Rust
2,998
star
69

curator

Apache Curator
Java
2,997
star
70

singa

a distributed deep learning platform
C++
2,968
star
71

avro

Apache Avro is a data serialization system.
Java
2,872
star
72

incubator-streampark

StreamPark, Make stream processing easier! easy-to-use streaming application development framework and operation platform
Scala
2,820
star
73

nutch

Apache Nutch is an extensible and scalable web crawler
Java
2,653
star
74

netbeans

Apache NetBeans
Java
2,643
star
75

guacamole-server

Mirror of Apache Guacamole Server
C
2,601
star
76

incubator-devlake

Apache DevLake is an open-source dev data platform to ingest, analyze, and visualize the fragmented data from DevOps tools, extracting insights for engineering excellence, developer experience, and community growth.
Go
2,578
star
77

commons-lang

Apache Commons Lang
Java
2,539
star
78

flume

Mirror of Apache Flume
Java
2,458
star
79

geode

Apache Geode
Java
2,244
star
80

gobblin

A distributed data integration framework that simplifies common aspects of big data integration such as data ingestion, replication, organization and lifecycle management for both streaming and batch data ecosystems.
Java
2,209
star
81

incubator-seata-samples

seata-samples
Java
2,196
star
82

maven-mvnd

Apache Maven Daemon
Java
2,191
star
83

activemq

Mirror of Apache ActiveMQ
Java
2,184
star
84

incubator-hugegraph

A graph database that supports more than 100+ billion data, high performance and scalability (Include OLTP Engine & REST-API & Backends)
Java
2,156
star
85

parquet-mr

Apache Parquet
Java
2,153
star
86

kvrocks

Kvrocks is a distributed key value NoSQL database that uses RocksDB as storage engine and is compatible with Redis protocol.
C++
2,147
star
87

pdfbox

Mirror of Apache PDFBox
Java
2,131
star
88

cordova-ios

Apache Cordova iOS
JavaScript
2,130
star
89

mahout

Mirror of Apache Mahout
Java
2,095
star
90

lucenenet

Apache Lucene.NET
C#
2,031
star
91

ambari

Apache Ambari simplifies provisioning, managing, and monitoring of Apache Hadoop clusters.
Java
1,990
star
92

incubator-pegasus

Apache Pegasus - A horizontally scalable, strongly consistent and high-performance key-value store
C++
1,962
star
93

libcloud

Apache Libcloud is a Python library which hides differences between different cloud provider APIs and allows you to manage different cloud resources through a unified and easy to use API.
Python
1,956
star
94

cloudstack

Apache CloudStack is an opensource Infrastructure as a Service (IaaS) cloud computing platform
Java
1,945
star
95

tika

The Apache Tika toolkit detects and extracts metadata and text from over a thousand different file types (such as PPT, XLS, and PDF).
Java
1,860
star
96

drill

Apache Drill is a distributed MPP query layer for self describing data
Java
1,841
star
97

dubbo-samples

samples for Apache Dubbo
Java
1,839
star
98

servicecomb-java-chassis

ServiceComb Java Chassis is a Software Development Kit (SDK) for rapid development of microservices in Java, providing service registration, service discovery, dynamic routing, and service management features
Java
1,829
star
99

tinkerpop

Apache TinkerPop - a graph computing framework
Java
1,825
star
100

trafficserver

Apache Traffic Serverโ„ข is a fast, scalable and extensible HTTP/1.1 and HTTP/2 compliant caching proxy server.
C++
1,804
star