Skip to content

Commit 6fbd60d

Browse files
committed
odb/transaction: add transaction interface to write packfiles
In git-receive-pack(1), the incoming packfile is written to the ODB via `unpack()`, which spawns git-index-pack(1) or git-unpack-objects(1) directly. With pluggable object databases, an alternative backend may need to handle writing packfile data differently though. Introduce `odb_transaction_write_pack()` as a generic interface to handle writing a packfile to a transaction and use the logic from `unpack()` as the "files" backend implementation. Note that when storing the objects as a packfile, git-index-pack(1) also writes a ".keep" lockfile next to it to prevent a concurrent repack from removing the new pack prior to reference updates being performed. The "files" transaction backend is responsible for managing these ".keep" files and removes them post-commit once the transaction is finalized. Call sites in git-receive-pack(1) are updated accordingly. Signed-off-by: Justin Tobler <jltobler@gmail.com>
1 parent 94d9ba8 commit 6fbd60d

4 files changed

Lines changed: 245 additions & 157 deletions

File tree

builtin/receive-pack.c

Lines changed: 3 additions & 157 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,13 @@
1515
#include "gpg-interface.h"
1616
#include "hex.h"
1717
#include "hook.h"
18-
#include "lockfile.h"
1918
#include "object.h"
2019
#include "object-file.h"
2120
#include "object-name.h"
2221
#include "odb.h"
2322
#include "oid-array.h"
2423
#include "oidset.h"
2524
#include "pack.h"
26-
#include "packfile.h"
2725
#include "parse-options.h"
2826
#include "pkt-line.h"
2927
#include "protocol.h"
@@ -2292,162 +2290,11 @@ static void read_push_options(struct packet_reader *reader,
22922290
}
22932291
}
22942292

2295-
static const char *parse_pack_header(struct pack_header *hdr, int pack_fd)
2296-
{
2297-
switch (read_pack_header(pack_fd, hdr)) {
2298-
case PH_ERROR_EOF:
2299-
return "eof before pack header was fully read";
2300-
2301-
case PH_ERROR_PACK_SIGNATURE:
2302-
return "protocol error (pack signature mismatch detected)";
2303-
2304-
case PH_ERROR_PROTOCOL:
2305-
return "protocol error (pack version unsupported)";
2306-
2307-
default:
2308-
return "unknown error in parse_pack_header";
2309-
2310-
case 0:
2311-
return NULL;
2312-
}
2313-
}
2314-
2315-
static struct tempfile *pack_lockfile;
2316-
2317-
static void push_header_arg(struct strvec *args, struct pack_header *hdr)
2318-
{
2319-
strvec_pushf(args, "--pack_header=%"PRIu32",%"PRIu32,
2320-
ntohl(hdr->hdr_version), ntohl(hdr->hdr_entries));
2321-
}
2322-
2323-
static unsigned int get_unpack_limit(struct repository *repo)
2324-
{
2325-
unsigned int limit = 100;
2326-
2327-
repo_config_get_uint(repo, "transfer.unpacklimit", &limit);
2328-
repo_config_get_uint(repo, "receive.unpacklimit", &limit);
2329-
2330-
return limit;
2331-
}
2332-
2333-
struct unpack_opts {
2334-
const char *fsck_msg_types;
2335-
const char *shallow_file;
2336-
off_t max_input_size;
2337-
int fsck_objects;
2338-
int reject_thin;
2339-
int err_fd;
2340-
int quiet;
2341-
};
2342-
2343-
static int unpack(struct odb_transaction *transaction, int pack_fd,
2344-
struct strbuf *err_msg, const struct unpack_opts *opts)
2345-
{
2346-
struct pack_header hdr;
2347-
const char *hdr_err;
2348-
int status;
2349-
struct child_process child = CHILD_PROCESS_INIT;
2350-
int err_fd = opts->err_fd;
2351-
2352-
hdr_err = parse_pack_header(&hdr, pack_fd);
2353-
if (hdr_err) {
2354-
if (err_fd > 0)
2355-
close(err_fd);
2356-
strbuf_addstr(err_msg, hdr_err);
2357-
return -1;
2358-
}
2359-
2360-
if (opts->shallow_file) {
2361-
strvec_push(&child.args, "--shallow-file");
2362-
strvec_push(&child.args, opts->shallow_file);
2363-
}
2364-
2365-
odb_transaction_env(transaction, &child.env);
2366-
2367-
if (ntohl(hdr.hdr_entries) < get_unpack_limit(the_repository)) {
2368-
strvec_push(&child.args, "unpack-objects");
2369-
push_header_arg(&child.args, &hdr);
2370-
if (opts->quiet)
2371-
strvec_push(&child.args, "-q");
2372-
if (opts->fsck_objects)
2373-
strvec_pushf(&child.args, "--strict%s",
2374-
opts->fsck_msg_types);
2375-
if (opts->max_input_size)
2376-
strvec_pushf(&child.args, "--max-input-size=%"PRIuMAX,
2377-
(uintmax_t)opts->max_input_size);
2378-
child.no_stdout = 1;
2379-
child.in = pack_fd;
2380-
child.err = err_fd;
2381-
child.git_cmd = 1;
2382-
status = run_command(&child);
2383-
if (status) {
2384-
strbuf_addstr(err_msg, "unpack-objects abnormal exit");
2385-
return -1;
2386-
}
2387-
} else {
2388-
char hostname[HOST_NAME_MAX + 1];
2389-
char *lockfile;
2390-
2391-
strvec_pushl(&child.args, "index-pack", "--stdin", NULL);
2392-
push_header_arg(&child.args, &hdr);
2393-
2394-
if (xgethostname(hostname, sizeof(hostname)))
2395-
xsnprintf(hostname, sizeof(hostname), "localhost");
2396-
strvec_pushf(&child.args,
2397-
"--keep=receive-pack %"PRIuMAX" on %s",
2398-
(uintmax_t)getpid(),
2399-
hostname);
2400-
2401-
if (!opts->quiet && err_fd)
2402-
strvec_push(&child.args, "--show-resolving-progress");
2403-
if (err_fd)
2404-
strvec_push(&child.args, "--report-end-of-input");
2405-
if (opts->fsck_objects)
2406-
strvec_pushf(&child.args, "--strict%s",
2407-
opts->fsck_msg_types);
2408-
if (!opts->reject_thin)
2409-
strvec_push(&child.args, "--fix-thin");
2410-
if (opts->max_input_size)
2411-
strvec_pushf(&child.args, "--max-input-size=%"PRIuMAX,
2412-
(uintmax_t)opts->max_input_size);
2413-
child.out = -1;
2414-
child.in = pack_fd;
2415-
child.err = err_fd;
2416-
child.git_cmd = 1;
2417-
status = start_command(&child);
2418-
if (status) {
2419-
strbuf_addstr(err_msg, "index-pack fork failed");
2420-
return -1;
2421-
}
2422-
2423-
/*
2424-
* The lockfile filepath is expected to be the final location of
2425-
* the ".keep" file after being migrated to the main ODB source.
2426-
* This ensures the lockfile can be found and removed later
2427-
* after the ODB transaction has been committed.
2428-
*/
2429-
lockfile = index_pack_lockfile(transaction->source, child.out, NULL);
2430-
if (lockfile) {
2431-
pack_lockfile = register_tempfile(lockfile);
2432-
free(lockfile);
2433-
}
2434-
close(child.out);
2435-
2436-
status = finish_command(&child);
2437-
if (status) {
2438-
strbuf_addstr(err_msg, "index-pack abnormal exit");
2439-
return -1;
2440-
}
2441-
odb_reprepare(the_repository->objects);
2442-
}
2443-
return 0;
2444-
}
2445-
24462293
static int unpack_with_sideband(struct odb_transaction *transaction,
24472294
const char *shallow_file,
24482295
struct strbuf *err_msg)
24492296
{
2450-
struct unpack_opts opts = {
2297+
struct odb_transaction_write_pack_opts opts = {
24512298
.fsck_objects = (receive_fsck_objects >= 0
24522299
? receive_fsck_objects
24532300
: transfer_fsck_objects >= 0
@@ -2463,7 +2310,7 @@ static int unpack_with_sideband(struct odb_transaction *transaction,
24632310
int ret;
24642311

24652312
if (!use_sideband)
2466-
return unpack(transaction, 0, err_msg, &opts);
2313+
return odb_transaction_write_pack(transaction, 0, err_msg, &opts);
24672314

24682315
use_keepalive = KEEPALIVE_AFTER_NUL;
24692316
memset(&muxer, 0, sizeof(muxer));
@@ -2473,7 +2320,7 @@ static int unpack_with_sideband(struct odb_transaction *transaction,
24732320
return 0;
24742321

24752322
opts.err_fd = muxer.in;
2476-
ret = unpack(transaction, 0, err_msg, &opts);
2323+
ret = odb_transaction_write_pack(transaction, 0, err_msg, &opts);
24772324

24782325
finish_async(&muxer);
24792326
return ret;
@@ -2749,7 +2596,6 @@ int cmd_receive_pack(int argc,
27492596
&push_options);
27502597
if (odb_transaction_finalize(transaction))
27512598
strbuf_addstr(&unpack_status, "unable to finalize object transaction");
2752-
delete_tempfile(&pack_lockfile);
27532599
sigchain_push(SIGPIPE, SIG_IGN);
27542600
if (report_status_v2)
27552601
report_v2(commands, &unpack_status);

0 commit comments

Comments
 (0)