Skip to content

Commit 82d0a8c

Browse files
committed
Merge branch 'rs/oidset-on-khash'
The oidset API was built on top of the oidmap API which in turn is on the hashmap API. Replace the implementation to build on top of the khash API and gain performance. * rs/oidset-on-khash: oidset: uninline oidset_init() oidset: use khash khash: factor out kh_release_* fetch-pack: load tip_oids eagerly iff needed fetch-pack: factor out is_unmatched_ref()
2 parents 9822b8f + 8c84ae6 commit 82d0a8c

File tree

4 files changed

+81
-61
lines changed

4 files changed

+81
-61
lines changed

fetch-pack.c

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -526,21 +526,14 @@ static void add_refs_to_oidset(struct oidset *oids, struct ref *refs)
526526
oidset_insert(oids, &refs->old_oid);
527527
}
528528

529-
static int tip_oids_contain(struct oidset *tip_oids,
530-
struct ref *unmatched, struct ref *newlist,
531-
const struct object_id *id)
529+
static int is_unmatched_ref(const struct ref *ref)
532530
{
533-
/*
534-
* Note that this only looks at the ref lists the first time it's
535-
* called. This works out in filter_refs() because even though it may
536-
* add to "newlist" between calls, the additions will always be for
537-
* oids that are already in the set.
538-
*/
539-
if (!tip_oids->map.map.tablesize) {
540-
add_refs_to_oidset(tip_oids, unmatched);
541-
add_refs_to_oidset(tip_oids, newlist);
542-
}
543-
return oidset_contains(tip_oids, id);
531+
struct object_id oid;
532+
const char *p;
533+
return ref->match_status == REF_NOT_MATCHED &&
534+
!parse_oid_hex(ref->name, &oid, &p) &&
535+
*p == '\0' &&
536+
oideq(&oid, &ref->old_oid);
544537
}
545538

546539
static void filter_refs(struct fetch_pack_args *args,
@@ -553,6 +546,8 @@ static void filter_refs(struct fetch_pack_args *args,
553546
struct ref *ref, *next;
554547
struct oidset tip_oids = OIDSET_INIT;
555548
int i;
549+
int strict = !(allow_unadvertised_object_request &
550+
(ALLOW_TIP_SHA1 | ALLOW_REACHABLE_SHA1));
556551

557552
i = 0;
558553
for (ref = *refs; ref; ref = next) {
@@ -589,23 +584,25 @@ static void filter_refs(struct fetch_pack_args *args,
589584
}
590585
}
591586

587+
if (strict) {
588+
for (i = 0; i < nr_sought; i++) {
589+
ref = sought[i];
590+
if (!is_unmatched_ref(ref))
591+
continue;
592+
593+
add_refs_to_oidset(&tip_oids, unmatched);
594+
add_refs_to_oidset(&tip_oids, newlist);
595+
break;
596+
}
597+
}
598+
592599
/* Append unmatched requests to the list */
593600
for (i = 0; i < nr_sought; i++) {
594-
struct object_id oid;
595-
const char *p;
596-
597601
ref = sought[i];
598-
if (ref->match_status != REF_NOT_MATCHED)
599-
continue;
600-
if (parse_oid_hex(ref->name, &oid, &p) ||
601-
*p != '\0' ||
602-
!oideq(&oid, &ref->old_oid))
602+
if (!is_unmatched_ref(ref))
603603
continue;
604604

605-
if ((allow_unadvertised_object_request &
606-
(ALLOW_TIP_SHA1 | ALLOW_REACHABLE_SHA1)) ||
607-
tip_oids_contain(&tip_oids, unmatched, newlist,
608-
&ref->old_oid)) {
605+
if (!strict || oidset_contains(&tip_oids, &ref->old_oid)) {
609606
ref->match_status = REF_MATCHED;
610607
*newtail = copy_ref(ref);
611608
newtail = &(*newtail)->next;

khash.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,16 @@ static const double __ac_HASH_UPPER = 0.77;
8282
SCOPE kh_##name##_t *kh_init_##name(void) { \
8383
return (kh_##name##_t*)xcalloc(1, sizeof(kh_##name##_t)); \
8484
} \
85+
SCOPE void kh_release_##name(kh_##name##_t *h) \
86+
{ \
87+
free(h->flags); \
88+
free((void *)h->keys); \
89+
free((void *)h->vals); \
90+
} \
8591
SCOPE void kh_destroy_##name(kh_##name##_t *h) \
8692
{ \
8793
if (h) { \
88-
free((void *)h->keys); free(h->flags); \
89-
free((void *)h->vals); \
94+
kh_release_##name(h); \
9095
free(h); \
9196
} \
9297
} \

oidset.c

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,37 @@
11
#include "cache.h"
22
#include "oidset.h"
33

4+
void oidset_init(struct oidset *set, size_t initial_size)
5+
{
6+
memset(&set->set, 0, sizeof(set->set));
7+
if (initial_size)
8+
kh_resize_oid(&set->set, initial_size);
9+
}
10+
411
int oidset_contains(const struct oidset *set, const struct object_id *oid)
512
{
6-
if (!set->map.map.tablesize)
7-
return 0;
8-
return !!oidmap_get(&set->map, oid);
13+
khiter_t pos = kh_get_oid(&set->set, *oid);
14+
return pos != kh_end(&set->set);
915
}
1016

1117
int oidset_insert(struct oidset *set, const struct object_id *oid)
1218
{
13-
struct oidmap_entry *entry;
14-
15-
if (!set->map.map.tablesize)
16-
oidmap_init(&set->map, 0);
17-
else if (oidset_contains(set, oid))
18-
return 1;
19-
20-
entry = xmalloc(sizeof(*entry));
21-
oidcpy(&entry->oid, oid);
22-
23-
oidmap_put(&set->map, entry);
24-
return 0;
19+
int added;
20+
kh_put_oid(&set->set, *oid, &added);
21+
return !added;
2522
}
2623

2724
int oidset_remove(struct oidset *set, const struct object_id *oid)
2825
{
29-
struct oidmap_entry *entry;
30-
31-
entry = oidmap_remove(&set->map, oid);
32-
free(entry);
33-
34-
return (entry != NULL);
26+
khiter_t pos = kh_get_oid(&set->set, *oid);
27+
if (pos == kh_end(&set->set))
28+
return 0;
29+
kh_del_oid(&set->set, pos);
30+
return 1;
3531
}
3632

3733
void oidset_clear(struct oidset *set)
3834
{
39-
oidmap_free(&set->map, 1);
35+
kh_release_oid(&set->set);
36+
oidset_init(set, 0);
4037
}

oidset.h

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
#ifndef OIDSET_H
22
#define OIDSET_H
33

4-
#include "oidmap.h"
4+
#include "hashmap.h"
5+
#include "khash.h"
56

67
/**
78
* This API is similar to sha1-array, in that it maintains a set of object ids
@@ -15,20 +16,35 @@
1516
* table overhead.
1617
*/
1718

19+
static inline unsigned int oid_hash(struct object_id oid)
20+
{
21+
return sha1hash(oid.hash);
22+
}
23+
24+
static inline int oid_equal(struct object_id a, struct object_id b)
25+
{
26+
return oideq(&a, &b);
27+
}
28+
29+
KHASH_INIT(oid, struct object_id, int, 0, oid_hash, oid_equal)
30+
1831
/**
1932
* A single oidset; should be zero-initialized (or use OIDSET_INIT).
2033
*/
2134
struct oidset {
22-
struct oidmap map;
35+
kh_oid_t set;
2336
};
2437

25-
#define OIDSET_INIT { OIDMAP_INIT }
38+
#define OIDSET_INIT { { 0 } }
2639

2740

28-
static inline void oidset_init(struct oidset *set, size_t initial_size)
29-
{
30-
oidmap_init(&set->map, initial_size);
31-
}
41+
/**
42+
* Initialize the oidset structure `set`.
43+
*
44+
* If `initial_size` is bigger than 0 then preallocate to allow inserting
45+
* the specified number of elements without further allocations.
46+
*/
47+
void oidset_init(struct oidset *set, size_t initial_size);
3248

3349
/**
3450
* Returns true iff `set` contains `oid`.
@@ -58,19 +74,24 @@ int oidset_remove(struct oidset *set, const struct object_id *oid);
5874
void oidset_clear(struct oidset *set);
5975

6076
struct oidset_iter {
61-
struct oidmap_iter m_iter;
77+
kh_oid_t *set;
78+
khiter_t iter;
6279
};
6380

6481
static inline void oidset_iter_init(struct oidset *set,
6582
struct oidset_iter *iter)
6683
{
67-
oidmap_iter_init(&set->map, &iter->m_iter);
84+
iter->set = &set->set;
85+
iter->iter = kh_begin(iter->set);
6886
}
6987

7088
static inline struct object_id *oidset_iter_next(struct oidset_iter *iter)
7189
{
72-
struct oidmap_entry *e = oidmap_iter_next(&iter->m_iter);
73-
return e ? &e->oid : NULL;
90+
for (; iter->iter != kh_end(iter->set); iter->iter++) {
91+
if (kh_exist(iter->set, iter->iter))
92+
return &kh_key(iter->set, iter->iter++);
93+
}
94+
return NULL;
7495
}
7596

7697
static inline struct object_id *oidset_iter_first(struct oidset *set,

0 commit comments

Comments
 (0)