Merge branch 'ds/find-unique-abbrev-optim'
Optimize the code to find shortest unique prefix of object names. * ds/find-unique-abbrev-optim: sha1_name: minimize OID comparisons during disambiguation sha1_name: parse less while finding common prefix sha1_name: unroll len loop in find_unique_abbrev_r() p4211-line-log.sh: add log --online --raw --parents perf testmaint
commit
cb52b49db5
135
sha1_name.c
135
sha1_name.c
|
|
@ -153,7 +153,9 @@ static void unique_in_pack(struct packed_git *p,
|
||||||
uint32_t num, last, i, first = 0;
|
uint32_t num, last, i, first = 0;
|
||||||
const struct object_id *current = NULL;
|
const struct object_id *current = NULL;
|
||||||
|
|
||||||
open_pack_index(p);
|
if (open_pack_index(p) || !p->num_objects)
|
||||||
|
return;
|
||||||
|
|
||||||
num = p->num_objects;
|
num = p->num_objects;
|
||||||
last = num;
|
last = num;
|
||||||
while (first < last) {
|
while (first < last) {
|
||||||
|
|
@ -474,10 +476,104 @@ static unsigned msb(unsigned long val)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct min_abbrev_data {
|
||||||
|
unsigned int init_len;
|
||||||
|
unsigned int cur_len;
|
||||||
|
char *hex;
|
||||||
|
const unsigned char *hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline char get_hex_char_from_oid(const struct object_id *oid,
|
||||||
|
unsigned int pos)
|
||||||
|
{
|
||||||
|
static const char hex[] = "0123456789abcdef";
|
||||||
|
|
||||||
|
if ((pos & 1) == 0)
|
||||||
|
return hex[oid->hash[pos >> 1] >> 4];
|
||||||
|
else
|
||||||
|
return hex[oid->hash[pos >> 1] & 0xf];
|
||||||
|
}
|
||||||
|
|
||||||
|
static int extend_abbrev_len(const struct object_id *oid, void *cb_data)
|
||||||
|
{
|
||||||
|
struct min_abbrev_data *mad = cb_data;
|
||||||
|
|
||||||
|
unsigned int i = mad->init_len;
|
||||||
|
while (mad->hex[i] && mad->hex[i] == get_hex_char_from_oid(oid, i))
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if (i < GIT_MAX_RAWSZ && i >= mad->cur_len)
|
||||||
|
mad->cur_len = i + 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void find_abbrev_len_for_pack(struct packed_git *p,
|
||||||
|
struct min_abbrev_data *mad)
|
||||||
|
{
|
||||||
|
int match = 0;
|
||||||
|
uint32_t num, last, first = 0;
|
||||||
|
struct object_id oid;
|
||||||
|
|
||||||
|
if (open_pack_index(p) || !p->num_objects)
|
||||||
|
return;
|
||||||
|
|
||||||
|
num = p->num_objects;
|
||||||
|
last = num;
|
||||||
|
while (first < last) {
|
||||||
|
uint32_t mid = first + (last - first) / 2;
|
||||||
|
const unsigned char *current;
|
||||||
|
int cmp;
|
||||||
|
|
||||||
|
current = nth_packed_object_sha1(p, mid);
|
||||||
|
cmp = hashcmp(mad->hash, current);
|
||||||
|
if (!cmp) {
|
||||||
|
match = 1;
|
||||||
|
first = mid;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (cmp > 0) {
|
||||||
|
first = mid + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
last = mid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* first is now the position in the packfile where we would insert
|
||||||
|
* mad->hash if it does not exist (or the position of mad->hash if
|
||||||
|
* it does exist). Hence, we consider a maximum of three objects
|
||||||
|
* nearby for the abbreviation length.
|
||||||
|
*/
|
||||||
|
mad->init_len = 0;
|
||||||
|
if (!match) {
|
||||||
|
nth_packed_object_oid(&oid, p, first);
|
||||||
|
extend_abbrev_len(&oid, mad);
|
||||||
|
} else if (first < num - 1) {
|
||||||
|
nth_packed_object_oid(&oid, p, first + 1);
|
||||||
|
extend_abbrev_len(&oid, mad);
|
||||||
|
}
|
||||||
|
if (first > 0) {
|
||||||
|
nth_packed_object_oid(&oid, p, first - 1);
|
||||||
|
extend_abbrev_len(&oid, mad);
|
||||||
|
}
|
||||||
|
mad->init_len = mad->cur_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void find_abbrev_len_packed(struct min_abbrev_data *mad)
|
||||||
|
{
|
||||||
|
struct packed_git *p;
|
||||||
|
|
||||||
|
prepare_packed_git();
|
||||||
|
for (p = packed_git; p; p = p->next)
|
||||||
|
find_abbrev_len_for_pack(p, mad);
|
||||||
|
}
|
||||||
|
|
||||||
int find_unique_abbrev_r(char *hex, const unsigned char *sha1, int len)
|
int find_unique_abbrev_r(char *hex, const unsigned char *sha1, int len)
|
||||||
{
|
{
|
||||||
int status, exists;
|
struct disambiguate_state ds;
|
||||||
|
struct min_abbrev_data mad;
|
||||||
|
struct object_id oid_ret;
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
unsigned long count = approximate_object_count();
|
unsigned long count = approximate_object_count();
|
||||||
/*
|
/*
|
||||||
|
|
@ -503,19 +599,26 @@ int find_unique_abbrev_r(char *hex, const unsigned char *sha1, int len)
|
||||||
sha1_to_hex_r(hex, sha1);
|
sha1_to_hex_r(hex, sha1);
|
||||||
if (len == GIT_SHA1_HEXSZ || !len)
|
if (len == GIT_SHA1_HEXSZ || !len)
|
||||||
return GIT_SHA1_HEXSZ;
|
return GIT_SHA1_HEXSZ;
|
||||||
exists = has_sha1_file(sha1);
|
|
||||||
while (len < GIT_SHA1_HEXSZ) {
|
mad.init_len = len;
|
||||||
struct object_id oid_ret;
|
mad.cur_len = len;
|
||||||
status = get_short_oid(hex, len, &oid_ret, GET_OID_QUIETLY);
|
mad.hex = hex;
|
||||||
if (exists
|
mad.hash = sha1;
|
||||||
? !status
|
|
||||||
: status == SHORT_NAME_NOT_FOUND) {
|
find_abbrev_len_packed(&mad);
|
||||||
hex[len] = 0;
|
|
||||||
return len;
|
if (init_object_disambiguation(hex, mad.cur_len, &ds) < 0)
|
||||||
}
|
return -1;
|
||||||
len++;
|
|
||||||
}
|
ds.fn = extend_abbrev_len;
|
||||||
return len;
|
ds.always_call_fn = 1;
|
||||||
|
ds.cb_data = (void *)&mad;
|
||||||
|
|
||||||
|
find_short_object_filename(&ds);
|
||||||
|
(void)finish_object_disambiguation(&ds, &oid_ret);
|
||||||
|
|
||||||
|
hex[mad.cur_len] = 0;
|
||||||
|
return mad.cur_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *find_unique_abbrev(const unsigned char *sha1, int len)
|
const char *find_unique_abbrev(const unsigned char *sha1, int len)
|
||||||
|
|
|
||||||
|
|
@ -31,4 +31,8 @@ test_perf 'git log -L (renames on)' '
|
||||||
git log -M -L 1:"$file" >/dev/null
|
git log -M -L 1:"$file" >/dev/null
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_perf 'git log --oneline --raw --parents' '
|
||||||
|
git log --oneline --raw --parents >/dev/null
|
||||||
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue