diff options
author | Spencer Jackson <spencer.jackson@mongodb.com> | 2019-02-07 14:24:58 -0500 |
---|---|---|
committer | Spencer Jackson <spencer.jackson@mongodb.com> | 2019-04-01 15:23:53 -0400 |
commit | bfec2c3a4398477688a0fcffca35b838e1483a3b (patch) | |
tree | cf4e171f45be3bbb0a98d134daaa3b8ad50fc575 | |
parent | 029336d07dd89eee17cfa090ca0b63f44883b485 (diff) | |
download | mongo-bfec2c3a4398477688a0fcffca35b838e1483a3b.tar.gz |
SERVER-38945: Cache OpenSSL error states to elide error clearing
(cherry picked from commit 9245a51842f1f8b9da42cadf27627642c4d94fd4)
-rw-r--r-- | src/mongo/util/net/ssl/detail/engine_openssl.hpp | 2 | ||||
-rw-r--r-- | src/mongo/util/net/ssl/detail/impl/engine_openssl.ipp | 20 |
2 files changed, 21 insertions, 1 deletions
diff --git a/src/mongo/util/net/ssl/detail/engine_openssl.hpp b/src/mongo/util/net/ssl/detail/engine_openssl.hpp index 5a98fe6c7a7..6f0f4afc54b 100644 --- a/src/mongo/util/net/ssl/detail/engine_openssl.hpp +++ b/src/mongo/util/net/ssl/detail/engine_openssl.hpp @@ -99,6 +99,8 @@ private: ASIO_DECL static asio::detail::static_mutex& accept_mutex(); #endif // (OPENSSL_VERSION_NUMBER < 0x10000000L) + ASIO_DECL void purge_error_state(); + // Perform one operation. Returns >= 0 on success or error, want_read if the // operation needs more input, or want_write if it needs to write some output // before the operation can complete. diff --git a/src/mongo/util/net/ssl/detail/impl/engine_openssl.ipp b/src/mongo/util/net/ssl/detail/impl/engine_openssl.ipp index 92594883d75..01de79294b2 100644 --- a/src/mongo/util/net/ssl/detail/impl/engine_openssl.ipp +++ b/src/mongo/util/net/ssl/detail/impl/engine_openssl.ipp @@ -144,13 +144,31 @@ asio::detail::static_mutex& engine::accept_mutex() { } #endif // (OPENSSL_VERSION_NUMBER < 0x10000000L) + +void engine::purge_error_state() { +#if (OPENSSL_VERSION_NUMBER < 0x1010000fL) + // OpenSSL 1.1.0 introduced a thread local state storage mechanism. + // Versions prior sometimes had contention issues on global mutexes + // which protected thread local state. + // If we are compiled against a version without native thread local + // support, cache a pointer to this thread's error state, which we can + // access without contention. If that state requires no cleanup, + // we can avoid invoking OpenSSL's more expensive machinery. + const static thread_local ERR_STATE* es = ERR_get_state(); + if (es->bottom == es->top) { + return; + } +#endif // (OPENSSL_VERSION_NUMBER < 0x1010000fL) + ::ERR_clear_error(); +} + engine::want engine::perform(int (engine::*op)(void*, std::size_t), void* data, std::size_t length, asio::error_code& ec, std::size_t* bytes_transferred) { std::size_t pending_output_before = ::BIO_ctrl_pending(ext_bio_); - ::ERR_clear_error(); + purge_error_state(); int result = (this->*op)(data, length); int ssl_error = ::SSL_get_error(ssl_, result); int sys_error = static_cast<int>(::ERR_get_error()); |