Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6c04269

Browse files
author
Edward Thomson
committed
git_odb_exists_many_prefixes: query odb for multiple short ids
Query the object database for multiple objects at a time, given their object ID (which may be abbreviated) and optional type.
1 parent e10144a commit 6c04269

File tree

4 files changed

+249
-13
lines changed

4 files changed

+249
-13
lines changed

include/git2/odb.h

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "common.h"
1111
#include "types.h"
1212
#include "oid.h"
13+
#include "oidarray.h"
1314

1415
/**
1516
* @file git2/odb.h
@@ -159,7 +160,8 @@ GIT_EXTERN(int) git_odb_read_header(size_t *len_out, git_otype *type_out, git_od
159160
GIT_EXTERN(int) git_odb_exists(git_odb *db, const git_oid *id);
160161

161162
/**
162-
* Determine if objects can be found in the object database from a short OID.
163+
* Determine if an object can be found in the object database by an
164+
* abbreviated object ID.
163165
*
164166
* @param out The full OID of the found object if just one is found.
165167
* @param db The database to be searched for the given object.
@@ -171,6 +173,34 @@ GIT_EXTERN(int) git_odb_exists(git_odb *db, const git_oid *id);
171173
GIT_EXTERN(int) git_odb_exists_prefix(
172174
git_oid *out, git_odb *db, const git_oid *short_id, size_t len);
173175

176+
/**
177+
* Determine if one or more objects can be found in the object database
178+
* by their abbreviated object IDs. Callers may further restrict the
179+
* lookup based on type. This function will write the complete object
180+
* ID to the `id`s array, and the updated length to the `id_lengths`
181+
* array. (If an object is found, it will have its length updated to
182+
* `GIT_OID_HEXSZ`; if an object is not found, will be be `0`.)
183+
*
184+
* Note that since this function operates on multiple objects, the
185+
* underlying database will not be asked to be reloaded if an object is
186+
* not found (which is unlike other object database operations.)
187+
*
188+
* @param db The database to be searched for the given objects.
189+
* @param ids An array of object IDs to search for
190+
* @param id_lengths The corresponding length of each entry in the `ids`
191+
* array
192+
* @param types The corresponding type of each entry in the `ids` array
193+
* (or null to lookup an object of any type)
194+
* @param cnt The length of the `ids`, `id_lengths` and `types` arrays
195+
* @return 0 on success or an error code on failure
196+
*/
197+
GIT_EXTERN(int) git_odb_exists_many_prefixes(
198+
git_odb *db,
199+
git_oid *ids,
200+
size_t *id_lengths,
201+
git_otype *types,
202+
size_t cnt);
203+
174204
/**
175205
* Refresh the object database to load newly added files.
176206
*

src/odb.c

Lines changed: 68 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include "git2/odb_backend.h"
2020
#include "git2/oid.h"
21+
#include "git2/oidarray.h"
2122

2223
#define GIT_ALTERNATES_FILE "info/alternates"
2324

@@ -651,7 +652,7 @@ int git_odb_exists(git_odb *db, const git_oid *id)
651652

652653
if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) {
653654
git_odb_object_free(object);
654-
return (int)true;
655+
return 1;
655656
}
656657

657658
if (odb_exists_1(db, id, false))
@@ -716,10 +717,8 @@ int git_odb_exists_prefix(
716717

717718
if (len < GIT_OID_MINPREFIXLEN)
718719
return git_odb__error_ambiguous("prefix length too short");
719-
if (len > GIT_OID_HEXSZ)
720-
len = GIT_OID_HEXSZ;
721720

722-
if (len == GIT_OID_HEXSZ) {
721+
if (len >= GIT_OID_HEXSZ) {
723722
if (git_odb_exists(db, short_id)) {
724723
if (out)
725724
git_oid_cpy(out, short_id);
@@ -730,10 +729,7 @@ int git_odb_exists_prefix(
730729
}
731730
}
732731

733-
/* just copy valid part of short_id */
734-
memcpy(&key.id, short_id->id, (len + 1) / 2);
735-
if (len & 1)
736-
key.id[len / 2] &= 0xF0;
732+
git_oid__cpy_prefix(&key, short_id, len);
737733

738734
error = odb_exists_prefix_1(out, db, &key, len, false);
739735

@@ -746,6 +742,69 @@ int git_odb_exists_prefix(
746742
return error;
747743
}
748744

745+
int git_odb_exists_many_prefixes(
746+
git_odb *db,
747+
git_oid *ids,
748+
size_t *id_lengths,
749+
git_otype *types,
750+
size_t cnt)
751+
{
752+
size_t len, i;
753+
int error;
754+
755+
assert(db && ids && id_lengths);
756+
757+
for (i = 0; i < cnt; i++) {
758+
git_oid *actual_id = NULL, tmp;
759+
git_otype actual_type = 0;
760+
761+
/* if we were given a full object ID, simply look it up */
762+
if (id_lengths[i] >= GIT_OID_HEXSZ) {
763+
error = git_odb_read_header(&len, &actual_type, db, &ids[i]);
764+
}
765+
766+
/* otherwise, resolve the short id to full, then (optionally)
767+
* read the header.
768+
*/
769+
else if (id_lengths[i] >= GIT_OID_MINPREFIXLEN) {
770+
error = odb_exists_prefix_1(&tmp,
771+
db, &ids[i], id_lengths[i], false);
772+
773+
if (!error) {
774+
actual_id = &tmp;
775+
776+
if (types && types[i] != GIT_OBJ_ANY)
777+
error = git_odb_read_header(&len, &actual_type, db, &tmp);
778+
else
779+
actual_type = GIT_OBJ_ANY;
780+
}
781+
}
782+
783+
if (error < 0 && error != GIT_ENOTFOUND && error != GIT_EAMBIGUOUS)
784+
break;
785+
786+
error = 0;
787+
788+
if (types && types[i] != GIT_OBJ_ANY && types[i] != actual_type)
789+
actual_type = 0;
790+
791+
if (!actual_type) {
792+
id_lengths[i] = 0;
793+
memset(&ids[i], 0, sizeof(git_oid));
794+
} else {
795+
id_lengths[i] = GIT_OID_HEXSZ;
796+
797+
if (actual_id)
798+
git_oid_cpy(&ids[i], actual_id);
799+
}
800+
}
801+
802+
if (!error)
803+
giterr_clear();
804+
805+
return error;
806+
}
807+
749808
int git_odb_read_header(size_t *len_p, git_otype *type_p, git_odb *db, const git_oid *id)
750809
{
751810
int error;
@@ -957,10 +1016,7 @@ int git_odb_read_prefix(
9571016
return 0;
9581017
}
9591018

960-
/* just copy valid part of short_id */
961-
memcpy(&key.id, short_id->id, (len + 1) / 2);
962-
if (len & 1)
963-
key.id[len / 2] &= 0xF0;
1019+
git_oid__cpy_prefix(&key, short_id, len);
9641020

9651021
error = read_prefix_1(out, db, &key, len, false);
9661022

src/oid.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,13 @@ GIT_INLINE(int) git_oid__cmp(const git_oid *a, const git_oid *b)
4444
return git_oid__hashcmp(a->id, b->id);
4545
}
4646

47+
GIT_INLINE(void) git_oid__cpy_prefix(
48+
git_oid *out, const git_oid *id, size_t len)
49+
{
50+
memcpy(&out->id, id->id, (len + 1) / 2);
51+
52+
if (len & 1)
53+
out->id[len / 2] &= 0xF0;
54+
}
55+
4756
#endif

tests/odb/mixed.c

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,144 @@ void test_odb_mixed__dup_oid_prefix_0(void) {
108108
cl_git_pass(git_odb_read_prefix(&obj, _odb, &oid, strlen(hex)));
109109
git_odb_object_free(obj);
110110
}
111+
112+
struct odb_test_data {
113+
char *lookup_id;
114+
char *expected_id;
115+
git_otype expected_type;
116+
};
117+
118+
struct odb_test_data prefix_data[] = {
119+
/* some prefixes and their expected values */
120+
{ "dea509d0", NULL, GIT_OBJ_ANY },
121+
{ "00000000", NULL, GIT_OBJ_ANY },
122+
{ "dea509d0", NULL, GIT_OBJ_ANY },
123+
{ "dea509d09", "dea509d097ce692e167dfc6a48a7a280cc5e877e", GIT_OBJ_BLOB },
124+
{ "dea509d0b", "dea509d0b3cb8ee0650f6ca210bc83f4678851ba", GIT_OBJ_BLOB },
125+
{ "ce0136250", "ce013625030ba8dba906f756967f9e9ca394464a", GIT_OBJ_BLOB },
126+
{ "0ddeaded", NULL, GIT_OBJ_ANY },
127+
{ "4d5979b", "4d5979b468252190cb572ae758aca36928e8a91e", GIT_OBJ_TREE },
128+
{ "0ddeaded", NULL, GIT_OBJ_ANY },
129+
{ "0ddeadede", "0ddeadede9e6d6ccddce0ee1e5749eed0485e5ea", GIT_OBJ_BLOB },
130+
{ "0ddeaded9", "0ddeaded9502971eefe1e41e34d0e536853ae20f", GIT_OBJ_BLOB },
131+
{ "f00b4e", NULL, GIT_OBJ_ANY },
132+
133+
/* some full-length object ids */
134+
{ "0000000000000000000000000000000000000000", NULL, GIT_OBJ_ANY },
135+
{
136+
"dea509d097ce692e167dfc6a48a7a280cc5e877e",
137+
"dea509d097ce692e167dfc6a48a7a280cc5e877e",
138+
GIT_OBJ_BLOB
139+
},
140+
{ "f00f00f00f00f00f00f00f00f00f00f00f00f00f", NULL, GIT_OBJ_ANY },
141+
{
142+
"4d5979b468252190cb572ae758aca36928e8a91e",
143+
"4d5979b468252190cb572ae758aca36928e8a91e",
144+
GIT_OBJ_TREE
145+
},
146+
};
147+
148+
static void setup_prefix_query(
149+
git_oid **out_ids,
150+
size_t **out_lengths,
151+
git_otype **out_types,
152+
size_t *out_num)
153+
{
154+
git_oid *ids;
155+
git_otype *types;
156+
size_t num, *lengths, i;
157+
158+
num = ARRAY_SIZE(prefix_data);
159+
160+
cl_assert((ids = git__calloc(num, sizeof(git_oid))));
161+
cl_assert((lengths = git__calloc(num, sizeof(size_t))));
162+
cl_assert((types = git__calloc(num, sizeof(git_otype))));
163+
164+
for (i = 0; i < num; i++) {
165+
lengths[i] = strlen(prefix_data[i].lookup_id);
166+
git_oid_fromstrn(&ids[i], prefix_data[i].lookup_id, lengths[i]);
167+
types[i] = prefix_data[i].expected_type;
168+
}
169+
170+
*out_ids = ids;
171+
*out_lengths = lengths;
172+
*out_types = types;
173+
*out_num = num;
174+
}
175+
176+
static void assert_found_objects(git_oid *ids, size_t *lengths)
177+
{
178+
size_t num, i;
179+
180+
num = ARRAY_SIZE(prefix_data);
181+
182+
for (i = 0; i < num; i++) {
183+
git_oid expected_id = {{0}};
184+
size_t expected_len = 0;
185+
186+
if (prefix_data[i].expected_id) {
187+
git_oid_fromstr(&expected_id, prefix_data[i].expected_id);
188+
expected_len = GIT_OID_HEXSZ;
189+
}
190+
191+
cl_assert_equal_i(expected_len, lengths[i]);
192+
cl_assert_equal_oid(&expected_id, &ids[i]);
193+
}
194+
}
195+
196+
static void assert_notfound_objects(git_oid *ids, size_t *lengths)
197+
{
198+
git_oid expected_id = {{0}};
199+
size_t num, i;
200+
201+
num = ARRAY_SIZE(prefix_data);
202+
203+
for (i = 0; i < num; i++) {
204+
cl_assert_equal_i(0, lengths[i]);
205+
cl_assert_equal_oid(&expected_id, &ids[i]);
206+
}
207+
}
208+
209+
void test_odb_mixed__prefix_many(void)
210+
{
211+
git_oid *ids;
212+
size_t i, num, *lengths;
213+
git_otype *types;
214+
215+
/* test looking for the actual (correct) types */
216+
217+
setup_prefix_query(&ids, &lengths, &types, &num);
218+
cl_git_pass(git_odb_exists_many_prefixes(_odb, ids, lengths, types, num));
219+
assert_found_objects(ids, lengths);
220+
git__free(ids); git__free(lengths); git__free(types);
221+
222+
/* test looking for no specified types (types array == NULL) */
223+
224+
setup_prefix_query(&ids, &lengths, &types, &num);
225+
cl_git_pass(git_odb_exists_many_prefixes(_odb, ids, lengths, NULL, num));
226+
assert_found_objects(ids, lengths);
227+
git__free(ids); git__free(lengths); git__free(types);
228+
229+
/* test looking for an explicit GIT_OBJ_ANY */
230+
231+
setup_prefix_query(&ids, &lengths, &types, &num);
232+
233+
for (i = 0; i < num; i++)
234+
types[i] = GIT_OBJ_ANY;
235+
236+
cl_git_pass(git_odb_exists_many_prefixes(_odb, ids, lengths, types, num));
237+
assert_found_objects(ids, lengths);
238+
git__free(ids); git__free(lengths); git__free(types);
239+
240+
/* test looking for the completely wrong type */
241+
242+
setup_prefix_query(&ids, &lengths, &types, &num);
243+
244+
for (i = 0; i < num; i++)
245+
types[i] = (types[i] == GIT_OBJ_BLOB) ? GIT_OBJ_TREE : GIT_OBJ_BLOB;
246+
247+
cl_git_pass(git_odb_exists_many_prefixes(_odb, ids, lengths, types, num));
248+
assert_notfound_objects(ids, lengths);
249+
git__free(ids); git__free(lengths); git__free(types);
250+
}
251+

0 commit comments

Comments
 (0)