Merge branch 'ew/fast-import-unpack-limit'
"git fast-import" learned the same performance trick to avoid creating too small a packfile as "git fetch" and "git push" have, using *.unpackLimit configuration. * ew/fast-import-unpack-limit: fast-import: invalidate pack_id references after loosening fast-import: implement unpack limitmaint
commit
8d6a7e9a19
|
@ -1189,6 +1189,15 @@ difftool.<tool>.cmd::
|
|||
difftool.prompt::
|
||||
Prompt before each invocation of the diff tool.
|
||||
|
||||
fastimport.unpackLimit::
|
||||
If the number of objects imported by linkgit:git-fast-import[1]
|
||||
is below this limit, then the objects will be unpacked into
|
||||
loose object files. However if the number of imported objects
|
||||
equals or exceeds this limit then the pack will be stored as a
|
||||
pack. Storing the pack from a fast-import can make the import
|
||||
operation complete faster, especially on slow filesystems. If
|
||||
not set, the value of `transfer.unpackLimit` is used instead.
|
||||
|
||||
fetch.recurseSubmodules::
|
||||
This option can be either set to a boolean value or to 'on-demand'.
|
||||
Setting it to a boolean changes the behavior of fetch and pull to
|
||||
|
|
|
@ -136,6 +136,8 @@ Performance and Compression Tuning
|
|||
Maximum size of each output packfile.
|
||||
The default is unlimited.
|
||||
|
||||
fastimport.unpackLimit::
|
||||
See linkgit:git-config[1]
|
||||
|
||||
Performance
|
||||
-----------
|
||||
|
|
|
@ -166,6 +166,7 @@ Format of STDIN stream:
|
|||
#include "quote.h"
|
||||
#include "exec_cmd.h"
|
||||
#include "dir.h"
|
||||
#include "run-command.h"
|
||||
|
||||
#define PACK_ID_BITS 16
|
||||
#define MAX_PACK_ID ((1<<PACK_ID_BITS)-1)
|
||||
|
@ -282,6 +283,7 @@ struct recent_command {
|
|||
/* Configured limits on output */
|
||||
static unsigned long max_depth = 10;
|
||||
static off_t max_packsize;
|
||||
static int unpack_limit = 100;
|
||||
static int force_update;
|
||||
static int pack_compression_level = Z_DEFAULT_COMPRESSION;
|
||||
static int pack_compression_seen;
|
||||
|
@ -596,6 +598,33 @@ static struct object_entry *insert_object(unsigned char *sha1)
|
|||
return e;
|
||||
}
|
||||
|
||||
static void invalidate_pack_id(unsigned int id)
|
||||
{
|
||||
unsigned int h;
|
||||
unsigned long lu;
|
||||
struct tag *t;
|
||||
|
||||
for (h = 0; h < ARRAY_SIZE(object_table); h++) {
|
||||
struct object_entry *e;
|
||||
|
||||
for (e = object_table[h]; e; e = e->next)
|
||||
if (e->pack_id == id)
|
||||
e->pack_id = MAX_PACK_ID;
|
||||
}
|
||||
|
||||
for (lu = 0; lu < branch_table_sz; lu++) {
|
||||
struct branch *b;
|
||||
|
||||
for (b = branch_table[lu]; b; b = b->table_next_branch)
|
||||
if (b->pack_id == id)
|
||||
b->pack_id = MAX_PACK_ID;
|
||||
}
|
||||
|
||||
for (t = first_tag; t; t = t->next_tag)
|
||||
if (t->pack_id == id)
|
||||
t->pack_id = MAX_PACK_ID;
|
||||
}
|
||||
|
||||
static unsigned int hc_str(const char *s, size_t len)
|
||||
{
|
||||
unsigned int r = 0;
|
||||
|
@ -951,6 +980,23 @@ static void unkeep_all_packs(void)
|
|||
}
|
||||
}
|
||||
|
||||
static int loosen_small_pack(const struct packed_git *p)
|
||||
{
|
||||
struct child_process unpack = CHILD_PROCESS_INIT;
|
||||
|
||||
if (lseek(p->pack_fd, 0, SEEK_SET) < 0)
|
||||
die_errno("Failed seeking to start of '%s'", p->pack_name);
|
||||
|
||||
unpack.in = p->pack_fd;
|
||||
unpack.git_cmd = 1;
|
||||
unpack.stdout_to_stderr = 1;
|
||||
argv_array_push(&unpack.args, "unpack-objects");
|
||||
if (!show_stats)
|
||||
argv_array_push(&unpack.args, "-q");
|
||||
|
||||
return run_command(&unpack);
|
||||
}
|
||||
|
||||
static void end_packfile(void)
|
||||
{
|
||||
static int running;
|
||||
|
@ -973,6 +1019,14 @@ static void end_packfile(void)
|
|||
fixup_pack_header_footer(pack_data->pack_fd, pack_data->sha1,
|
||||
pack_data->pack_name, object_count,
|
||||
cur_pack_sha1, pack_size);
|
||||
|
||||
if (object_count <= unpack_limit) {
|
||||
if (!loosen_small_pack(pack_data)) {
|
||||
invalidate_pack_id(pack_id);
|
||||
goto discard_pack;
|
||||
}
|
||||
}
|
||||
|
||||
close(pack_data->pack_fd);
|
||||
idx_name = keep_pack(create_index());
|
||||
|
||||
|
@ -1003,6 +1057,7 @@ static void end_packfile(void)
|
|||
pack_id++;
|
||||
}
|
||||
else {
|
||||
discard_pack:
|
||||
close(pack_data->pack_fd);
|
||||
unlink_or_warn(pack_data->pack_name);
|
||||
}
|
||||
|
@ -3320,6 +3375,7 @@ static void parse_option(const char *option)
|
|||
static void git_pack_config(void)
|
||||
{
|
||||
int indexversion_value;
|
||||
int limit;
|
||||
unsigned long packsizelimit_value;
|
||||
|
||||
if (!git_config_get_ulong("pack.depth", &max_depth)) {
|
||||
|
@ -3344,6 +3400,11 @@ static void git_pack_config(void)
|
|||
if (!git_config_get_ulong("pack.packsizelimit", &packsizelimit_value))
|
||||
max_packsize = packsizelimit_value;
|
||||
|
||||
if (!git_config_get_int("fastimport.unpacklimit", &limit))
|
||||
unpack_limit = limit;
|
||||
else if (!git_config_get_int("transfer.unpacklimit", &limit))
|
||||
unpack_limit = limit;
|
||||
|
||||
git_config(git_default_config, NULL);
|
||||
}
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@ echo "$@"'
|
|||
###
|
||||
|
||||
test_expect_success 'empty stream succeeds' '
|
||||
git config fastimport.unpackLimit 0 &&
|
||||
git fast-import </dev/null
|
||||
'
|
||||
|
||||
|
@ -2690,6 +2691,7 @@ test_expect_success 'R: blob bigger than threshold' '
|
|||
echo >>input &&
|
||||
|
||||
test_create_repo R &&
|
||||
git --git-dir=R/.git config fastimport.unpackLimit 0 &&
|
||||
git --git-dir=R/.git fast-import --big-file-threshold=1 <input
|
||||
'
|
||||
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
#!/bin/sh
|
||||
test_description='test git fast-import unpack limit'
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success 'create loose objects on import' '
|
||||
test_tick &&
|
||||
cat >input <<-INPUT_END &&
|
||||
commit refs/heads/master
|
||||
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
|
||||
data <<COMMIT
|
||||
initial
|
||||
COMMIT
|
||||
|
||||
done
|
||||
INPUT_END
|
||||
|
||||
git -c fastimport.unpackLimit=2 fast-import --done <input &&
|
||||
git fsck --no-progress &&
|
||||
test $(find .git/objects/?? -type f | wc -l) -eq 2 &&
|
||||
test $(find .git/objects/pack -type f | wc -l) -eq 0
|
||||
'
|
||||
|
||||
test_expect_success 'bigger packs are preserved' '
|
||||
test_tick &&
|
||||
cat >input <<-INPUT_END &&
|
||||
commit refs/heads/master
|
||||
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
|
||||
data <<COMMIT
|
||||
incremental should create a pack
|
||||
COMMIT
|
||||
from refs/heads/master^0
|
||||
|
||||
commit refs/heads/branch
|
||||
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
|
||||
data <<COMMIT
|
||||
branch
|
||||
COMMIT
|
||||
|
||||
done
|
||||
INPUT_END
|
||||
|
||||
git -c fastimport.unpackLimit=2 fast-import --done <input &&
|
||||
git fsck --no-progress &&
|
||||
test $(find .git/objects/?? -type f | wc -l) -eq 2 &&
|
||||
test $(find .git/objects/pack -type f | wc -l) -eq 2
|
||||
'
|
||||
|
||||
test_expect_success 'lookups after checkpoint works' '
|
||||
hello_id=$(echo hello | git hash-object --stdin -t blob) &&
|
||||
id="$GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE" &&
|
||||
before=$(git rev-parse refs/heads/master^0) &&
|
||||
(
|
||||
cat <<-INPUT_END &&
|
||||
blob
|
||||
mark :1
|
||||
data 6
|
||||
hello
|
||||
|
||||
commit refs/heads/master
|
||||
mark :2
|
||||
committer $id
|
||||
data <<COMMIT
|
||||
checkpoint after this
|
||||
COMMIT
|
||||
from refs/heads/master^0
|
||||
M 100644 :1 hello
|
||||
|
||||
# pre-checkpoint
|
||||
cat-blob :1
|
||||
cat-blob $hello_id
|
||||
checkpoint
|
||||
# post-checkpoint
|
||||
cat-blob :1
|
||||
cat-blob $hello_id
|
||||
INPUT_END
|
||||
|
||||
n=0 &&
|
||||
from=$before &&
|
||||
while test x"$from" = x"$before"
|
||||
do
|
||||
if test $n -gt 30
|
||||
then
|
||||
echo >&2 "checkpoint did not update branch"
|
||||
exit 1
|
||||
else
|
||||
n=$(($n + 1))
|
||||
fi &&
|
||||
sleep 1 &&
|
||||
from=$(git rev-parse refs/heads/master^0)
|
||||
done &&
|
||||
cat <<-INPUT_END &&
|
||||
commit refs/heads/master
|
||||
committer $id
|
||||
data <<COMMIT
|
||||
make sure from "unpacked sha1 reference" works, too
|
||||
COMMIT
|
||||
from $from
|
||||
INPUT_END
|
||||
echo done
|
||||
) | git -c fastimport.unpackLimit=100 fast-import --done &&
|
||||
test $(find .git/objects/?? -type f | wc -l) -eq 6 &&
|
||||
test $(find .git/objects/pack -type f | wc -l) -eq 2
|
||||
'
|
||||
|
||||
test_done
|
Loading…
Reference in New Issue