Skip to content

Commit e7b6afb

Browse files
committed
Add OpenSSL backend for checksum computation.
After this change, every component that relies on checksuming would improve in performance by a lot in thanks to OpenSSL optimised hash algorithms. My benchmarks showed the following improvements: - The benchmarking test was showing 0.16 GB/s raw speed with APR backend and 1.38 seconds GB/s with OpenSSL. All of those are SHA1. This is 8.62 times jump! - Status of a working copy with a single file (with size of 370 MB) simply touched was taking 1.94 seconds of real time to execute with APR backend and 0.30 seconds with OpenSSL (6.46 times improvement). - The same test with a file of around 3 GB had a jump from 15.73 seconds to 2.23 seconds (7.05 times improvement). - Checkout of the whole repository with those two files over file:// protocol took 40 seconds with APR and 20 seconds with OpenSSL (2 times improvement). Currenly, only CMake build system implements support for this feature. As far as I checked, it should not at least break other build systems, but I didn't implement support for them either. This implementation relies on deprecated API of OpenSSL which (I think) is objectively better than the approach they currenly consider recommended (which is to use EVP interface). 1) it's just simpler 2) doesn't perform vtable calls 3) and OpenSSL uses it anyway in EVP (personally, i don't get the reason why it was deprecated in the first place) This is a completelly optional feature which is disabled by default. If one doesn't want to use it, we wont force you to. There are many disadvantages of loading such heavy libraries when we don't need all the stuff it gives us. This optimisation comes with its own cost. But, our client already loads OpenSSL indirectly through libserf so this is not an issue in some cases. Let's just try it. Why not? * CMakeLists.txt (options): Add SVN_CHECKSUM_USE_OPENSSL. (SVN_CHECKSUM_USE_OPENSSL): Check for option to decide whether to look for the OpenSSL library and setup definitions or not. (configsummary): Log value of SVN_CHECKSUM_USE_OPENSSL. * build.conf (libsvn_subr): Add dependency on openssl. * subversion/libsvn_subr/checksum_apr.c (): Put the whole file into an ifndef condition depending on SVN_CHECKSUM_USE_OPENSSL. * subversion/libsvn_subr/checksum_openssl.c (svn_checksum__md5, svn_checksum__md5_ctx_t, svn_checksum__md5_ctx_create, svn_checksum__md5_ctx_reset, svn_checksum__md5_ctx_update, svn_checksum__md5_ctx_final, svn_checksum__sha1, svn_checksum__sha1_ctx_t, svn_checksum__sha1_ctx_create, svn_checksum__sha1_ctx_reset, svn_checksum__sha1_ctx_update, svn_checksum__sha1_ctx_final): Implement through OpenSSL (under an ifdef). git-svn-id: https://svn.apache.org/repos/asf/subversion/trunk@1930949 13f79535-47bb-0310-9956-ffa450edef68
1 parent f73ee44 commit e7b6afb

File tree

4 files changed

+176
-1
lines changed

4 files changed

+176
-1
lines changed

CMakeLists.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ cmake_dependent_option(SVN_BUILD_SHARED_RA "Build shared RA modules" ON "BUILD_S
111111
option(SVN_DEBUG "Enables specific features for developer builds" OFF)
112112
cmake_dependent_option(SVN_USE_WIN32_CRASHHANDLER "Enables WIN32 crash handler." ON "WIN32" OFF)
113113
option(SVN_USE_DSO "Defined if svn should try to load DSOs" OFF)
114+
option(SVN_CHECKSUM_USE_OPENSSL "Defined if svn should use OpenSSL to compute checksums." OFF)
114115
set(SVN_SOVERSION "0" CACHE STRING "Subversion library ABI version")
115116
mark_as_advanced(SVN_SOVERSION)
116117

@@ -383,6 +384,17 @@ if (SVN_ENABLE_RA_SERF)
383384
endif()
384385
endif()
385386

387+
if (SVN_CHECKSUM_USE_OPENSSL)
388+
find_package(OpenSSL REQUIRED)
389+
add_library(external-openssl ALIAS OpenSSL::Crypto)
390+
add_private_config_definition(
391+
"Defined if svn should use OpenSSL to compute checksums."
392+
"SVN_CHECKSUM_USE_OPENSSL" "1"
393+
)
394+
else()
395+
add_library(external-openssl INTERFACE)
396+
endif()
397+
386398
### Python
387399

388400
if(SVN_ENABLE_SWIG_PYTHON)
@@ -952,6 +964,7 @@ message(STATUS " Build shared libraries ........ : ${BUILD_SHARED_LIBS}")
952964
message(STATUS " Build shared FS Modues ........ : ${SVN_BUILD_SHARED_FS}")
953965
message(STATUS " Build shared RA Modues ........ : ${SVN_BUILD_SHARED_RA}")
954966
message(STATUS " Use pkg-config dependencies ... : ${SVN_USE_PKG_CONFIG}")
967+
message(STATUS " Use OpenSSL for checksum ...... : ${SVN_CHECKSUM_USE_OPENSSL}")
955968
message(STATUS " FS modules:")
956969
message(STATUS " Enable FSFS ................... : ${SVN_ENABLE_FS_FS}")
957970
message(STATUS " Enable FSX .................... : ${SVN_ENABLE_FS_X}")

build.conf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ install = fsmod-lib
394394
path = subversion/libsvn_subr
395395
sources = *.c lz4/*.c
396396
libs = aprutil apriconv apr xml zlib apr_memcache
397-
sqlite magic intl lz4 utf8proc macos-plist macos-keychain
397+
sqlite magic intl lz4 utf8proc macos-plist macos-keychain openssl
398398
msvc-libs = kernel32.lib advapi32.lib shfolder.lib ole32.lib
399399
crypt32.lib version.lib ws2_32.lib
400400
msvc-export =

subversion/libsvn_subr/checksum_apr.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
*/
2323

2424
#include "svn_private_config.h"
25+
#ifndef SVN_CHECKSUM_USE_OPENSSL
2526

2627
#define APR_WANT_BYTEFUNC
2728

@@ -130,3 +131,5 @@ svn_checksum__sha1_ctx_final(unsigned char *digest,
130131
return SVN_NO_ERROR;
131132
}
132133

134+
#endif /* SVN_CHECKSUM_USE_OPENSSL */
135+
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
/*
2+
* checksum_openssl.c: OpenSSL backed checksums
3+
*
4+
* ====================================================================
5+
* Licensed to the Apache Software Foundation (ASF) under one
6+
* or more contributor license agreements. See the NOTICE file
7+
* distributed with this work for additional information
8+
* regarding copyright ownership. The ASF licenses this file
9+
* to you under the Apache License, Version 2.0 (the
10+
* "License"); you may not use this file except in compliance
11+
* with the License. You may obtain a copy of the License at
12+
*
13+
* http://www.apache.org/licenses/LICENSE-2.0
14+
*
15+
* Unless required by applicable law or agreed to in writing,
16+
* software distributed under the License is distributed on an
17+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18+
* KIND, either express or implied. See the License for the
19+
* specific language governing permissions and limitations
20+
* under the License.
21+
* ====================================================================
22+
*/
23+
24+
#include "svn_private_config.h"
25+
#ifdef SVN_CHECKSUM_USE_OPENSSL
26+
27+
#define APR_WANT_BYTEFUNC
28+
29+
#include <apr_md5.h>
30+
#include <apr_sha1.h>
31+
32+
#include "svn_error.h"
33+
#include "checksum.h"
34+
35+
/* There is an alternative way to compute checksums in OpenSSL which is to use
36+
* their EVP interface. Here are the arguments why we are sticking with this
37+
* one even though it's deprecated in OpenSSL v3.0:
38+
*
39+
* - EVP provides much more complicated interface.
40+
*
41+
* - We don't need the most of the features it gives us.
42+
*
43+
* - It might affect performance because there are vtable calls involved.
44+
*
45+
* - The default implementation used in EVP actually relies the exact same set
46+
* of functions under the hood.
47+
*/
48+
49+
#define OPENSSL_SUPPRESS_DEPRECATED
50+
#include <openssl/sha.h>
51+
#include <openssl/md5.h>
52+
53+
54+
/*** MD5 checksum ***/
55+
svn_error_t *
56+
svn_checksum__md5(unsigned char *digest,
57+
const void *data,
58+
apr_size_t len)
59+
{
60+
MD5_CTX ctx;
61+
62+
MD5_Init(&ctx);
63+
MD5_Update(&ctx, data, len);
64+
MD5_Final(digest, &ctx);
65+
66+
return SVN_NO_ERROR;
67+
}
68+
69+
svn_checksum__md5_ctx_t *
70+
svn_checksum__md5_ctx_create(apr_pool_t *pool)
71+
{
72+
MD5_CTX *result = apr_palloc(pool, sizeof(*result));
73+
MD5_Init(result);
74+
return (svn_checksum__md5_ctx_t *)result;
75+
}
76+
77+
svn_error_t *
78+
svn_checksum__md5_ctx_reset(svn_checksum__md5_ctx_t *ctx)
79+
{
80+
MD5_CTX *md5_ctx = (MD5_CTX *)ctx;
81+
memset(md5_ctx, 0, sizeof(*md5_ctx));
82+
MD5_Init(md5_ctx);
83+
return SVN_NO_ERROR;
84+
}
85+
86+
svn_error_t *
87+
svn_checksum__md5_ctx_update(svn_checksum__md5_ctx_t *ctx,
88+
const void *data,
89+
apr_size_t len)
90+
{
91+
MD5_CTX *md5_ctx = (MD5_CTX *)ctx;
92+
MD5_Update(md5_ctx, data, len);
93+
return SVN_NO_ERROR;
94+
}
95+
96+
svn_error_t *
97+
svn_checksum__md5_ctx_final(unsigned char *digest,
98+
const svn_checksum__md5_ctx_t *ctx)
99+
{
100+
MD5_CTX *md5_ctx = (MD5_CTX *)ctx;
101+
MD5_Final(digest, md5_ctx);
102+
return SVN_NO_ERROR;
103+
}
104+
105+
106+
/*** SHA1 checksum ***/
107+
svn_error_t *
108+
svn_checksum__sha1(unsigned char *digest,
109+
const void *data,
110+
apr_size_t len)
111+
{
112+
SHA_CTX ctx;
113+
114+
SHA1_Init(&ctx);
115+
SHA1_Update(&ctx, data, len);
116+
SHA1_Final(digest, &ctx);
117+
118+
return SVN_NO_ERROR;
119+
}
120+
121+
svn_checksum__sha1_ctx_t *
122+
svn_checksum__sha1_ctx_create(apr_pool_t *pool)
123+
{
124+
SHA_CTX *result = apr_palloc(pool, sizeof(*result));
125+
SHA1_Init(result);
126+
return (svn_checksum__sha1_ctx_t *)result;
127+
}
128+
129+
svn_error_t *
130+
svn_checksum__sha1_ctx_reset(svn_checksum__sha1_ctx_t *ctx)
131+
{
132+
SHA_CTX *sha_ctx = (SHA_CTX *)ctx;
133+
memset(sha_ctx, 0, sizeof(*sha_ctx));
134+
SHA1_Init(sha_ctx);
135+
return SVN_NO_ERROR;
136+
}
137+
138+
svn_error_t *
139+
svn_checksum__sha1_ctx_update(svn_checksum__sha1_ctx_t *ctx,
140+
const void *data,
141+
apr_size_t len)
142+
{
143+
SHA_CTX *sha_ctx = (SHA_CTX *)ctx;
144+
SHA1_Update(sha_ctx, data, len);
145+
return SVN_NO_ERROR;
146+
}
147+
148+
svn_error_t *
149+
svn_checksum__sha1_ctx_final(unsigned char *digest,
150+
const svn_checksum__sha1_ctx_t *ctx)
151+
{
152+
153+
SHA_CTX *sha_ctx = (SHA_CTX *)ctx;
154+
SHA1_Final(digest, sha_ctx);
155+
return SVN_NO_ERROR;
156+
}
157+
158+
#endif /* SVN_CHECKSUM_USE_OPENSSL */
159+

0 commit comments

Comments
 (0)