builtin/receive-pack: stage incoming objects via ODB transactions
Objects received by git-receive-pack(1) are quarantined in a temporary "incoming" directory and migrated into the object database prior to the reference updates. The quarantine is currently managed through `tmp_objdir` directly. In a pluggable ODB future, how exactly an object gets written to a transaction may vary for a given ODB source. Refactor git-receive-pack(1) to use the ODB transaction interfaces to manage the object staging area in a more agnostic manner accordingly. Note that the ODB transaction is now responsible for managing the primary and alternate ODBs for the repository. One small change as a result is that the temporary directory is now applied as the primary ODB in the main process instead of an alternate. This does not change anything for git-receive-pack(1) though because it only needs access to the newly written objects and doesn't care how exactly it is set up. Signed-off-by: Justin Tobler <jltobler@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>main
parent
6c242569c1
commit
bdee7b3013
|
|
@ -37,7 +37,6 @@
|
|||
#include "sigchain.h"
|
||||
#include "string-list.h"
|
||||
#include "strvec.h"
|
||||
#include "tmp-objdir.h"
|
||||
#include "trace.h"
|
||||
#include "trace2.h"
|
||||
#include "version.h"
|
||||
|
|
@ -112,8 +111,6 @@ static enum {
|
|||
} use_keepalive;
|
||||
static int keepalive_in_sec = 5;
|
||||
|
||||
static struct tmp_objdir *tmp_objdir;
|
||||
|
||||
static struct proc_receive_ref {
|
||||
unsigned int want_add:1,
|
||||
want_delete:1,
|
||||
|
|
@ -926,6 +923,7 @@ static void receive_hook_feed_state_free(void *data)
|
|||
static int run_receive_hook(struct command *commands,
|
||||
const char *hook_name,
|
||||
int skip_broken,
|
||||
struct odb_transaction *transaction,
|
||||
const struct string_list *push_options)
|
||||
{
|
||||
struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
|
||||
|
|
@ -959,8 +957,8 @@ static int run_receive_hook(struct command *commands,
|
|||
strvec_push(&opt.env, "GIT_PUSH_OPTION_COUNT");
|
||||
}
|
||||
|
||||
if (tmp_objdir)
|
||||
strvec_pushv(&opt.env, tmp_objdir_env(tmp_objdir));
|
||||
if (transaction)
|
||||
odb_transaction_env(transaction, &opt.env);
|
||||
|
||||
prepare_push_cert_sha1(&opt);
|
||||
|
||||
|
|
@ -1789,24 +1787,30 @@ static const struct object_id *command_singleton_iterator(void *cb_data)
|
|||
}
|
||||
|
||||
static void set_connectivity_errors(struct command *commands,
|
||||
struct shallow_info *si)
|
||||
struct shallow_info *si,
|
||||
struct odb_transaction *transaction)
|
||||
{
|
||||
struct command *cmd;
|
||||
|
||||
for (cmd = commands; cmd; cmd = cmd->next) {
|
||||
struct command *singleton = cmd;
|
||||
struct check_connected_options opt = CHECK_CONNECTED_INIT;
|
||||
struct strvec env = STRVEC_INIT;
|
||||
|
||||
if (shallow_update && si->shallow_ref[cmd->index])
|
||||
/* to be checked in update_shallow_ref() */
|
||||
continue;
|
||||
|
||||
opt.env = tmp_objdir_env(tmp_objdir);
|
||||
odb_transaction_env(transaction, &env);
|
||||
opt.env = env.v;
|
||||
|
||||
if (!check_connected(command_singleton_iterator, &singleton,
|
||||
&opt))
|
||||
continue;
|
||||
|
||||
cmd->error_string = "missing necessary objects";
|
||||
|
||||
strvec_clear(&env);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2027,6 +2031,7 @@ cleanup:
|
|||
static void execute_commands(struct command *commands,
|
||||
const char *unpacker_error,
|
||||
struct shallow_info *si,
|
||||
struct odb_transaction *transaction,
|
||||
const struct string_list *push_options)
|
||||
{
|
||||
struct check_connected_options opt = CHECK_CONNECTED_INIT;
|
||||
|
|
@ -2043,6 +2048,8 @@ static void execute_commands(struct command *commands,
|
|||
}
|
||||
|
||||
if (!skip_connectivity_check) {
|
||||
struct strvec env = STRVEC_INIT;
|
||||
|
||||
if (use_sideband) {
|
||||
memset(&muxer, 0, sizeof(muxer));
|
||||
muxer.proc = copy_to_sideband;
|
||||
|
|
@ -2056,14 +2063,17 @@ static void execute_commands(struct command *commands,
|
|||
data.si = si;
|
||||
opt.err_fd = err_fd;
|
||||
opt.progress = err_fd && !quiet;
|
||||
opt.env = tmp_objdir_env(tmp_objdir);
|
||||
odb_transaction_env(transaction, &env);
|
||||
opt.env = env.v;
|
||||
opt.exclude_hidden_refs_section = "receive";
|
||||
|
||||
if (check_connected(iterate_receive_command_list, &data, &opt))
|
||||
set_connectivity_errors(commands, si);
|
||||
set_connectivity_errors(commands, si, transaction);
|
||||
|
||||
if (use_sideband)
|
||||
finish_async(&muxer);
|
||||
|
||||
strvec_clear(&env);
|
||||
}
|
||||
|
||||
reject_updates_to_hidden(commands);
|
||||
|
|
@ -2084,7 +2094,7 @@ static void execute_commands(struct command *commands,
|
|||
}
|
||||
}
|
||||
|
||||
if (run_receive_hook(commands, "pre-receive", 0, push_options)) {
|
||||
if (run_receive_hook(commands, "pre-receive", 0, transaction, push_options)) {
|
||||
for (cmd = commands; cmd; cmd = cmd->next) {
|
||||
if (!cmd->error_string)
|
||||
cmd->error_string = "pre-receive hook declined";
|
||||
|
|
@ -2105,14 +2115,13 @@ static void execute_commands(struct command *commands,
|
|||
* Now we'll start writing out refs, which means the objects need
|
||||
* to be in their final positions so that other processes can see them.
|
||||
*/
|
||||
if (tmp_objdir_migrate(tmp_objdir) < 0) {
|
||||
if (odb_transaction_commit(transaction)) {
|
||||
for (cmd = commands; cmd; cmd = cmd->next) {
|
||||
if (!cmd->error_string)
|
||||
cmd->error_string = "unable to migrate objects to permanent storage";
|
||||
}
|
||||
return;
|
||||
}
|
||||
tmp_objdir = NULL;
|
||||
|
||||
check_aliased_updates(commands);
|
||||
|
||||
|
|
@ -2325,7 +2334,8 @@ static void push_header_arg(struct strvec *args, struct pack_header *hdr)
|
|||
ntohl(hdr->hdr_version), ntohl(hdr->hdr_entries));
|
||||
}
|
||||
|
||||
static const char *unpack(int err_fd, struct shallow_info *si)
|
||||
static const char *unpack(int err_fd, struct shallow_info *si,
|
||||
struct odb_transaction *transaction)
|
||||
{
|
||||
struct pack_header hdr;
|
||||
const char *hdr_err;
|
||||
|
|
@ -2350,20 +2360,7 @@ static const char *unpack(int err_fd, struct shallow_info *si)
|
|||
strvec_push(&child.args, alt_shallow_file);
|
||||
}
|
||||
|
||||
tmp_objdir = tmp_objdir_create(the_repository, "incoming");
|
||||
if (!tmp_objdir) {
|
||||
if (err_fd > 0)
|
||||
close(err_fd);
|
||||
return "unable to create temporary object directory";
|
||||
}
|
||||
strvec_pushv(&child.env, tmp_objdir_env(tmp_objdir));
|
||||
|
||||
/*
|
||||
* Normally we just pass the tmp_objdir environment to the child
|
||||
* processes that do the heavy lifting, but we may need to see these
|
||||
* objects ourselves to set up shallow information.
|
||||
*/
|
||||
tmp_objdir_add_as_alternate(tmp_objdir);
|
||||
odb_transaction_env(transaction, &child.env);
|
||||
|
||||
if (ntohl(hdr.hdr_entries) < unpack_limit) {
|
||||
strvec_push(&child.args, "unpack-objects");
|
||||
|
|
@ -2430,13 +2427,14 @@ static const char *unpack(int err_fd, struct shallow_info *si)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static const char *unpack_with_sideband(struct shallow_info *si)
|
||||
static const char *unpack_with_sideband(struct shallow_info *si,
|
||||
struct odb_transaction *transaction)
|
||||
{
|
||||
struct async muxer;
|
||||
const char *ret;
|
||||
|
||||
if (!use_sideband)
|
||||
return unpack(0, si);
|
||||
return unpack(0, si, transaction);
|
||||
|
||||
use_keepalive = KEEPALIVE_AFTER_NUL;
|
||||
memset(&muxer, 0, sizeof(muxer));
|
||||
|
|
@ -2445,7 +2443,7 @@ static const char *unpack_with_sideband(struct shallow_info *si)
|
|||
if (start_async(&muxer))
|
||||
return NULL;
|
||||
|
||||
ret = unpack(muxer.in, si);
|
||||
ret = unpack(muxer.in, si, transaction);
|
||||
|
||||
finish_async(&muxer);
|
||||
return ret;
|
||||
|
|
@ -2622,6 +2620,7 @@ int cmd_receive_pack(int argc,
|
|||
struct oid_array ref = OID_ARRAY_INIT;
|
||||
struct shallow_info si;
|
||||
struct packet_reader reader;
|
||||
struct odb_transaction *transaction = NULL;
|
||||
|
||||
struct option options[] = {
|
||||
OPT__QUIET(&quiet, N_("quiet")),
|
||||
|
|
@ -2706,11 +2705,14 @@ int cmd_receive_pack(int argc,
|
|||
if (!si.nr_ours && !si.nr_theirs)
|
||||
shallow_update = 0;
|
||||
if (!delete_only(commands)) {
|
||||
unpack_status = unpack_with_sideband(&si);
|
||||
if (odb_transaction_begin(the_repository->objects, &transaction, ODB_TRANSACTION_RECEIVE))
|
||||
unpack_status = "unable to start object transaction";
|
||||
else
|
||||
unpack_status = unpack_with_sideband(&si, transaction);
|
||||
update_shallow_info(commands, &si, &ref);
|
||||
}
|
||||
use_keepalive = KEEPALIVE_ALWAYS;
|
||||
execute_commands(commands, unpack_status, &si,
|
||||
execute_commands(commands, unpack_status, &si, transaction,
|
||||
&push_options);
|
||||
delete_tempfile(&pack_lockfile);
|
||||
sigchain_push(SIGPIPE, SIG_IGN);
|
||||
|
|
@ -2719,7 +2721,7 @@ int cmd_receive_pack(int argc,
|
|||
else if (report_status)
|
||||
report(commands, unpack_status);
|
||||
sigchain_pop(SIGPIPE);
|
||||
run_receive_hook(commands, "post-receive", 1,
|
||||
run_receive_hook(commands, "post-receive", 1, NULL,
|
||||
&push_options);
|
||||
run_update_post_hook(commands);
|
||||
free_commands(commands);
|
||||
|
|
|
|||
Loading…
Reference in New Issue