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 "sigchain.h"
|
||||||
#include "string-list.h"
|
#include "string-list.h"
|
||||||
#include "strvec.h"
|
#include "strvec.h"
|
||||||
#include "tmp-objdir.h"
|
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
#include "trace2.h"
|
#include "trace2.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
@ -112,8 +111,6 @@ static enum {
|
||||||
} use_keepalive;
|
} use_keepalive;
|
||||||
static int keepalive_in_sec = 5;
|
static int keepalive_in_sec = 5;
|
||||||
|
|
||||||
static struct tmp_objdir *tmp_objdir;
|
|
||||||
|
|
||||||
static struct proc_receive_ref {
|
static struct proc_receive_ref {
|
||||||
unsigned int want_add:1,
|
unsigned int want_add:1,
|
||||||
want_delete: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,
|
static int run_receive_hook(struct command *commands,
|
||||||
const char *hook_name,
|
const char *hook_name,
|
||||||
int skip_broken,
|
int skip_broken,
|
||||||
|
struct odb_transaction *transaction,
|
||||||
const struct string_list *push_options)
|
const struct string_list *push_options)
|
||||||
{
|
{
|
||||||
struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
|
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");
|
strvec_push(&opt.env, "GIT_PUSH_OPTION_COUNT");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tmp_objdir)
|
if (transaction)
|
||||||
strvec_pushv(&opt.env, tmp_objdir_env(tmp_objdir));
|
odb_transaction_env(transaction, &opt.env);
|
||||||
|
|
||||||
prepare_push_cert_sha1(&opt);
|
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,
|
static void set_connectivity_errors(struct command *commands,
|
||||||
struct shallow_info *si)
|
struct shallow_info *si,
|
||||||
|
struct odb_transaction *transaction)
|
||||||
{
|
{
|
||||||
struct command *cmd;
|
struct command *cmd;
|
||||||
|
|
||||||
for (cmd = commands; cmd; cmd = cmd->next) {
|
for (cmd = commands; cmd; cmd = cmd->next) {
|
||||||
struct command *singleton = cmd;
|
struct command *singleton = cmd;
|
||||||
struct check_connected_options opt = CHECK_CONNECTED_INIT;
|
struct check_connected_options opt = CHECK_CONNECTED_INIT;
|
||||||
|
struct strvec env = STRVEC_INIT;
|
||||||
|
|
||||||
if (shallow_update && si->shallow_ref[cmd->index])
|
if (shallow_update && si->shallow_ref[cmd->index])
|
||||||
/* to be checked in update_shallow_ref() */
|
/* to be checked in update_shallow_ref() */
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
opt.env = tmp_objdir_env(tmp_objdir);
|
odb_transaction_env(transaction, &env);
|
||||||
|
opt.env = env.v;
|
||||||
|
|
||||||
if (!check_connected(command_singleton_iterator, &singleton,
|
if (!check_connected(command_singleton_iterator, &singleton,
|
||||||
&opt))
|
&opt))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
cmd->error_string = "missing necessary objects";
|
cmd->error_string = "missing necessary objects";
|
||||||
|
|
||||||
|
strvec_clear(&env);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2027,6 +2031,7 @@ cleanup:
|
||||||
static void execute_commands(struct command *commands,
|
static void execute_commands(struct command *commands,
|
||||||
const char *unpacker_error,
|
const char *unpacker_error,
|
||||||
struct shallow_info *si,
|
struct shallow_info *si,
|
||||||
|
struct odb_transaction *transaction,
|
||||||
const struct string_list *push_options)
|
const struct string_list *push_options)
|
||||||
{
|
{
|
||||||
struct check_connected_options opt = CHECK_CONNECTED_INIT;
|
struct check_connected_options opt = CHECK_CONNECTED_INIT;
|
||||||
|
|
@ -2043,6 +2048,8 @@ static void execute_commands(struct command *commands,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!skip_connectivity_check) {
|
if (!skip_connectivity_check) {
|
||||||
|
struct strvec env = STRVEC_INIT;
|
||||||
|
|
||||||
if (use_sideband) {
|
if (use_sideband) {
|
||||||
memset(&muxer, 0, sizeof(muxer));
|
memset(&muxer, 0, sizeof(muxer));
|
||||||
muxer.proc = copy_to_sideband;
|
muxer.proc = copy_to_sideband;
|
||||||
|
|
@ -2056,14 +2063,17 @@ static void execute_commands(struct command *commands,
|
||||||
data.si = si;
|
data.si = si;
|
||||||
opt.err_fd = err_fd;
|
opt.err_fd = err_fd;
|
||||||
opt.progress = err_fd && !quiet;
|
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";
|
opt.exclude_hidden_refs_section = "receive";
|
||||||
|
|
||||||
if (check_connected(iterate_receive_command_list, &data, &opt))
|
if (check_connected(iterate_receive_command_list, &data, &opt))
|
||||||
set_connectivity_errors(commands, si);
|
set_connectivity_errors(commands, si, transaction);
|
||||||
|
|
||||||
if (use_sideband)
|
if (use_sideband)
|
||||||
finish_async(&muxer);
|
finish_async(&muxer);
|
||||||
|
|
||||||
|
strvec_clear(&env);
|
||||||
}
|
}
|
||||||
|
|
||||||
reject_updates_to_hidden(commands);
|
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) {
|
for (cmd = commands; cmd; cmd = cmd->next) {
|
||||||
if (!cmd->error_string)
|
if (!cmd->error_string)
|
||||||
cmd->error_string = "pre-receive hook declined";
|
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
|
* 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.
|
* 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) {
|
for (cmd = commands; cmd; cmd = cmd->next) {
|
||||||
if (!cmd->error_string)
|
if (!cmd->error_string)
|
||||||
cmd->error_string = "unable to migrate objects to permanent storage";
|
cmd->error_string = "unable to migrate objects to permanent storage";
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
tmp_objdir = NULL;
|
|
||||||
|
|
||||||
check_aliased_updates(commands);
|
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));
|
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;
|
struct pack_header hdr;
|
||||||
const char *hdr_err;
|
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);
|
strvec_push(&child.args, alt_shallow_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp_objdir = tmp_objdir_create(the_repository, "incoming");
|
odb_transaction_env(transaction, &child.env);
|
||||||
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);
|
|
||||||
|
|
||||||
if (ntohl(hdr.hdr_entries) < unpack_limit) {
|
if (ntohl(hdr.hdr_entries) < unpack_limit) {
|
||||||
strvec_push(&child.args, "unpack-objects");
|
strvec_push(&child.args, "unpack-objects");
|
||||||
|
|
@ -2430,13 +2427,14 @@ static const char *unpack(int err_fd, struct shallow_info *si)
|
||||||
return NULL;
|
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;
|
struct async muxer;
|
||||||
const char *ret;
|
const char *ret;
|
||||||
|
|
||||||
if (!use_sideband)
|
if (!use_sideband)
|
||||||
return unpack(0, si);
|
return unpack(0, si, transaction);
|
||||||
|
|
||||||
use_keepalive = KEEPALIVE_AFTER_NUL;
|
use_keepalive = KEEPALIVE_AFTER_NUL;
|
||||||
memset(&muxer, 0, sizeof(muxer));
|
memset(&muxer, 0, sizeof(muxer));
|
||||||
|
|
@ -2445,7 +2443,7 @@ static const char *unpack_with_sideband(struct shallow_info *si)
|
||||||
if (start_async(&muxer))
|
if (start_async(&muxer))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
ret = unpack(muxer.in, si);
|
ret = unpack(muxer.in, si, transaction);
|
||||||
|
|
||||||
finish_async(&muxer);
|
finish_async(&muxer);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -2622,6 +2620,7 @@ int cmd_receive_pack(int argc,
|
||||||
struct oid_array ref = OID_ARRAY_INIT;
|
struct oid_array ref = OID_ARRAY_INIT;
|
||||||
struct shallow_info si;
|
struct shallow_info si;
|
||||||
struct packet_reader reader;
|
struct packet_reader reader;
|
||||||
|
struct odb_transaction *transaction = NULL;
|
||||||
|
|
||||||
struct option options[] = {
|
struct option options[] = {
|
||||||
OPT__QUIET(&quiet, N_("quiet")),
|
OPT__QUIET(&quiet, N_("quiet")),
|
||||||
|
|
@ -2706,11 +2705,14 @@ int cmd_receive_pack(int argc,
|
||||||
if (!si.nr_ours && !si.nr_theirs)
|
if (!si.nr_ours && !si.nr_theirs)
|
||||||
shallow_update = 0;
|
shallow_update = 0;
|
||||||
if (!delete_only(commands)) {
|
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);
|
update_shallow_info(commands, &si, &ref);
|
||||||
}
|
}
|
||||||
use_keepalive = KEEPALIVE_ALWAYS;
|
use_keepalive = KEEPALIVE_ALWAYS;
|
||||||
execute_commands(commands, unpack_status, &si,
|
execute_commands(commands, unpack_status, &si, transaction,
|
||||||
&push_options);
|
&push_options);
|
||||||
delete_tempfile(&pack_lockfile);
|
delete_tempfile(&pack_lockfile);
|
||||||
sigchain_push(SIGPIPE, SIG_IGN);
|
sigchain_push(SIGPIPE, SIG_IGN);
|
||||||
|
|
@ -2719,7 +2721,7 @@ int cmd_receive_pack(int argc,
|
||||||
else if (report_status)
|
else if (report_status)
|
||||||
report(commands, unpack_status);
|
report(commands, unpack_status);
|
||||||
sigchain_pop(SIGPIPE);
|
sigchain_pop(SIGPIPE);
|
||||||
run_receive_hook(commands, "post-receive", 1,
|
run_receive_hook(commands, "post-receive", 1, NULL,
|
||||||
&push_options);
|
&push_options);
|
||||||
run_update_post_hook(commands);
|
run_update_post_hook(commands);
|
||||||
free_commands(commands);
|
free_commands(commands);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue