Skip to content

Commit d960bd0

Browse files
pks-tgitster
authored andcommitted
oidtree: add ability to store data
The oidtree data structure is currently only used to store object IDs, without any associated data. So consequently, it can only really be used to track which object IDs exist, and we can use the tree structure to efficiently operate on OID prefixes. But there are valid use cases where we want to both: - Store object IDs in a sorted order. - Associated arbitrary data with them. Refactor the oidtree interface so that it allows us to store arbitrary payloads within the respective nodes. This will be used in the next commit. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 4439f83 commit d960bd0

5 files changed

Lines changed: 68 additions & 12 deletions

File tree

loose.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ static int insert_loose_map(struct odb_source *source,
5757
inserted |= insert_oid_pair(map->to_compat, oid, compat_oid);
5858
inserted |= insert_oid_pair(map->to_storage, compat_oid, oid);
5959
if (inserted)
60-
oidtree_insert(files->loose->cache, compat_oid);
60+
oidtree_insert(files->loose->cache, compat_oid, NULL);
6161

6262
return inserted;
6363
}

object-file.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1857,6 +1857,7 @@ static int for_each_object_wrapper_cb(const struct object_id *oid,
18571857
}
18581858

18591859
static int for_each_prefixed_object_wrapper_cb(const struct object_id *oid,
1860+
void *node_data UNUSED,
18601861
void *cb_data)
18611862
{
18621863
struct for_each_object_wrapper_data *data = cb_data;
@@ -2002,7 +2003,7 @@ static int append_loose_object(const struct object_id *oid,
20022003
const char *path UNUSED,
20032004
void *data)
20042005
{
2005-
oidtree_insert(data, oid);
2006+
oidtree_insert(data, oid, NULL);
20062007
return 0;
20072008
}
20082009

oidtree.c

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
struct oidtree_node {
1010
struct cb_node base;
1111
struct object_id key;
12+
void *data;
1213
};
1314

1415
void oidtree_init(struct oidtree *ot)
@@ -25,29 +26,42 @@ void oidtree_clear(struct oidtree *ot)
2526
}
2627
}
2728

28-
void oidtree_insert(struct oidtree *ot, const struct object_id *oid)
29+
struct oidtree_data {
30+
struct object_id oid;
31+
};
32+
33+
void oidtree_insert(struct oidtree *ot, const struct object_id *oid,
34+
void *data)
2935
{
3036
struct oidtree_node *on;
37+
struct cb_node *node;
3138

3239
if (!oid->algo)
3340
BUG("oidtree_insert requires oid->algo");
3441

3542
on = mem_pool_alloc(&ot->mem_pool, sizeof(*on));
3643
oidcpy(&on->key, oid);
44+
on->data = data;
3745

3846
/*
3947
* n.b. Current callers won't get us duplicates, here. If a
4048
* future caller causes duplicates, there'll be a small leak
4149
* that won't be freed until oidtree_clear. Currently it's not
4250
* worth maintaining a free list
4351
*/
44-
cb_insert(&ot->tree, &on->base, sizeof(*oid));
52+
node = cb_insert(&ot->tree, &on->base, sizeof(*oid));
53+
if (node) {
54+
struct oidtree_node *preexisting = container_of(node, struct oidtree_node, base);
55+
preexisting->data = data;
56+
}
4557
}
4658

47-
bool oidtree_contains(struct oidtree *ot, const struct object_id *oid)
59+
static struct oidtree_node *oidtree_lookup(struct oidtree *ot,
60+
const struct object_id *oid)
4861
{
4962
struct object_id k;
5063
size_t klen = sizeof(k);
64+
struct cb_node *node;
5165

5266
oidcpy(&k, oid);
5367

@@ -58,7 +72,20 @@ bool oidtree_contains(struct oidtree *ot, const struct object_id *oid)
5872
klen += BUILD_ASSERT_OR_ZERO(offsetof(struct object_id, hash) <
5973
offsetof(struct object_id, algo));
6074

61-
return !!cb_lookup(&ot->tree, (const uint8_t *)&k, klen);
75+
node = cb_lookup(&ot->tree, (const uint8_t *)&k, klen);
76+
return node ? container_of(node, struct oidtree_node, base) : NULL;
77+
}
78+
79+
bool oidtree_contains(struct oidtree *ot, const struct object_id *oid)
80+
{
81+
struct oidtree_node *node = oidtree_lookup(ot, oid);
82+
return node ? 1 : 0;
83+
}
84+
85+
void *oidtree_get(struct oidtree *ot, const struct object_id *oid)
86+
{
87+
struct oidtree_node *node = oidtree_lookup(ot, oid);
88+
return node ? node->data : NULL;
6289
}
6390

6491
struct oidtree_each_data {
@@ -82,7 +109,7 @@ static int iter(struct cb_node *n, void *cb_data)
82109
return 0;
83110
}
84111

85-
return data->cb(&node->key, data->cb_data);
112+
return data->cb(&node->key, node->data, data->cb_data);
86113
}
87114

88115
int oidtree_each(struct oidtree *ot, const struct object_id *prefix,

oidtree.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,26 @@ void oidtree_init(struct oidtree *ot);
2929
*/
3030
void oidtree_clear(struct oidtree *ot);
3131

32-
/* Insert the object ID into the tree. */
33-
void oidtree_insert(struct oidtree *ot, const struct object_id *oid);
32+
/*
33+
* Insert the object ID into the tree and store the given pointer alongside
34+
* with it. The data pointer of any preexisting entry will be overwritten.
35+
*/
36+
void oidtree_insert(struct oidtree *ot, const struct object_id *oid,
37+
void *data);
3438

3539
/* Check whether the tree contains the given object ID. */
3640
bool oidtree_contains(struct oidtree *ot, const struct object_id *oid);
3741

42+
/* Get the payload stored with the given object ID. */
43+
void *oidtree_get(struct oidtree *ot, const struct object_id *oid);
44+
3845
/*
3946
* Callback function used for `oidtree_each()`. Returning a non-zero exit code
4047
* will cause iteration to stop. The exit code will be propagated to the caller
4148
* of `oidtree_each()`.
4249
*/
4350
typedef int (*oidtree_each_cb)(const struct object_id *oid,
51+
void *node_data,
4452
void *cb_data);
4553

4654
/*

t/unit-tests/u-oidtree.c

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ static int fill_tree_loc(struct oidtree *ot, const char *hexes[], size_t n)
1919
for (size_t i = 0; i < n; i++) {
2020
struct object_id oid;
2121
cl_parse_any_oid(hexes[i], &oid);
22-
oidtree_insert(ot, &oid);
22+
oidtree_insert(ot, &oid, NULL);
2323
}
2424
return 0;
2525
}
@@ -38,9 +38,9 @@ struct expected_hex_iter {
3838
const char *query;
3939
};
4040

41-
static int check_each_cb(const struct object_id *oid, void *data)
41+
static int check_each_cb(const struct object_id *oid, void *node_data UNUSED, void *cb_data)
4242
{
43-
struct expected_hex_iter *hex_iter = data;
43+
struct expected_hex_iter *hex_iter = cb_data;
4444
struct object_id expected;
4545

4646
cl_assert(hex_iter->i < hex_iter->expected_hexes.nr);
@@ -105,3 +105,23 @@ void test_oidtree__each(void)
105105
check_each(&ot, "32100", "321", NULL);
106106
check_each(&ot, "32", "320", "321", NULL);
107107
}
108+
109+
void test_oidtree__insert_overwrites_data(void)
110+
{
111+
struct object_id oid;
112+
struct oidtree ot;
113+
int a, b;
114+
115+
cl_parse_any_oid("1", &oid);
116+
117+
oidtree_init(&ot);
118+
119+
oidtree_insert(&ot, &oid, NULL);
120+
cl_assert_equal_p(oidtree_get(&ot, &oid), NULL);
121+
oidtree_insert(&ot, &oid, &a);
122+
cl_assert_equal_p(oidtree_get(&ot, &oid), &a);
123+
oidtree_insert(&ot, &oid, &b);
124+
cl_assert_equal_p(oidtree_get(&ot, &oid), &b);
125+
126+
oidtree_clear(&ot);
127+
}

0 commit comments

Comments
 (0)