Commit 45dc219f by Edward Thomson Committed by GitHub

Merge pull request #3921 from libgit2/cmn/walk-limit-enough

Improve revision walk preparation logic
parents d11fcf86 fedc05c8
...@@ -15,6 +15,8 @@ v0.24 + 1 ...@@ -15,6 +15,8 @@ v0.24 + 1
* Support for reading and writing git index v4 files * Support for reading and writing git index v4 files
* Improve the performance of the revwalk and bring us closer to git's code.
### API additions ### API additions
* You can now get the user-agent used by libgit2 using the * You can now get the user-agent used by libgit2 using the
......
...@@ -25,17 +25,15 @@ GIT_BEGIN_DECL ...@@ -25,17 +25,15 @@ GIT_BEGIN_DECL
*/ */
typedef enum { typedef enum {
/** /**
* Sort the repository contents in no particular ordering; * Sort the output with the same default time-order method from git.
* this sorting is arbitrary, implementation-specific
* and subject to change at any time.
* This is the default sorting for new walkers. * This is the default sorting for new walkers.
*/ */
GIT_SORT_NONE = 0, GIT_SORT_NONE = 0,
/** /**
* Sort the repository contents in topological order * Sort the repository contents in topological order (parents before
* (parents before children); this sorting mode * children); this sorting mode can be combined with time sorting to
* can be combined with time sorting. * produce git's "time-order".
*/ */
GIT_SORT_TOPOLOGICAL = 1 << 0, GIT_SORT_TOPOLOGICAL = 1 << 0,
......
...@@ -13,10 +13,15 @@ ...@@ -13,10 +13,15 @@
int git_commit_list_time_cmp(const void *a, const void *b) int git_commit_list_time_cmp(const void *a, const void *b)
{ {
const git_commit_list_node *commit_a = a; int64_t time_a = ((git_commit_list_node *) a)->time;
const git_commit_list_node *commit_b = b; int64_t time_b = ((git_commit_list_node *) b)->time;
return (commit_a->time < commit_b->time); if (time_a < time_b)
return 1;
if (time_a > time_b)
return -1;
return 0;
} }
git_commit_list *git_commit_list_insert(git_commit_list_node *item, git_commit_list **list_p) git_commit_list *git_commit_list_insert(git_commit_list_node *item, git_commit_list **list_p)
......
...@@ -28,6 +28,7 @@ typedef struct git_commit_list_node { ...@@ -28,6 +28,7 @@ typedef struct git_commit_list_node {
uninteresting:1, uninteresting:1,
topo_delay:1, topo_delay:1,
parsed:1, parsed:1,
added:1,
flags : FLAG_BITS; flags : FLAG_BITS;
unsigned short in_degree; unsigned short in_degree;
......
...@@ -93,7 +93,7 @@ int git_pqueue_insert(git_pqueue *pq, void *item) ...@@ -93,7 +93,7 @@ int git_pqueue_insert(git_pqueue *pq, void *item)
(void)git_pqueue_pop(pq); (void)git_pqueue_pop(pq);
} }
if (!(error = git_vector_insert(pq, item))) if (!(error = git_vector_insert(pq, item)) && pq->_cmp)
pqueue_up(pq, pq->length - 1); pqueue_up(pq, pq->length - 1);
return error; return error;
...@@ -101,9 +101,15 @@ int git_pqueue_insert(git_pqueue *pq, void *item) ...@@ -101,9 +101,15 @@ int git_pqueue_insert(git_pqueue *pq, void *item)
void *git_pqueue_pop(git_pqueue *pq) void *git_pqueue_pop(git_pqueue *pq)
{ {
void *rval = git_pqueue_get(pq, 0); void *rval;
if (git_pqueue_size(pq) > 1) { if (!pq->_cmp) {
rval = git_vector_last(pq);
} else {
rval = git_pqueue_get(pq, 0);
}
if (git_pqueue_size(pq) > 1 && pq->_cmp) {
/* move last item to top of heap, shrink, and push item down */ /* move last item to top of heap, shrink, and push item down */
pq->contents[0] = git_vector_last(pq); pq->contents[0] = git_vector_last(pq);
git_vector_pop(pq); git_vector_pop(pq);
......
...@@ -35,6 +35,7 @@ extern int git_pqueue_init( ...@@ -35,6 +35,7 @@ extern int git_pqueue_init(
#define git_pqueue_clear git_vector_clear #define git_pqueue_clear git_vector_clear
#define git_pqueue_size git_vector_length #define git_pqueue_size git_vector_length
#define git_pqueue_get git_vector_get #define git_pqueue_get git_vector_get
#define git_pqueue_reverse git_vector_reverse
/** /**
* Insert a new item into the queue * Insert a new item into the queue
......
...@@ -586,7 +586,7 @@ static int rebase_init_operations( ...@@ -586,7 +586,7 @@ static int rebase_init_operations(
(error = git_revwalk_hide(revwalk, git_annotated_commit_id(upstream))) < 0) (error = git_revwalk_hide(revwalk, git_annotated_commit_id(upstream))) < 0)
goto done; goto done;
git_revwalk_sorting(revwalk, GIT_SORT_REVERSE | GIT_SORT_TIME); git_revwalk_sorting(revwalk, GIT_SORT_REVERSE);
while ((error = git_revwalk_next(&id, revwalk)) == 0) { while ((error = git_revwalk_next(&id, revwalk)) == 0) {
if ((error = git_commit_lookup(&commit, repo, &id)) < 0) if ((error = git_commit_lookup(&commit, repo, &id)) < 0)
......
...@@ -401,3 +401,19 @@ int git_vector_verify_sorted(const git_vector *v) ...@@ -401,3 +401,19 @@ int git_vector_verify_sorted(const git_vector *v)
return 0; return 0;
} }
void git_vector_reverse(git_vector *v)
{
size_t a, b;
a = 0;
b = v->length - 1;
while (a < b) {
void *tmp = v->contents[a];
v->contents[a] = v->contents[b];
v->contents[b] = tmp;
a++;
b--;
}
}
...@@ -118,4 +118,9 @@ GIT_INLINE(void) git_vector_set_cmp(git_vector *v, git_vector_cmp cmp) ...@@ -118,4 +118,9 @@ GIT_INLINE(void) git_vector_set_cmp(git_vector *v, git_vector_cmp cmp)
/* Just use this in tests, not for realz. returns -1 if not sorted */ /* Just use this in tests, not for realz. returns -1 if not sorted */
int git_vector_verify_sorted(const git_vector *v); int git_vector_verify_sorted(const git_vector *v);
/**
* Reverse the vector in-place.
*/
void git_vector_reverse(git_vector *v);
#endif #endif
...@@ -376,3 +376,32 @@ void test_core_vector__grow_and_shrink(void) ...@@ -376,3 +376,32 @@ void test_core_vector__grow_and_shrink(void)
git_vector_free(&x); git_vector_free(&x);
} }
void test_core_vector__reverse(void)
{
git_vector v = GIT_VECTOR_INIT;
size_t i;
void *in1[] = {(void *) 0x0, (void *) 0x1, (void *) 0x2, (void *) 0x3};
void *out1[] = {(void *) 0x3, (void *) 0x2, (void *) 0x1, (void *) 0x0};
void *in2[] = {(void *) 0x0, (void *) 0x1, (void *) 0x2, (void *) 0x3, (void *) 0x4};
void *out2[] = {(void *) 0x4, (void *) 0x3, (void *) 0x2, (void *) 0x1, (void *) 0x0};
for (i = 0; i < 4; i++)
cl_git_pass(git_vector_insert(&v, in1[i]));
git_vector_reverse(&v);
for (i = 0; i < 4; i++)
cl_assert_equal_p(out1[i], git_vector_get(&v, i));
git_vector_clear(&v);
for (i = 0; i < 5; i++)
cl_git_pass(git_vector_insert(&v, in2[i]));
git_vector_reverse(&v);
for (i = 0; i < 5; i++)
cl_assert_equal_p(out2[i], git_vector_get(&v, i));
}
...@@ -28,8 +28,8 @@ static int foreach_cb(const git_oid *oid, void *data) ...@@ -28,8 +28,8 @@ static int foreach_cb(const git_oid *oid, void *data)
/* /*
* $ git --git-dir tests/resources/testrepo.git count-objects --verbose * $ git --git-dir tests/resources/testrepo.git count-objects --verbose
* count: 47 * count: 60
* size: 4 * size: 240
* in-pack: 1640 * in-pack: 1640
* packs: 3 * packs: 3
* size-pack: 425 * size-pack: 425
...@@ -44,7 +44,7 @@ void test_odb_foreach__foreach(void) ...@@ -44,7 +44,7 @@ void test_odb_foreach__foreach(void)
git_repository_odb(&_odb, _repo); git_repository_odb(&_odb, _repo);
cl_git_pass(git_odb_foreach(_odb, foreach_cb, &nobj)); cl_git_pass(git_odb_foreach(_odb, foreach_cb, &nobj));
cl_assert_equal_i(47 + 1640, nobj); /* count + in-pack */ cl_assert_equal_i(60 + 1640, nobj); /* count + in-pack */
} }
void test_odb_foreach__one_pack(void) void test_odb_foreach__one_pack(void)
...@@ -118,7 +118,7 @@ void test_odb_foreach__files_in_objects_dir(void) ...@@ -118,7 +118,7 @@ void test_odb_foreach__files_in_objects_dir(void)
cl_git_pass(git_repository_odb(&odb, repo)); cl_git_pass(git_repository_odb(&odb, repo));
cl_git_pass(git_odb_foreach(odb, foreach_cb, &nobj)); cl_git_pass(git_odb_foreach(odb, foreach_cb, &nobj));
cl_assert_equal_i(47 + 1640, nobj); /* count + in-pack */ cl_assert_equal_i(60 + 1640, nobj); /* count + in-pack */
git_odb_free(odb); git_odb_free(odb);
git_repository_free(repo); git_repository_free(repo);
......
...@@ -38,8 +38,9 @@ static const int commit_sorting_time_reverse[][6] = { ...@@ -38,8 +38,9 @@ static const int commit_sorting_time_reverse[][6] = {
{4, 5, 2, 1, 3, 0} {4, 5, 2, 1, 3, 0}
}; };
/* This is specified unsorted, so both combinations are possible */
static const int commit_sorting_segment[][6] = { static const int commit_sorting_segment[][6] = {
{1, 2, -1, -1, -1, -1} {1, 2, -1, -1, -1, -1}, {2, 1, -1, -1, -1, -1}
}; };
#define commit_count 6 #define commit_count 6
...@@ -155,9 +156,8 @@ void test_revwalk_basic__glob_heads(void) ...@@ -155,9 +156,8 @@ void test_revwalk_basic__glob_heads(void)
cl_git_pass(git_revwalk_push_glob(_walk, "heads")); cl_git_pass(git_revwalk_push_glob(_walk, "heads"));
while (git_revwalk_next(&oid, _walk) == 0) { while (git_revwalk_next(&oid, _walk) == 0)
i++; i++;
}
/* git log --branches --oneline | wc -l => 14 */ /* git log --branches --oneline | wc -l => 14 */
cl_assert_equal_i(i, 14); cl_assert_equal_i(i, 14);
...@@ -338,7 +338,7 @@ void test_revwalk_basic__push_range(void) ...@@ -338,7 +338,7 @@ void test_revwalk_basic__push_range(void)
git_revwalk_reset(_walk); git_revwalk_reset(_walk);
git_revwalk_sorting(_walk, 0); git_revwalk_sorting(_walk, 0);
cl_git_pass(git_revwalk_push_range(_walk, "9fd738e~2..9fd738e")); cl_git_pass(git_revwalk_push_range(_walk, "9fd738e~2..9fd738e"));
cl_git_pass(test_walk_only(_walk, commit_sorting_segment, 1)); cl_git_pass(test_walk_only(_walk, commit_sorting_segment, 2));
} }
void test_revwalk_basic__push_mixed(void) void test_revwalk_basic__push_mixed(void)
...@@ -473,3 +473,51 @@ void test_revwalk_basic__big_timestamp(void) ...@@ -473,3 +473,51 @@ void test_revwalk_basic__big_timestamp(void)
git_signature_free(sig); git_signature_free(sig);
} }
/* Ensure that we correctly hide a commit that is (timewise) older
* than the commits that we are showing.
*
* % git rev-list 8e73b76..bd75801
* bd758010071961f28336333bc41e9c64c9a64866
*/
void test_revwalk_basic__old_hidden_commit_one(void)
{
git_oid new_id, old_id, oid;
revwalk_basic_setup_walk("testrepo.git");
cl_git_pass(git_oid_fromstr(&new_id, "bd758010071961f28336333bc41e9c64c9a64866"));
cl_git_pass(git_revwalk_push(_walk, &new_id));
cl_git_pass(git_oid_fromstr(&old_id, "8e73b769e97678d684b809b163bebdae2911720f"));
cl_git_pass(git_revwalk_hide(_walk, &old_id));
cl_git_pass(git_revwalk_next(&oid, _walk));
cl_assert(!git_oid_streq(&oid, "bd758010071961f28336333bc41e9c64c9a64866"));
cl_git_fail_with(GIT_ITEROVER, git_revwalk_next(&oid, _walk));
}
/* Ensure that we correctly hide a commit that is (timewise) older
* than the commits that we are showing.
*
* % git rev-list bd75801 ^b91e763
* bd758010071961f28336333bc41e9c64c9a64866
*/
void test_revwalk_basic__old_hidden_commit_two(void)
{
git_oid new_id, old_id, oid;
revwalk_basic_setup_walk("testrepo.git");
cl_git_pass(git_oid_fromstr(&new_id, "bd758010071961f28336333bc41e9c64c9a64866"));
cl_git_pass(git_revwalk_push(_walk, &new_id));
cl_git_pass(git_oid_fromstr(&old_id, "b91e763008b10db366442469339f90a2b8400d0a"));
cl_git_pass(git_revwalk_hide(_walk, &old_id));
cl_git_pass(git_revwalk_next(&oid, _walk));
cl_assert(!git_oid_streq(&oid, "bd758010071961f28336333bc41e9c64c9a64866"));
cl_git_fail_with(GIT_ITEROVER, git_revwalk_next(&oid, _walk));
}
...@@ -158,6 +158,7 @@ void test_revwalk_hidecb__hide_some_commits(void) ...@@ -158,6 +158,7 @@ void test_revwalk_hidecb__hide_some_commits(void)
cl_git_pass(git_revwalk_new(&walk, _repo)); cl_git_pass(git_revwalk_new(&walk, _repo));
cl_git_pass(git_revwalk_push(walk, &_head_id)); cl_git_pass(git_revwalk_push(walk, &_head_id));
git_revwalk_sorting(walk, GIT_SORT_TOPOLOGICAL);
/* Add hide callback */ /* Add hide callback */
cl_git_pass(git_revwalk_add_hide_cb(walk, hide_commit_cb, NULL)); cl_git_pass(git_revwalk_add_hide_cb(walk, hide_commit_cb, NULL));
...@@ -182,6 +183,7 @@ void test_revwalk_hidecb__test_payload(void) ...@@ -182,6 +183,7 @@ void test_revwalk_hidecb__test_payload(void)
cl_git_pass(git_revwalk_new(&walk, _repo)); cl_git_pass(git_revwalk_new(&walk, _repo));
cl_git_pass(git_revwalk_push(walk, &_head_id)); cl_git_pass(git_revwalk_push(walk, &_head_id));
git_revwalk_sorting(walk, GIT_SORT_TOPOLOGICAL);
/* Add hide callback, pass id of parent of initial commit as payload data */ /* Add hide callback, pass id of parent of initial commit as payload data */
cl_git_pass(git_revwalk_add_hide_cb(walk, hide_commit_use_payload_cb, &commit_ids[5])); cl_git_pass(git_revwalk_add_hide_cb(walk, hide_commit_use_payload_cb, &commit_ids[5]));
......
...@@ -40,6 +40,7 @@ void test_revwalk_simplify__first_parent(void) ...@@ -40,6 +40,7 @@ void test_revwalk_simplify__first_parent(void)
git_oid_fromstr(&id, commit_head); git_oid_fromstr(&id, commit_head);
cl_git_pass(git_revwalk_push(walk, &id)); cl_git_pass(git_revwalk_push(walk, &id));
git_revwalk_sorting(walk, GIT_SORT_TOPOLOGICAL);
git_revwalk_simplify_first_parent(walk); git_revwalk_simplify_first_parent(walk);
i = 0; i = 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment