зеркало из https://github.com/microsoft/git.git
count-objects: report garbage files in pack directory too
prepare_packed_git_one() is modified to allow count-objects to hook a report function to so we don't need to duplicate the pack searching logic in count-objects.c. When report_pack_garbage is NULL, the overhead is insignificant. The garbage is reported with warning() instead of error() in packed garbage case because it's not an error to have garbage. Loose garbage is still reported as errors and will be converted to warnings later. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Родитель
d90906a902
Коммит
543c5caa6c
|
@ -33,8 +33,8 @@ size-pack: disk space consumed by the packs, in KiB
|
||||||
prune-packable: the number of loose objects that are also present in
|
prune-packable: the number of loose objects that are also present in
|
||||||
the packs. These objects could be pruned using `git prune-packed`.
|
the packs. These objects could be pruned using `git prune-packed`.
|
||||||
+
|
+
|
||||||
garbage: the number of files in loose object database that are not
|
garbage: the number of files in object database that are not valid
|
||||||
valid loose objects
|
loose objects nor valid packs
|
||||||
|
|
||||||
GIT
|
GIT
|
||||||
---
|
---
|
||||||
|
|
|
@ -9,6 +9,14 @@
|
||||||
#include "builtin.h"
|
#include "builtin.h"
|
||||||
#include "parse-options.h"
|
#include "parse-options.h"
|
||||||
|
|
||||||
|
static unsigned long garbage;
|
||||||
|
|
||||||
|
static void real_report_garbage(const char *desc, const char *path)
|
||||||
|
{
|
||||||
|
warning("%s: %s", desc, path);
|
||||||
|
garbage++;
|
||||||
|
}
|
||||||
|
|
||||||
static void count_objects(DIR *d, char *path, int len, int verbose,
|
static void count_objects(DIR *d, char *path, int len, int verbose,
|
||||||
unsigned long *loose,
|
unsigned long *loose,
|
||||||
off_t *loose_size,
|
off_t *loose_size,
|
||||||
|
@ -76,7 +84,7 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)
|
||||||
const char *objdir = get_object_directory();
|
const char *objdir = get_object_directory();
|
||||||
int len = strlen(objdir);
|
int len = strlen(objdir);
|
||||||
char *path = xmalloc(len + 50);
|
char *path = xmalloc(len + 50);
|
||||||
unsigned long loose = 0, packed = 0, packed_loose = 0, garbage = 0;
|
unsigned long loose = 0, packed = 0, packed_loose = 0;
|
||||||
off_t loose_size = 0;
|
off_t loose_size = 0;
|
||||||
struct option opts[] = {
|
struct option opts[] = {
|
||||||
OPT__VERBOSE(&verbose, N_("be verbose")),
|
OPT__VERBOSE(&verbose, N_("be verbose")),
|
||||||
|
@ -87,6 +95,8 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)
|
||||||
/* we do not take arguments other than flags for now */
|
/* we do not take arguments other than flags for now */
|
||||||
if (argc)
|
if (argc)
|
||||||
usage_with_options(count_objects_usage, opts);
|
usage_with_options(count_objects_usage, opts);
|
||||||
|
if (verbose)
|
||||||
|
report_garbage = real_report_garbage;
|
||||||
memcpy(path, objdir, len);
|
memcpy(path, objdir, len);
|
||||||
if (len && objdir[len-1] != '/')
|
if (len && objdir[len-1] != '/')
|
||||||
path[len++] = '/';
|
path[len++] = '/';
|
||||||
|
|
3
cache.h
3
cache.h
|
@ -1057,6 +1057,9 @@ extern const char *parse_feature_value(const char *feature_list, const char *fea
|
||||||
|
|
||||||
extern struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path);
|
extern struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path);
|
||||||
|
|
||||||
|
/* A hook for count-objects to report invalid files in pack directory */
|
||||||
|
extern void (*report_garbage)(const char *desc, const char *path);
|
||||||
|
|
||||||
extern void prepare_packed_git(void);
|
extern void prepare_packed_git(void);
|
||||||
extern void reprepare_packed_git(void);
|
extern void reprepare_packed_git(void);
|
||||||
extern void install_packed_git(struct packed_git *pack);
|
extern void install_packed_git(struct packed_git *pack);
|
||||||
|
|
83
sha1_file.c
83
sha1_file.c
|
@ -21,6 +21,7 @@
|
||||||
#include "sha1-lookup.h"
|
#include "sha1-lookup.h"
|
||||||
#include "bulk-checkin.h"
|
#include "bulk-checkin.h"
|
||||||
#include "streaming.h"
|
#include "streaming.h"
|
||||||
|
#include "dir.h"
|
||||||
|
|
||||||
#ifndef O_NOATIME
|
#ifndef O_NOATIME
|
||||||
#if defined(__linux__) && (defined(__i386__) || defined(__PPC__))
|
#if defined(__linux__) && (defined(__i386__) || defined(__PPC__))
|
||||||
|
@ -1000,6 +1001,63 @@ void install_packed_git(struct packed_git *pack)
|
||||||
packed_git = pack;
|
packed_git = pack;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void (*report_garbage)(const char *desc, const char *path);
|
||||||
|
|
||||||
|
static void report_helper(const struct string_list *list,
|
||||||
|
int seen_bits, int first, int last)
|
||||||
|
{
|
||||||
|
const char *msg;
|
||||||
|
switch (seen_bits) {
|
||||||
|
case 0:
|
||||||
|
msg = "no corresponding .idx nor .pack";
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
msg = "no corresponding .idx";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
msg = "no corresponding .pack";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (; first < last; first++)
|
||||||
|
report_garbage(msg, list->items[first].string);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void report_pack_garbage(struct string_list *list)
|
||||||
|
{
|
||||||
|
int i, baselen = -1, first = 0, seen_bits = 0;
|
||||||
|
|
||||||
|
if (!report_garbage)
|
||||||
|
return;
|
||||||
|
|
||||||
|
sort_string_list(list);
|
||||||
|
|
||||||
|
for (i = 0; i < list->nr; i++) {
|
||||||
|
const char *path = list->items[i].string;
|
||||||
|
if (baselen != -1 &&
|
||||||
|
strncmp(path, list->items[first].string, baselen)) {
|
||||||
|
report_helper(list, seen_bits, first, i);
|
||||||
|
baselen = -1;
|
||||||
|
seen_bits = 0;
|
||||||
|
}
|
||||||
|
if (baselen == -1) {
|
||||||
|
const char *dot = strrchr(path, '.');
|
||||||
|
if (!dot) {
|
||||||
|
report_garbage("garbage found", path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
baselen = dot - path + 1;
|
||||||
|
first = i;
|
||||||
|
}
|
||||||
|
if (!strcmp(path + baselen, "pack"))
|
||||||
|
seen_bits |= 1;
|
||||||
|
else if (!strcmp(path + baselen, "idx"))
|
||||||
|
seen_bits |= 2;
|
||||||
|
}
|
||||||
|
report_helper(list, seen_bits, first, list->nr);
|
||||||
|
}
|
||||||
|
|
||||||
static void prepare_packed_git_one(char *objdir, int local)
|
static void prepare_packed_git_one(char *objdir, int local)
|
||||||
{
|
{
|
||||||
/* Ensure that this buffer is large enough so that we can
|
/* Ensure that this buffer is large enough so that we can
|
||||||
|
@ -1009,6 +1067,7 @@ static void prepare_packed_git_one(char *objdir, int local)
|
||||||
int len;
|
int len;
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
struct dirent *de;
|
struct dirent *de;
|
||||||
|
struct string_list garbage = STRING_LIST_INIT_DUP;
|
||||||
|
|
||||||
sprintf(path, "%s/pack", objdir);
|
sprintf(path, "%s/pack", objdir);
|
||||||
len = strlen(path);
|
len = strlen(path);
|
||||||
|
@ -1024,7 +1083,17 @@ static void prepare_packed_git_one(char *objdir, int local)
|
||||||
int namelen = strlen(de->d_name);
|
int namelen = strlen(de->d_name);
|
||||||
struct packed_git *p;
|
struct packed_git *p;
|
||||||
|
|
||||||
if (len + namelen + 1 > sizeof(path))
|
if (len + namelen + 1 > sizeof(path)) {
|
||||||
|
if (report_garbage) {
|
||||||
|
struct strbuf sb = STRBUF_INIT;
|
||||||
|
strbuf_addf(&sb, "%.*s/%s", len - 1, path, de->d_name);
|
||||||
|
report_garbage("path too long", sb.buf);
|
||||||
|
strbuf_release(&sb);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_dot_or_dotdot(de->d_name))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
strcpy(path + len, de->d_name);
|
strcpy(path + len, de->d_name);
|
||||||
|
@ -1043,8 +1112,20 @@ static void prepare_packed_git_one(char *objdir, int local)
|
||||||
(p = add_packed_git(path, len + namelen, local)) != NULL)
|
(p = add_packed_git(path, len + namelen, local)) != NULL)
|
||||||
install_packed_git(p);
|
install_packed_git(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!report_garbage)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (has_extension(de->d_name, ".idx") ||
|
||||||
|
has_extension(de->d_name, ".pack") ||
|
||||||
|
has_extension(de->d_name, ".keep"))
|
||||||
|
string_list_append(&garbage, path);
|
||||||
|
else
|
||||||
|
report_garbage("garbage found", path);
|
||||||
}
|
}
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
|
report_pack_garbage(&garbage);
|
||||||
|
string_list_clear(&garbage, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sort_pack(const void *a_, const void *b_)
|
static int sort_pack(const void *a_, const void *b_)
|
||||||
|
|
|
@ -195,4 +195,30 @@ test_expect_success 'gc: prune old objects after local clone' '
|
||||||
)
|
)
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'garbage report in count-objects -v' '
|
||||||
|
: >.git/objects/pack/foo &&
|
||||||
|
: >.git/objects/pack/foo.bar &&
|
||||||
|
: >.git/objects/pack/foo.keep &&
|
||||||
|
: >.git/objects/pack/foo.pack &&
|
||||||
|
: >.git/objects/pack/fake.bar &&
|
||||||
|
: >.git/objects/pack/fake.keep &&
|
||||||
|
: >.git/objects/pack/fake.pack &&
|
||||||
|
: >.git/objects/pack/fake.idx &&
|
||||||
|
: >.git/objects/pack/fake2.keep &&
|
||||||
|
: >.git/objects/pack/fake3.idx &&
|
||||||
|
git count-objects -v 2>stderr &&
|
||||||
|
grep "index file .git/objects/pack/fake.idx is too small" stderr &&
|
||||||
|
grep "^warning:" stderr | sort >actual &&
|
||||||
|
cat >expected <<\EOF &&
|
||||||
|
warning: garbage found: .git/objects/pack/fake.bar
|
||||||
|
warning: garbage found: .git/objects/pack/foo
|
||||||
|
warning: garbage found: .git/objects/pack/foo.bar
|
||||||
|
warning: no corresponding .idx nor .pack: .git/objects/pack/fake2.keep
|
||||||
|
warning: no corresponding .idx: .git/objects/pack/foo.keep
|
||||||
|
warning: no corresponding .idx: .git/objects/pack/foo.pack
|
||||||
|
warning: no corresponding .pack: .git/objects/pack/fake3.idx
|
||||||
|
EOF
|
||||||
|
test_cmp expected actual
|
||||||
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
|
Загрузка…
Ссылка в новой задаче