#define PACK_ID_BITS 16
#define MAX_PACK_ID ((1<<PACK_ID_BITS)-1)
+#define DEPTH_BITS 13
+#define MAX_DEPTH ((1<<DEPTH_BITS)-1)
struct object_entry
{
struct object_entry *next;
uint32_t offset;
- unsigned type : TYPE_BITS;
- unsigned pack_id : PACK_ID_BITS;
+ uint32_t type : TYPE_BITS,
+ pack_id : PACK_ID_BITS,
+ depth : DEPTH_BITS;
unsigned char sha1[20];
};
WHENSPEC_NOW,
} whenspec_type;
+struct recent_command
+{
+ struct recent_command *prev;
+ struct recent_command *next;
+ char *buf;
+};
+
/* Configured limits on output */
static unsigned long max_depth = 10;
static off_t max_packsize = (1LL << 32) - 1;
static whenspec_type whenspec = WHENSPEC_RAW;
static struct strbuf command_buf;
static int unread_command_buf;
+static struct recent_command cmd_hist = {&cmd_hist, &cmd_hist, NULL};
+static struct recent_command *cmd_tail = &cmd_hist;
+static struct recent_command *rc_free;
+static unsigned int cmd_save = 100;
static uintmax_t next_mark;
static struct dbuf new_data;
+static void write_branch_report(FILE *rpt, struct branch *b)
+{
+ fprintf(rpt, "%s:\n", b->name);
+
+ fprintf(rpt, " status :");
+ if (b->active)
+ fputs(" active", rpt);
+ if (b->branch_tree.tree)
+ fputs(" loaded", rpt);
+ if (is_null_sha1(b->branch_tree.versions[1].sha1))
+ fputs(" dirty", rpt);
+ fputc('\n', rpt);
+
+ fprintf(rpt, " tip commit : %s\n", sha1_to_hex(b->sha1));
+ fprintf(rpt, " old tree : %s\n", sha1_to_hex(b->branch_tree.versions[0].sha1));
+ fprintf(rpt, " cur tree : %s\n", sha1_to_hex(b->branch_tree.versions[1].sha1));
+ fprintf(rpt, " commit clock: %" PRIuMAX "\n", b->last_commit);
+
+ fputs(" last pack : ", rpt);
+ if (b->pack_id < MAX_PACK_ID)
+ fprintf(rpt, "%u", b->pack_id);
+ fputc('\n', rpt);
+
+ fputc('\n', rpt);
+}
+
+static void write_crash_report(const char *err)
+{
+ char *loc = git_path("fast_import_crash_%d", getpid());
+ FILE *rpt = fopen(loc, "w");
+ struct branch *b;
+ unsigned long lu;
+ struct recent_command *rc;
+
+ if (!rpt) {
+ error("can't write crash report %s: %s", loc, strerror(errno));
+ return;
+ }
+
+ fprintf(stderr, "fast-import: dumping crash report to %s\n", loc);
+
+ fprintf(rpt, "fast-import crash report:\n");
+ fprintf(rpt, " fast-import process: %d\n", getpid());
+ fprintf(rpt, " parent process : %d\n", getppid());
+ fprintf(rpt, " at %s\n", show_date(time(NULL), 0, DATE_LOCAL));
+ fputc('\n', rpt);
+
+ fputs("fatal: ", rpt);
+ fputs(err, rpt);
+ fputc('\n', rpt);
+
+ fputc('\n', rpt);
+ fputs("Most Recent Commands Before Crash\n", rpt);
+ fputs("---------------------------------\n", rpt);
+ for (rc = cmd_hist.next; rc != &cmd_hist; rc = rc->next) {
+ if (rc->next == &cmd_hist)
+ fputs("* ", rpt);
+ else
+ fputs(" ", rpt);
+ fputs(rc->buf, rpt);
+ fputc('\n', rpt);
+ }
+
+ fputc('\n', rpt);
+ fputs("Active Branch LRU\n", rpt);
+ fputs("-----------------\n", rpt);
+ fprintf(rpt, " active_branches = %lu cur, %lu max\n",
+ cur_active_branches,
+ max_active_branches);
+ fputc('\n', rpt);
+ fputs(" pos clock name\n", rpt);
+ fputs(" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", rpt);
+ for (b = active_branches, lu = 0; b; b = b->active_next_branch)
+ fprintf(rpt, " %2lu) %6" PRIuMAX" %s\n",
+ ++lu, b->last_commit, b->name);
+
+ fputc('\n', rpt);
+ fputs("Inactive Branches\n", rpt);
+ fputs("-----------------\n", rpt);
+ for (lu = 0; lu < branch_table_sz; lu++) {
+ for (b = branch_table[lu]; b; b = b->table_next_branch)
+ write_branch_report(rpt, b);
+ }
+
+ fputc('\n', rpt);
+ fputs("-------------------\n", rpt);
+ fputs("END OF CRASH REPORT\n", rpt);
+ fclose(rpt);
+}
+
+static NORETURN void die_nicely(const char *err, va_list params)
+{
+ static int zombie;
+ char message[2 * PATH_MAX];
+
+ vsnprintf(message, sizeof(message), err, params);
+ fputs("fatal: ", stderr);
+ fputs(message, stderr);
+ fputc('\n', stderr);
+
+ if (!zombie) {
+ zombie = 1;
+ write_crash_report(message);
+ }
+ exit(128);
+}
static void alloc_objects(unsigned int cnt)
{
unsigned pos = sizeof(hdr) - 1;
delta_count_by_type[type]++;
- last->depth++;
+ e->depth = last->depth + 1;
hdrlen = encode_header(OBJ_OFS_DELTA, deltalen, hdr);
write_or_die(pack_data->pack_fd, hdr, hdrlen);
write_or_die(pack_data->pack_fd, hdr + pos, sizeof(hdr) - pos);
pack_size += sizeof(hdr) - pos;
} else {
- if (last)
- last->depth = 0;
+ e->depth = 0;
hdrlen = encode_header(type, datlen, hdr);
write_or_die(pack_data->pack_fd, hdr, hdrlen);
pack_size += hdrlen;
free(last->data);
last->data = dat;
last->offset = e->offset;
+ last->depth = e->depth;
last->len = datlen;
}
return 0;
if (myoe && myoe->pack_id != MAX_PACK_ID) {
if (myoe->type != OBJ_TREE)
die("Not a tree: %s", sha1_to_hex(sha1));
- t->delta_depth = 0;
+ t->delta_depth = myoe->depth;
buf = gfi_unpack_entry(myoe, &size);
} else {
enum object_type type;
static void read_next_command(void)
{
do {
- if (unread_command_buf)
+ if (unread_command_buf) {
unread_command_buf = 0;
- else
+ if (command_buf.eof)
+ return;
+ } else {
+ struct recent_command *rc;
+
+ command_buf.buf = NULL;
read_line(&command_buf, stdin, '\n');
- } while (!command_buf.eof && command_buf.buf[0] == '#');
+ if (command_buf.eof)
+ return;
+
+ rc = rc_free;
+ if (rc)
+ rc_free = rc->next;
+ else {
+ rc = cmd_hist.next;
+ cmd_hist.next = rc->next;
+ cmd_hist.next->prev = &cmd_hist;
+ free(rc->buf);
+ }
+
+ rc->buf = command_buf.buf;
+ rc->prev = cmd_tail;
+ rc->next = cmd_hist.prev;
+ rc->prev->next = rc;
+ cmd_tail = rc;
+ }
+ } while (command_buf.buf[0] == '#');
}
-static void skip_optional_lf()
+static void skip_optional_lf(void)
{
int term_char = fgetc(stdin);
if (term_char != '\n' && term_char != EOF)
size_t sz = 8192, term_len = command_buf.len - 5 - 2;
length = 0;
buffer = xmalloc(sz);
+ command_buf.buf = NULL;
for (;;) {
read_line(&command_buf, stdin, '\n');
if (command_buf.eof)
} else if (oe) {
if (oe->type != OBJ_BLOB)
die("Not a blob (actually a %s): %s",
- command_buf.buf, typename(oe->type));
+ typename(oe->type), command_buf.buf);
} else {
enum object_type type = sha1_object_info(sha1, NULL);
if (type < 0)
int main(int argc, const char **argv)
{
- int i, show_stats = 1;
+ unsigned int i, show_stats = 1;
git_config(git_default_config);
alloc_objects(object_entry_alloc);
}
else if (!prefixcmp(a, "--max-pack-size="))
max_packsize = strtoumax(a + 16, NULL, 0) * 1024 * 1024;
- else if (!prefixcmp(a, "--depth="))
+ else if (!prefixcmp(a, "--depth=")) {
max_depth = strtoul(a + 8, NULL, 0);
+ if (max_depth > MAX_DEPTH)
+ die("--depth cannot exceed %u", MAX_DEPTH);
+ }
else if (!prefixcmp(a, "--active-branches="))
max_active_branches = strtoul(a + 18, NULL, 0);
else if (!prefixcmp(a, "--import-marks="))
if (i != argc)
usage(fast_import_usage);
+ rc_free = pool_alloc(cmd_save * sizeof(*rc_free));
+ for (i = 0; i < (cmd_save - 1); i++)
+ rc_free[i].next = &rc_free[i + 1];
+ rc_free[cmd_save - 1].next = NULL;
+
prepare_packed_git();
start_packfile();
+ set_die_routine(die_nicely);
for (;;) {
read_next_command();
if (command_buf.eof)