Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

libevent-based http server #2176

Merged
merged 41 commits into from
Mar 25, 2017
Merged

libevent-based http server #2176

merged 41 commits into from
Mar 25, 2017

Conversation

@str4d str4d added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. A-rpc-interface Area: RPC interface C-upstream-port Category: Changes that are ported from the Bitcoin Core codebase. labels Mar 14, 2017
@str4d str4d added this to the 1.0.8 milestone Mar 14, 2017
@str4d
Copy link
Contributor Author

str4d commented Mar 14, 2017

Based on #2175, merge that first.

@daira
Copy link
Contributor

daira commented Mar 15, 2017

How sure are we that this resolves #1680?

@bitcartel
Copy link
Contributor

@daira I have a python script which makes zillions of rpc requests. I used it to debug #1680. Can modify to test behaviour under load and with keep-alive option enabled.

@bitcartel
Copy link
Contributor

bitcartel commented Mar 22, 2017

@str4d Just checking, allmention/trace of rpckeepalive has been removed? Are there libevent improvements to backport?

@daira So from empirical testing with local scripts which make repeated calls to the RPC interface, this libevent based server appears faster, but the python scripts will report error: [Errno 99] Cannot assign requested address under load, whereas 1.0.7 currently doesn't do that.

I'm fine with merging this.

@str4d
Copy link
Contributor Author

str4d commented Mar 22, 2017

@bitcartel wrote:

@str4d Just checking, allmention/trace of rpckeepalive has been removed?

Yes.

Are there libevent improvements to backport?

Ooh, yes I have now spotted a couple of additional PRs. I will add them to this PR.

@str4d str4d force-pushed the 1593-libevent branch 3 times, most recently from a93d092 to 5779978 Compare March 22, 2017 20:47
@str4d
Copy link
Contributor Author

str4d commented Mar 22, 2017

@bitcartel it expanded from a "couple" of PRs 😅 Most of the additional PRs are trivial, but we can always split off a few into 1.0.9 if necessary.

@str4d
Copy link
Contributor Author

str4d commented Mar 22, 2017

@zkbot try

@zkbot
Copy link
Contributor

zkbot commented Mar 22, 2017

⌛ Trying commit 1d3aa37 with merge b0afc4b...

@zkbot
Copy link
Contributor

zkbot commented Mar 22, 2017

☀️ Test successful - zcash

str4d and others added 12 commits March 24, 2017 09:03
This option was a temporary workaround, and is no longer necessary
with the new web server.
Dropping all use of boost::asio.
Sending a request body with GET request is not valid in HTTP spec, and
not compatible with evhttpd.
- *Replace usage of boost::asio with [libevent2](http://libevent.org/)*.
boost::asio is not part of C++11, so unlike other boost there is no
forwards-compatibility reason to stick with it. Together with zcash#4738 (convert
json_spirit to UniValue), this rids Bitcoin Core of the worst offenders with
regard to compile-time slowness.

- *Replace spit-and-duct-tape http server with evhttp*. Front-end http handling
is handled by libevent, a work queue (with configurable depth and parallelism)
is used to handle application requests.

- *Wrap HTTP request in C++ class*; this makes the application code mostly
HTTP-server-neutral

- *Refactor RPC to move all http-specific code to a separate file*.
Theoreticaly this can allow building without HTTP server but with another RPC
backend, e.g. Qt's debug console (currently not implemented) or future RPC
mechanisms people may want to use.

- *HTTP dispatch mechanism*; services (e.g., RPC, REST) register which URL
paths they want to handle.

By using a proven, high-performance asynchronous networking library (also used
by Tor) and HTTP server, problems such as zcash#5674, zcash#5655, zcash#344 should be avoided.

What works? bitcoind, bitcoin-cli, bitcoin-qt. Unit tests and RPC/REST tests
pass. The aim for now is everything but SSL support.

Configuration options:

- `-rpcthreads`: repurposed as "number of  work handler threads". Still
defaults to 4.

- `-rpcworkqueue`: maximum depth of work queue. When this is reached, new
requests will return a 500 Internal Error.

- `-rpctimeout`: inactivity time, in seconds, after which to disconnect a
client.

- `-debug=http`: low-level http activity logging
Implement RPCTimerHandler for Qt RPC console, so that `walletpassphrase`
works with GUI and `-server=0`.

Also simplify HTTPEvent-related code by using boost::function directly.

Zcash: QT changes ommitted
…entBase()

Split StartHTTPServer into InitHTTPServer and StartHTTPServer to give
clients a window to register their handlers without race conditions.

Thanks @ajweiss for figuring this out.
Make it possible to reuse sockets.
This is necessary to make the RPC tests work in WINE.
@str4d
Copy link
Contributor Author

str4d commented Mar 23, 2017

Rebased on master. This PR now only contains the libevent commits, but annoyingly GitHub now shows them in date order instead of branch order...

Copy link
Contributor

@daira daira left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please respond to comments.

if [ "x${EXEEXT}" = "x.exe" ]; then
echo "Win tests currently disabled"
exit 0
fi
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh. I'd prefer to let them fail on Windows than disable them. Was there any other upstream PR to fix them for Windows?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, they are still disabled by default upstream, and bitcoin/bitcoin#5677 (comment) is referenced as the reason for disabling. In upstream's migration of this script from Bash to Python (bitcoin/bitcoin#6616), an override flag was added, so we will gain that as well once I pull that in.

Copy link
Contributor

@daira daira Mar 25, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yuck. I don't want to hide the fact that these tests are failing on Windows. Please revert the disabling.

self.__conn.request(method, path, postdata, headers)
return self._get_response()
except httplib.BadStatusLine as e:
if e.line == "''": # if connection was closed, try again
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having read https://bugs.python.org/issue356 , I'm not sure this will actually work in Python 3.5+, because that will throw a ConnectionResetError which, while it does inherit from BadStatusLine, does not necessarily have e.line == "''".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like we also want bitcoin/bitcoin#8139 and bitcoin/bitcoin#8839.

Copy link
Contributor

@daira daira Mar 25, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm feeling quite smug about spotting that it wouldn't work just from reading the Python issue :-) 👍 on including those PRs.

$(LIBZCASH) \
$(LIBBITCOIN_CRYPTO) \
$(LIBZCASH_LIBS)

# bitcoin-cli binary #
zcash_cli_SOURCES = bitcoin-cli.cpp
zcash_cli_CPPFLAGS = $(BITCOIN_INCLUDES)
zcash_cli_CPPFLAGS = $(BITCOIN_INCLUDES) $(EVENT_CFLAGS)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not also $(EVENT_PTHREADS_CFLAGS)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked with upstream, and they don't have $(EVENT_PTHREADS_CFLAGS) in current master, so unlikely I made a mistake while cherry-picking. I wouldn't expect it to be necessary anyway, as the threading side should only be needed in zcashd.

const char *http_errorstring(int code)
{
switch(code) {
#if LIBEVENT_VERSION_NUMBER >= 0x02010300
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We know the version is always at least this, so the conditional compilation is unnecessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK; I'd like to address this in a separate PR so we can also send it upstream.

}
}

#if LIBEVENT_VERSION_NUMBER >= 0x02010300
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The conditional compilation is unnecessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

#ifndef EVENT_LOG_WARN
// EVENT_LOG_WARN was added in 2.0.19; but before then _EVENT_LOG_WARN existed.
# define EVENT_LOG_WARN _EVENT_LOG_WARN
#endif
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The conditional block is unnecessary; we should always be using libevent >= 2.0.19.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


// Redirect libevent's logging to our own log
event_set_log_callback(&libevent_log_cb);
#if LIBEVENT_VERSION_NUMBER >= 0x02010100
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Conditional compilation unnecessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

break;
if (i != iend)
{
LogPrint("http", "Unregistering HTTP handler for %s (exactmath %d)\n", prefix, exactMatch);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: s/exactmath/exactmatch/

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll pull in bitcoin/bitcoin#6640.

* nStatus is the HTTP status code to send.
* strReply is the body of the reply. Keep it empty to send a standard message.
*
* @note Can be called only once. As this will give the request back to the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This really calls out for session types. Oh well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a ticket we can open, or is this a missing language feature?

Copy link
Contributor

@daira daira Mar 25, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing language feature. I was just griping about C++'s inexpressiveness.

src/rpcserver.h Outdated
* RPC will call the function to create a timer that will call func in *millis* milliseconds.
* @note As the RPC mechanism is backend-neutral, it can use different implementations of timers.
* This is needed to cope with the case in which there is no HTTP server, but
* only GUI RPC console, and to break the dependency of pcserver on httprpc.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: s/pcserver/rpcserver/

@str4d
Copy link
Contributor Author

str4d commented Mar 24, 2017

@daira comments responded to, and mostly addressed (just waiting on #2176 (comment) and #2176 (comment)).

@daira
Copy link
Contributor

daira commented Mar 25, 2017

Please revert the disabling of RPC tests on Windows, and fix the "pcserver" typo. Otherwise utACK.

@ebfull
Copy link
Contributor

ebfull commented Mar 25, 2017

This is a fantastic cherry-pick, I'm ACK. Nice and clean.

@bitcartel
Copy link
Contributor

ACK @zkbot r+

@zkbot
Copy link
Contributor

zkbot commented Mar 25, 2017

📌 Commit 3da13e8 has been approved by bitcartel

@zkbot
Copy link
Contributor

zkbot commented Mar 25, 2017

⌛ Testing commit 3da13e8 with merge f9f4866...

@zkbot
Copy link
Contributor

zkbot commented Mar 25, 2017

☀️ Test successful - zcash

@zkbot zkbot merged commit 3da13e8 into zcash:master Mar 25, 2017
@str4d str4d deleted the 1593-libevent branch March 25, 2017 07:16
@str4d str4d mentioned this pull request Mar 25, 2017
@daira
Copy link
Contributor

daira commented Mar 25, 2017

Post-hoc utACK for the last three commits.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-rpc-interface Area: RPC interface C-upstream-port Category: Changes that are ported from the Bitcoin Core codebase. S-waiting-on-review Status: Awaiting review from the assignee but also interested parties.
Projects
None yet
Development

Successfully merging this pull request may close these issues.