Skip to content

Commit 445f307

Browse files
committed
tree: allow for a tree limit in Tree::count_recursive
Sometimes you find yourself with a repository that not only has a lot of blobs but a lot of trees without many blobs in between. Such a repository can cause `count_recursive` to take a long time to return. Allow for a second limit for the number of trees. If unset we use the limit for blobs which will not have any effect unless you have less than one blob per tree, which is roughly what we're trying to protect against here.
1 parent 762fd37 commit 445f307

File tree

2 files changed

+37
-15
lines changed

2 files changed

+37
-15
lines changed

ext/rugged/rugged_tree.c

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -81,32 +81,41 @@ static VALUE rb_git_tree_entrycount(VALUE self)
8181

8282
struct rugged_treecount_cb_payload
8383
{
84-
int count;
85-
int limit;
84+
int entry_count;
85+
int tree_count;
86+
int entry_limit;
87+
int tree_limit;
8688
};
8789

8890
static int rugged__treecount_cb(const char *root, const git_tree_entry *entry, void *data)
8991
{
9092
struct rugged_treecount_cb_payload *payload = data;
9193

92-
if (payload->limit >= 0 && payload->count >= payload->limit) {
94+
if (payload->entry_limit >= 0 && payload->entry_count >= payload->entry_limit) {
95+
return -1;
96+
} else if (payload->tree_limit >= 0 && payload->tree_count >= payload->tree_limit) {
9397
return -1;
9498
} else if(git_tree_entry_type(entry) == GIT_OBJ_TREE) {
99+
++(payload->tree_count);
95100
return 0;
96101
} else {
97-
++(payload->count);
102+
++(payload->entry_count);
98103
return 1;
99104
}
100105
}
101106

102107
/*
103108
* call-seq:
104-
* tree.count_recursive(limit=nil) -> count
109+
* tree.count_recursive(entry_limit=nil, tree_limit=nil) -> count
105110
*
106-
* `limit` - The maximum number of blobs to the count in the repository.
107-
* Rugged will stop walking the tree after `limit` items to avoid long
111+
* `entry_limit` - The maximum number of blobs to the count in the repository.
112+
* Rugged will stop walking the trees after `entry_limit` items to avoid long
108113
* execution times.
109114
*
115+
* `tree_limit` - The maximum number of trees to look in. Rugged will stop
116+
* walking the trees after `tree_limit` items to avoid long execution times. If
117+
* it is unset but `entry_limit` is set, `tree_limit` is set to the same value.
118+
*
110119
* Return the number of blobs (up to the limit) contained in the tree and
111120
* all subtrees.
112121
*/
@@ -115,18 +124,29 @@ static VALUE rb_git_tree_entrycount_recursive(int argc, VALUE* argv, VALUE self)
115124
git_tree *tree;
116125
int error;
117126
struct rugged_treecount_cb_payload payload;
118-
VALUE rb_limit;
127+
VALUE rb_entry_limit, rb_tree_limit;
119128

120129
TypedData_Get_Struct(self, git_tree, &rugged_object_type, tree);
121130

122-
rb_scan_args(argc, argv, "01", &rb_limit);
131+
rb_scan_args(argc, argv, "02", &rb_entry_limit, &rb_tree_limit);
132+
133+
payload.entry_limit = -1;
134+
payload.tree_limit = -1;
135+
payload.entry_count = 0;
136+
payload.tree_count = 0;
123137

124-
payload.limit = -1;
125-
payload.count = 0;
138+
if (!NIL_P(rb_entry_limit)) {
139+
Check_Type(rb_entry_limit, T_FIXNUM);
140+
payload.entry_limit = FIX2INT(rb_entry_limit);
141+
}
142+
143+
if (!NIL_P(rb_tree_limit)) {
144+
Check_Type(rb_tree_limit, T_FIXNUM);
145+
payload.tree_limit = FIX2INT(rb_tree_limit);
146+
}
126147

127-
if (!NIL_P(rb_limit)) {
128-
Check_Type(rb_limit, T_FIXNUM);
129-
payload.limit = FIX2INT(rb_limit);
148+
if (payload.tree_limit < 0 && payload.entry_limit >= 0) {
149+
payload.tree_limit = payload.entry_limit;
130150
}
131151

132152

@@ -139,7 +159,7 @@ static VALUE rb_git_tree_entrycount_recursive(int argc, VALUE* argv, VALUE self)
139159

140160
rugged_exception_check(error);
141161

142-
return INT2FIX(payload.count);
162+
return INT2FIX(payload.entry_count);
143163
}
144164

145165
/*

test/tree_test.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ def test_read_tree_data
4848
assert_equal 6, @tree.count_recursive
4949
assert_equal 5, @tree.count_recursive(5)
5050
assert_equal 6, @tree.count_recursive(10)
51+
assert_equal 2, @tree.count_recursive(10, 1)
52+
assert_equal 4, @tree.count_recursive(10, 2)
5153
assert_raises(TypeError) do
5254
@tree.count_recursive("NaN")
5355
end

0 commit comments

Comments
 (0)