diff --git a/builtin/odb--daemon.c b/builtin/odb--daemon.c index e73c5f8ac5794d..4f11dd136d09ae 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,93 @@ 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; +} + +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_ancestor__request *req; + struct odb_over_ipc__get_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_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-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. @@ -277,6 +365,30 @@ 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; + } + + 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_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 523af6f64f3351..5441c9b53b671b 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 *); @@ -1081,18 +1082,22 @@ 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, - 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; @@ -1111,15 +1116,18 @@ static 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; int ret; + 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); if (ret) return ret; diff --git a/object-name.h b/object-name.h index 064ddc97d1fe99..d33022847d9fe7 100644 --- a/object-name.h +++ b/object-name.h @@ -121,6 +121,15 @@ 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); + +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 diff --git a/odb-over-ipc.c b/odb-over-ipc.c index 1d342b71ebbebd..f0342df1990659 100644 --- a/odb-over-ipc.c +++ b/odb-over-ipc.c @@ -264,4 +264,99 @@ 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; +} + +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_ancestor__request req; + struct odb_over_ipc__get_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-ancestor", 12); + 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_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 8fc1f27200731d..e84a2ce7b0491e 100644 --- a/odb-over-ipc.h +++ b/odb-over-ipc.h @@ -82,6 +82,32 @@ 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; +}; + +struct odb_over_ipc__get_ancestor__request +{ + struct odb_over_ipc__key key; + int generation; + int name_len; +}; + +struct odb_over_ipc__get_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 @@ -100,6 +126,13 @@ 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); + +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. * The connection is implicitly created upon the first request and we