From 40800ddc60c985372cfdbbff24da0c30a60bbef8 Mon Sep 17 00:00:00 2001 From: Matthew John Cheetham Date: Tue, 23 Apr 2024 15:25:14 -0700 Subject: [PATCH 1/5] object-name: expose get_parent function Expose the static `get_parent` function so we can use it in the odb--daemon implementation of the `get-parent` IPC call. Signed-off-by: Matthew John Cheetham --- object-name.c | 6 +++--- object-name.h | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/object-name.c b/object-name.c index 523af6f64f3351..55dc8a67d4241c 100644 --- a/object-name.c +++ b/object-name.c @@ -1081,9 +1081,9 @@ static int get_oid_basic(struct repository *r, const char *str, int len, return 0; } -static enum get_oid_result get_parent(struct repository *r, - const char *name, int len, - struct object_id *result, int idx) +enum get_oid_result get_parent(struct repository *r, + const char *name, int len, + struct object_id *result, int idx) { struct object_id oid; enum get_oid_result ret = get_oid_1(r, name, len, &oid, diff --git a/object-name.h b/object-name.h index 064ddc97d1fe99..34277c60ec9d5e 100644 --- a/object-name.h +++ b/object-name.h @@ -121,6 +121,10 @@ struct object *repo_peel_to_type(struct repository *r, const char *name, int namelen, struct object *o, enum object_type); +enum get_oid_result get_parent(struct repository *r, + const char *name, int len, + struct object_id *result, int idx); + /* Convert to/from hex/sha1 representation */ #define MINIMUM_ABBREV minimum_abbrev #define DEFAULT_ABBREV default_abbrev From d98751e0158fc638738e17eaf2278ae37b40c7bc Mon Sep 17 00:00:00 2001 From: Matthew John Cheetham Date: Tue, 23 Apr 2024 15:26:35 -0700 Subject: [PATCH 2/5] odb--daemon: implement get-parent command Implement a basic version of the get-parent command in the ODB daemon that will simply call the `get_parent` function that is being routed over the IPC channel with the same arguments. This will get us a simple working proof of concept. Signed-off-by: Matthew John Cheetham --- builtin/odb--daemon.c | 56 +++++++++++++++++++++++++++++++++++++++++++ object-name.c | 9 +++++-- odb-over-ipc.c | 47 ++++++++++++++++++++++++++++++++++++ odb-over-ipc.h | 16 +++++++++++++ 4 files changed, 126 insertions(+), 2 deletions(-) diff --git a/builtin/odb--daemon.c b/builtin/odb--daemon.c index e73c5f8ac5794d..3d78326a0ce945 100644 --- a/builtin/odb--daemon.c +++ b/builtin/odb--daemon.c @@ -1,6 +1,7 @@ #include "builtin.h" #include "config.h" #include "object-file.h" +#include "object-name.h" #include "object-store.h" #include "oidmap.h" #include "parse-options.h" @@ -211,6 +212,49 @@ static int odb_ipc_cb__hash_object(struct my_odb_ipc_state *state, return 0; } +static int odb_ipc_cb__get_parent(struct my_odb_ipc_state *state, + const char *command, size_t command_len, + ipc_server_reply_cb *reply_cb, + struct ipc_server_reply_data *reply_data) +{ + struct odb_over_ipc__get_parent__request *req; + struct odb_over_ipc__get_parent__response *resp; + const char *name; + size_t name_len; + int ret; + + if (command_len < sizeof(*req)) + BUG("incorrect size for binary data"); + + req = (struct odb_over_ipc__get_parent__request *)command; + + name = command + sizeof(*req); + name_len = command_len - sizeof(*req); + + if (req->name_len != name_len) + BUG("incorrect data length"); + + resp = xmalloc(sizeof(*resp)); + memcpy(&resp->key.key, "get-parent", 11); + + ret = get_parent(the_repository, name, name_len, &resp->oid, req->idx); + + if (ret != FOUND) + goto fail; + + reply_cb(reply_data, (const char *)resp, sizeof(*resp)); + + return 0; + +fail: + /* + * Send the client an error response to force it to do + * the work itself. + */ + reply_cb(reply_data, "error", 6); + return 0; +} + /* * This callback handles IPC requests from clients. We run on an * arbitrary thread. @@ -277,6 +321,18 @@ static int odb_ipc_cb(void *data, return 0; } + if (!strcmp(command, "get-parent")) { + /* + * A client has requested that we find the parent of a given + * object. + */ + trace2_region_enter("odb-daemon", "get-parent", NULL); + ret = odb_ipc_cb__get_parent(state, command, command_len, + reply_cb, reply_data); + trace2_region_leave("odb-daemon", "get-parent", NULL); + return 0; + } + // TODO respond to other requests from client. // // TODO decide how to return an error for unknown commands. diff --git a/object-name.c b/object-name.c index 55dc8a67d4241c..287faf1e397037 100644 --- a/object-name.c +++ b/object-name.c @@ -24,6 +24,7 @@ #include "commit-reach.h" #include "date.h" #include "object-file-convert.h" +#include "odb-over-ipc.h" static int get_oid_oneline(struct repository *r, const char *, struct object_id *, struct commit_list *); @@ -1086,13 +1087,17 @@ enum get_oid_result get_parent(struct repository *r, struct object_id *result, int idx) { struct object_id oid; - enum get_oid_result ret = get_oid_1(r, name, len, &oid, - GET_OID_COMMITTISH); + enum get_oid_result ret; struct commit *commit; struct commit_list *p; + if (odb_over_ipc__get_parent(r, name, len, idx, result) == 0) + return FOUND; + + ret = get_oid_1(r, name, len, &oid, GET_OID_COMMITTISH); if (ret) return ret; + commit = lookup_commit_reference(r, &oid); if (repo_parse_commit(r, commit)) return MISSING_OBJECT; diff --git a/odb-over-ipc.c b/odb-over-ipc.c index 1d342b71ebbebd..979d56d9e499c5 100644 --- a/odb-over-ipc.c +++ b/odb-over-ipc.c @@ -264,4 +264,51 @@ int odb_over_ipc__hash_object(struct repository *r, struct object_id *oid, return ret; } +int odb_over_ipc__get_parent(struct repository *r, const char *name, int len, + int idx, struct object_id *result) +{ + struct odb_over_ipc__get_parent__request req; + struct odb_over_ipc__get_parent__response *resp; + struct strbuf msg = STRBUF_INIT; + struct strbuf answer = STRBUF_INIT; + int ret; + + if (is_daemon) + return -1; + + if (!core_use_odb_over_ipc) + return -1; + + if (r != the_repository) // TODO not dealing with this + return -1; + + memset(&req, 0, sizeof(req)); + memcpy(req.key.key, "get-parent", 10); + req.idx = idx; + req.name_len = len; + + /* Append the name at the end of the request */ + strbuf_init(&msg, sizeof(req) + len); + strbuf_add(&msg, &req, sizeof(req)); + strbuf_add(&msg, name, len); + + ret = odb_over_ipc__command((const char *)msg.buf, msg.len, &answer); + if (ret) + return ret; + + if (!strncmp(answer.buf, "error", 5)) { + trace2_printf("odb-over-ipc: failed"); + return -1; + } + + if (answer.len != sizeof(*resp)) + BUG("incorrect size for binary data"); + resp = (struct odb_over_ipc__get_parent__response *)answer.buf; + + oidcpy(result, &resp->oid); + + strbuf_release(&answer); + return ret; +} + #endif /* SUPPORTS_SIMPLE_IPC */ diff --git a/odb-over-ipc.h b/odb-over-ipc.h index 8fc1f27200731d..d3a9858cad93dc 100644 --- a/odb-over-ipc.h +++ b/odb-over-ipc.h @@ -82,6 +82,19 @@ struct odb_over_ipc__hash_object__response struct object_id oid; }; +struct odb_over_ipc__get_parent__request +{ + struct odb_over_ipc__key key; + int idx; + int name_len; +}; + +struct odb_over_ipc__get_parent__response +{ + struct odb_over_ipc__key key; + struct object_id oid; +}; + /* * Connect to an existing `git odb--daemon` process and ask it for * an object. This is intended to be inserted into the client @@ -100,6 +113,9 @@ int odb_over_ipc__get_oid(struct repository *r, const struct object_id *oid, int odb_over_ipc__hash_object(struct repository *r, struct object_id *oid, int fd, enum object_type type, unsigned flags); +int odb_over_ipc__get_parent(struct repository *r, const char *name, int len, + int idx, struct object_id *result); + /* * Explicitly shutdown IPC connection to the `git odb--daemon` process. * The connection is implicitly created upon the first request and we From b2276a1adcc64b8eff2a306ff91a629dc82c3210 Mon Sep 17 00:00:00 2001 From: Matthew John Cheetham Date: Wed, 24 Apr 2024 13:59:43 -0700 Subject: [PATCH 3/5] object-name: expose get_nth_ancestor function Expose the static `get_nth_ancestor` function so we can use it in the odb--daemon implementation of the `get-nth-ancestor` IPC call. Signed-off-by: Matthew John Cheetham --- object-name.c | 8 ++++---- object-name.h | 5 +++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/object-name.c b/object-name.c index 287faf1e397037..de7daa8845a4f3 100644 --- a/object-name.c +++ b/object-name.c @@ -1116,10 +1116,10 @@ enum get_oid_result get_parent(struct repository *r, return MISSING_OBJECT; } -static enum get_oid_result get_nth_ancestor(struct repository *r, - const char *name, int len, - struct object_id *result, - int generation) +enum get_oid_result get_nth_ancestor(struct repository *r, + const char *name, int len, + struct object_id *result, + int generation) { struct object_id oid; struct commit *commit; diff --git a/object-name.h b/object-name.h index 34277c60ec9d5e..d33022847d9fe7 100644 --- a/object-name.h +++ b/object-name.h @@ -125,6 +125,11 @@ enum get_oid_result get_parent(struct repository *r, const char *name, int len, struct object_id *result, int idx); +enum get_oid_result get_nth_ancestor(struct repository *r, + const char *name, int len, + struct object_id *result, + int generation); + /* Convert to/from hex/sha1 representation */ #define MINIMUM_ABBREV minimum_abbrev #define DEFAULT_ABBREV default_abbrev From fb50118a40cae5596395b4a2048b75919c0880bf Mon Sep 17 00:00:00 2001 From: Matthew John Cheetham Date: Wed, 24 Apr 2024 14:04:55 -0700 Subject: [PATCH 4/5] odb--daemon: implement get-nth-ancestor command Implement a basic version of the get-nth-ancestor command in the ODB daemon that will simply call the `get_nth_ancestor` function that is being routed over the IPC channel with the same arguments. This will get us a simple working proof of concept. Signed-off-by: Matthew John Cheetham --- builtin/odb--daemon.c | 56 +++++++++++++++++++++++++++++++++++++++++++ object-name.c | 3 +++ odb-over-ipc.c | 48 +++++++++++++++++++++++++++++++++++++ odb-over-ipc.h | 17 +++++++++++++ 4 files changed, 124 insertions(+) diff --git a/builtin/odb--daemon.c b/builtin/odb--daemon.c index 3d78326a0ce945..feadffb36772f7 100644 --- a/builtin/odb--daemon.c +++ b/builtin/odb--daemon.c @@ -255,6 +255,50 @@ static int odb_ipc_cb__get_parent(struct my_odb_ipc_state *state, return 0; } +static int odb_ipc_cb__get_nth_ancestor(struct my_odb_ipc_state *state, + const char *command, size_t command_len, + ipc_server_reply_cb *reply_cb, + struct ipc_server_reply_data *reply_data) +{ + struct odb_over_ipc__get_nth_ancestor__request *req; + struct odb_over_ipc__get_nth_ancestor__response *resp; + const char *name; + size_t name_len; + int ret; + + if (command_len < sizeof(*req)) + BUG("incorrect size for binary data"); + + req = (struct odb_over_ipc__get_nth_ancestor__request *)command; + + name = command + sizeof(*req); + name_len = command_len - sizeof(*req); + + if (req->name_len != name_len) + BUG("incorrect data length"); + + resp = xmalloc(sizeof(*resp)); + memcpy(&resp->key.key, "get-nth-ancestor", 11); + + ret = get_nth_ancestor(the_repository, name, name_len, &resp->oid, + req->generation); + + if (ret != FOUND) + goto fail; + + reply_cb(reply_data, (const char *)resp, sizeof(*resp)); + + return 0; + +fail: + /* + * Send the client an error response to force it to do + * the work itself. + */ + reply_cb(reply_data, "error", 6); + return 0; +} + /* * This callback handles IPC requests from clients. We run on an * arbitrary thread. @@ -333,6 +377,18 @@ static int odb_ipc_cb(void *data, return 0; } + if (!strcmp(command, "get-nth-ancestor")) { + /* + * A client has requested that we find the nth ancestpr of a + * given object. + */ + trace2_region_enter("odb-daemon", "get-nth-ancestor", NULL); + ret = odb_ipc_cb__get_nth_ancestor(state, command, command_len, + reply_cb, reply_data); + trace2_region_leave("odb-daemon", "get-nth-ancestor", NULL); + return 0; + } + // TODO respond to other requests from client. // // TODO decide how to return an error for unknown commands. diff --git a/object-name.c b/object-name.c index de7daa8845a4f3..9cd45b0163675e 100644 --- a/object-name.c +++ b/object-name.c @@ -1125,6 +1125,9 @@ enum get_oid_result get_nth_ancestor(struct repository *r, struct commit *commit; int ret; + if (odb_over_ipc__get_nth_ancestor(r, name, len, generation, result) == 0) + return FOUND; + ret = get_oid_1(r, name, len, &oid, GET_OID_COMMITTISH); if (ret) return ret; diff --git a/odb-over-ipc.c b/odb-over-ipc.c index 979d56d9e499c5..cbab474740e22c 100644 --- a/odb-over-ipc.c +++ b/odb-over-ipc.c @@ -311,4 +311,52 @@ int odb_over_ipc__get_parent(struct repository *r, const char *name, int len, return ret; } +int odb_over_ipc__get_nth_ancestor(struct repository *r, const char *name, + int len, int generation, + struct object_id *result) +{ + struct odb_over_ipc__get_nth_ancestor__request req; + struct odb_over_ipc__get_nth_ancestor__response *resp; + struct strbuf msg = STRBUF_INIT; + struct strbuf answer = STRBUF_INIT; + int ret; + + if (is_daemon) + return -1; + + if (!core_use_odb_over_ipc) + return -1; + + if (r != the_repository) // TODO not dealing with this + return -1; + + memset(&req, 0, sizeof(req)); + memcpy(req.key.key, "get-nth-ancestor", 16); + req.generation = generation; + req.name_len = len; + + /* Append the name at the end of the request */ + strbuf_init(&msg, sizeof(req) + len); + strbuf_add(&msg, &req, sizeof(req)); + strbuf_add(&msg, name, len); + + ret = odb_over_ipc__command((const char *)msg.buf, msg.len, &answer); + if (ret) + return ret; + + if (!strncmp(answer.buf, "error", 5)) { + trace2_printf("odb-over-ipc: failed"); + return -1; + } + + if (answer.len != sizeof(*resp)) + BUG("incorrect size for binary data"); + resp = (struct odb_over_ipc__get_nth_ancestor__response *)answer.buf; + + oidcpy(result, &resp->oid); + + strbuf_release(&answer); + return ret; +} + #endif /* SUPPORTS_SIMPLE_IPC */ diff --git a/odb-over-ipc.h b/odb-over-ipc.h index d3a9858cad93dc..26a5111c197181 100644 --- a/odb-over-ipc.h +++ b/odb-over-ipc.h @@ -95,6 +95,19 @@ struct odb_over_ipc__get_parent__response struct object_id oid; }; +struct odb_over_ipc__get_nth_ancestor__request +{ + struct odb_over_ipc__key key; + int generation; + int name_len; +}; + +struct odb_over_ipc__get_nth_ancestor__response +{ + struct odb_over_ipc__key key; + struct object_id oid; +}; + /* * Connect to an existing `git odb--daemon` process and ask it for * an object. This is intended to be inserted into the client @@ -116,6 +129,10 @@ int odb_over_ipc__hash_object(struct repository *r, struct object_id *oid, int odb_over_ipc__get_parent(struct repository *r, const char *name, int len, int idx, struct object_id *result); +int odb_over_ipc__get_nth_ancestor(struct repository *r, const char *name, + int len, int generation, + struct object_id *result); + /* * Explicitly shutdown IPC connection to the `git odb--daemon` process. * The connection is implicitly created upon the first request and we From 73ffe3c125428a9d1ad6d8fc290ea3cb6d318a43 Mon Sep 17 00:00:00 2001 From: Matthew John Cheetham Date: Wed, 24 Apr 2024 14:12:51 -0700 Subject: [PATCH 5/5] odb--daemon: rename get-nth-ancestor to get-ancestor Reduce the length of the IPC API `get-nth-ancestor` to be shorter, so that the request key is less than 15 characters + 1 null terminator. Signed-off-by: Matthew John Cheetham --- builtin/odb--daemon.c | 22 +++++++++++----------- object-name.c | 2 +- odb-over-ipc.c | 14 +++++++------- odb-over-ipc.h | 10 +++++----- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/builtin/odb--daemon.c b/builtin/odb--daemon.c index feadffb36772f7..4f11dd136d09ae 100644 --- a/builtin/odb--daemon.c +++ b/builtin/odb--daemon.c @@ -255,13 +255,13 @@ static int odb_ipc_cb__get_parent(struct my_odb_ipc_state *state, return 0; } -static int odb_ipc_cb__get_nth_ancestor(struct my_odb_ipc_state *state, - const char *command, size_t command_len, - ipc_server_reply_cb *reply_cb, - struct ipc_server_reply_data *reply_data) +static int odb_ipc_cb__get_ancestor(struct my_odb_ipc_state *state, + const char *command, size_t command_len, + ipc_server_reply_cb *reply_cb, + struct ipc_server_reply_data *reply_data) { - struct odb_over_ipc__get_nth_ancestor__request *req; - struct odb_over_ipc__get_nth_ancestor__response *resp; + struct odb_over_ipc__get_ancestor__request *req; + struct odb_over_ipc__get_ancestor__response *resp; const char *name; size_t name_len; int ret; @@ -269,7 +269,7 @@ static int odb_ipc_cb__get_nth_ancestor(struct my_odb_ipc_state *state, if (command_len < sizeof(*req)) BUG("incorrect size for binary data"); - req = (struct odb_over_ipc__get_nth_ancestor__request *)command; + req = (struct odb_over_ipc__get_ancestor__request *)command; name = command + sizeof(*req); name_len = command_len - sizeof(*req); @@ -278,7 +278,7 @@ static int odb_ipc_cb__get_nth_ancestor(struct my_odb_ipc_state *state, BUG("incorrect data length"); resp = xmalloc(sizeof(*resp)); - memcpy(&resp->key.key, "get-nth-ancestor", 11); + memcpy(&resp->key.key, "get-ancestor", 11); ret = get_nth_ancestor(the_repository, name, name_len, &resp->oid, req->generation); @@ -377,14 +377,14 @@ static int odb_ipc_cb(void *data, return 0; } - if (!strcmp(command, "get-nth-ancestor")) { + if (!strcmp(command, "get-ancestor")) { /* * A client has requested that we find the nth ancestpr of a * given object. */ trace2_region_enter("odb-daemon", "get-nth-ancestor", NULL); - ret = odb_ipc_cb__get_nth_ancestor(state, command, command_len, - reply_cb, reply_data); + ret = odb_ipc_cb__get_ancestor(state, command, command_len, + reply_cb, reply_data); trace2_region_leave("odb-daemon", "get-nth-ancestor", NULL); return 0; } diff --git a/object-name.c b/object-name.c index 9cd45b0163675e..5441c9b53b671b 100644 --- a/object-name.c +++ b/object-name.c @@ -1125,7 +1125,7 @@ enum get_oid_result get_nth_ancestor(struct repository *r, struct commit *commit; int ret; - if (odb_over_ipc__get_nth_ancestor(r, name, len, generation, result) == 0) + if (odb_over_ipc__get_ancestor(r, name, len, generation, result) == 0) return FOUND; ret = get_oid_1(r, name, len, &oid, GET_OID_COMMITTISH); diff --git a/odb-over-ipc.c b/odb-over-ipc.c index cbab474740e22c..f0342df1990659 100644 --- a/odb-over-ipc.c +++ b/odb-over-ipc.c @@ -311,12 +311,12 @@ int odb_over_ipc__get_parent(struct repository *r, const char *name, int len, return ret; } -int odb_over_ipc__get_nth_ancestor(struct repository *r, const char *name, - int len, int generation, - struct object_id *result) +int odb_over_ipc__get_ancestor(struct repository *r, const char *name, + int len, int generation, + struct object_id *result) { - struct odb_over_ipc__get_nth_ancestor__request req; - struct odb_over_ipc__get_nth_ancestor__response *resp; + struct odb_over_ipc__get_ancestor__request req; + struct odb_over_ipc__get_ancestor__response *resp; struct strbuf msg = STRBUF_INIT; struct strbuf answer = STRBUF_INIT; int ret; @@ -331,7 +331,7 @@ int odb_over_ipc__get_nth_ancestor(struct repository *r, const char *name, return -1; memset(&req, 0, sizeof(req)); - memcpy(req.key.key, "get-nth-ancestor", 16); + memcpy(req.key.key, "get-ancestor", 12); req.generation = generation; req.name_len = len; @@ -351,7 +351,7 @@ int odb_over_ipc__get_nth_ancestor(struct repository *r, const char *name, if (answer.len != sizeof(*resp)) BUG("incorrect size for binary data"); - resp = (struct odb_over_ipc__get_nth_ancestor__response *)answer.buf; + resp = (struct odb_over_ipc__get_ancestor__response *)answer.buf; oidcpy(result, &resp->oid); diff --git a/odb-over-ipc.h b/odb-over-ipc.h index 26a5111c197181..e84a2ce7b0491e 100644 --- a/odb-over-ipc.h +++ b/odb-over-ipc.h @@ -95,14 +95,14 @@ struct odb_over_ipc__get_parent__response struct object_id oid; }; -struct odb_over_ipc__get_nth_ancestor__request +struct odb_over_ipc__get_ancestor__request { struct odb_over_ipc__key key; int generation; int name_len; }; -struct odb_over_ipc__get_nth_ancestor__response +struct odb_over_ipc__get_ancestor__response { struct odb_over_ipc__key key; struct object_id oid; @@ -129,9 +129,9 @@ int odb_over_ipc__hash_object(struct repository *r, struct object_id *oid, int odb_over_ipc__get_parent(struct repository *r, const char *name, int len, int idx, struct object_id *result); -int odb_over_ipc__get_nth_ancestor(struct repository *r, const char *name, - int len, int generation, - struct object_id *result); +int odb_over_ipc__get_ancestor(struct repository *r, const char *name, + int len, int generation, + struct object_id *result); /* * Explicitly shutdown IPC connection to the `git odb--daemon` process.