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
* 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
* You can now get the user-agent used by libgit2 using the
......
......@@ -25,17 +25,15 @@ GIT_BEGIN_DECL
*/
typedef enum {
/**
* Sort the repository contents in no particular ordering;
* this sorting is arbitrary, implementation-specific
* and subject to change at any time.
* Sort the output with the same default time-order method from git.
* This is the default sorting for new walkers.
*/
GIT_SORT_NONE = 0,
/**
* Sort the repository contents in topological order
* (parents before children); this sorting mode
* can be combined with time sorting.
* Sort the repository contents in topological order (parents before
* children); this sorting mode can be combined with time sorting to
* produce git's "time-order".
*/
GIT_SORT_TOPOLOGICAL = 1 << 0,
......
......@@ -13,10 +13,15 @@
int git_commit_list_time_cmp(const void *a, const void *b)
{
const git_commit_list_node *commit_a = a;
const git_commit_list_node *commit_b = b;
int64_t time_a = ((git_commit_list_node *) a)->time;
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)
......
......@@ -28,6 +28,7 @@ typedef struct git_commit_list_node {
uninteresting:1,
topo_delay:1,
parsed:1,
added:1,
flags : FLAG_BITS;
unsigned short in_degree;
......
......@@ -93,7 +93,7 @@ int git_pqueue_insert(git_pqueue *pq, void *item)
(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);
return error;
......@@ -101,9 +101,15 @@ int git_pqueue_insert(git_pqueue *pq, void *item)
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 */
pq->contents[0] = git_vector_last(pq);
git_vector_pop(pq);
......
......@@ -35,6 +35,7 @@ extern int git_pqueue_init(
#define git_pqueue_clear git_vector_clear
#define git_pqueue_size git_vector_length
#define git_pqueue_get git_vector_get
#define git_pqueue_reverse git_vector_reverse
/**
* Insert a new item into the queue
......
......@@ -586,7 +586,7 @@ static int rebase_init_operations(
(error = git_revwalk_hide(revwalk, git_annotated_commit_id(upstream))) < 0)
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) {
if ((error = git_commit_lookup(&commit, repo, &id)) < 0)
......
......@@ -401,3 +401,19 @@ int git_vector_verify_sorted(const git_vector *v)
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)
/* Just use this in tests, not for realz. returns -1 if not sorted */
int git_vector_verify_sorted(const git_vector *v);
/**
* Reverse the vector in-place.
*/
void git_vector_reverse(git_vector *v);
#endif
......@@ -376,3 +376,32 @@ void test_core_vector__grow_and_shrink(void)
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)
/*
* $ git --git-dir tests/resources/testrepo.git count-objects --verbose
* count: 47
* size: 4
* count: 60
* size: 240
* in-pack: 1640
* packs: 3
* size-pack: 425
......@@ -44,7 +44,7 @@ void test_odb_foreach__foreach(void)
git_repository_odb(&_odb, _repo);
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)
......@@ -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_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_repository_free(repo);
......
......@@ -38,8 +38,9 @@ static const int commit_sorting_time_reverse[][6] = {
{4, 5, 2, 1, 3, 0}
};
/* This is specified unsorted, so both combinations are possible */
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
......@@ -155,9 +156,8 @@ void test_revwalk_basic__glob_heads(void)
cl_git_pass(git_revwalk_push_glob(_walk, "heads"));
while (git_revwalk_next(&oid, _walk) == 0) {
while (git_revwalk_next(&oid, _walk) == 0)
i++;
}
/* git log --branches --oneline | wc -l => 14 */
cl_assert_equal_i(i, 14);
......@@ -338,7 +338,7 @@ void test_revwalk_basic__push_range(void)
git_revwalk_reset(_walk);
git_revwalk_sorting(_walk, 0);
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)
......@@ -473,3 +473,51 @@ void test_revwalk_basic__big_timestamp(void)
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)
cl_git_pass(git_revwalk_new(&walk, _repo));
cl_git_pass(git_revwalk_push(walk, &_head_id));
git_revwalk_sorting(walk, GIT_SORT_TOPOLOGICAL);
/* Add hide callback */
cl_git_pass(git_revwalk_add_hide_cb(walk, hide_commit_cb, NULL));
......@@ -182,6 +183,7 @@ void test_revwalk_hidecb__test_payload(void)
cl_git_pass(git_revwalk_new(&walk, _repo));
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 */
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)
git_oid_fromstr(&id, commit_head);
cl_git_pass(git_revwalk_push(walk, &id));
git_revwalk_sorting(walk, GIT_SORT_TOPOLOGICAL);
git_revwalk_simplify_first_parent(walk);
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