summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Steinhardt <ps@pks.im>2017-04-21 07:31:56 +0000
committerPatrick Steinhardt <ps@pks.im>2017-04-28 14:05:45 +0200
commit35079f507b5287a2a4726cae7753439f753453e2 (patch)
tree65ead793083b46ad4a813d1b488a6f01af451c87
parent28a0741f1ae6f5e1261c8e73854dda69e7a61067 (diff)
downloadlibgit2-35079f507b5287a2a4726cae7753439f753453e2.tar.gz
odb: add option to turn off hash verification
Verifying hashsums of objects we are reading from the ODB may be costly as we have to perform an additional hashsum calculation on the object. Especially when reading large objects, the penalty can be as high as 35%, as can be seen when executing the equivalent of `git cat-file` with and without verification enabled. To mitigate for this, we add a global option for libgit2 which enables the developer to turn off the verification, e.g. when he can be reasonably sure that the objects on disk won't be corrupted.
-rw-r--r--include/git2/common.h8
-rw-r--r--src/odb.c14
-rw-r--r--src/odb.h2
-rw-r--r--src/settings.c5
-rw-r--r--tests/object/lookup.c5
5 files changed, 29 insertions, 5 deletions
diff --git a/include/git2/common.h b/include/git2/common.h
index 6d2092028..d83e8c3a0 100644
--- a/include/git2/common.h
+++ b/include/git2/common.h
@@ -182,6 +182,7 @@ typedef enum {
GIT_OPT_ENABLE_SYNCHRONOUS_OBJECT_CREATION,
GIT_OPT_GET_WINDOWS_SHAREMODE,
GIT_OPT_SET_WINDOWS_SHAREMODE,
+ GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION,
} git_libgit2_opt_t;
/**
@@ -337,6 +338,13 @@ typedef enum {
* > is written to permanent storage, not simply cached. This
* > defaults to disabled.
*
+ * opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, int enabled)
+ *
+ * > Enable strict verification of object hashsums when reading
+ * > objects from disk. This may impact performance due to an
+ * > additional checksum calculation on each object. This defaults
+ * > to enabled.
+ *
* @param option Option key
* @param ... value to set the option
* @return 0 on success, <0 on failure
diff --git a/src/odb.c b/src/odb.c
index 0efa23417..157a3808e 100644
--- a/src/odb.c
+++ b/src/odb.c
@@ -31,6 +31,8 @@
#define GIT_ALTERNATES_MAX_DEPTH 5
+bool git_odb__strict_hash_verification = true;
+
typedef struct
{
git_odb_backend *backend;
@@ -1027,12 +1029,14 @@ static int odb_read_1(git_odb_object **out, git_odb *db, const git_oid *id,
if (!found)
return GIT_ENOTFOUND;
- if ((error = git_odb_hash(&hashed, raw.data, raw.len, raw.type)) < 0)
- goto out;
+ if (git_odb__strict_hash_verification) {
+ if ((error = git_odb_hash(&hashed, raw.data, raw.len, raw.type)) < 0)
+ goto out;
- if (!git_oid_equal(id, &hashed)) {
- error = git_odb__error_mismatch(id, &hashed);
- goto out;
+ if (!git_oid_equal(id, &hashed)) {
+ error = git_odb__error_mismatch(id, &hashed);
+ goto out;
+ }
}
giterr_clear();
diff --git a/src/odb.h b/src/odb.h
index 78c7b0339..61d687abf 100644
--- a/src/odb.h
+++ b/src/odb.h
@@ -20,6 +20,8 @@
#define GIT_OBJECT_DIR_MODE 0777
#define GIT_OBJECT_FILE_MODE 0444
+extern bool git_odb__strict_hash_verification;
+
/* DO NOT EXPORT */
typedef struct {
void *data; /**< Raw, decompressed object data. */
diff --git a/src/settings.c b/src/settings.c
index 07ac16a8f..169fcd51c 100644
--- a/src/settings.c
+++ b/src/settings.c
@@ -15,6 +15,7 @@
#include "cache.h"
#include "global.h"
#include "object.h"
+#include "odb.h"
#include "refs.h"
#include "transports/smart.h"
@@ -243,6 +244,10 @@ int git_libgit2_opts(int key, ...)
#endif
break;
+ case GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION:
+ git_odb__strict_hash_verification = (va_arg(ap, int) != 0);
+ break;
+
default:
giterr_set(GITERR_INVALID, "invalid option key");
error = -1;
diff --git a/tests/object/lookup.c b/tests/object/lookup.c
index ed12f917a..277e2e0c0 100644
--- a/tests/object/lookup.c
+++ b/tests/object/lookup.c
@@ -111,6 +111,11 @@ void test_object_lookup__lookup_object_with_wrong_hash_returns_error(void)
/* Verify that lookup fails due to a hashsum mismatch */
cl_git_fail_with(GIT_EMISMATCH, git_object_lookup(&object, g_repo, &oid, GIT_OBJ_COMMIT));
+ /* Disable verification and try again */
+ cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 0));
+ cl_git_pass(git_object_lookup(&object, g_repo, &oid, GIT_OBJ_COMMIT));
+ cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 1));
+
git_buf_free(&oldpath);
git_buf_free(&newpath);
}