Commit 6c526148 authored by Junio C Hamano's avatar Junio C Hamano

csum-file: introduce sha1file_checkpoint

It is useful to be able to rewind a check-summed file to a certain
previous state after writing data into it using sha1write() API. The
fast-import command does this after streaming a blob data to the packfile
being generated and then noticing that the same blob has already been
written, and it does this with a private code truncate_pack() that is
commented as "Yes, this is a layering violation".

Introduce two API functions, sha1file_checkpoint(), that allows the caller
to save a state of a sha1file, and then later revert it to the saved state.
Use it to reimplement truncate_pack().
Signed-off-by: default avatarJunio C Hamano <gitster@pobox.com>
parent 0e990530
......@@ -158,6 +158,26 @@ struct sha1file *sha1fd_throughput(int fd, const char *name, struct progress *tp
return f;
}
void sha1file_checkpoint(struct sha1file *f, struct sha1file_checkpoint *checkpoint)
{
sha1flush(f);
checkpoint->offset = f->total;
checkpoint->ctx = f->ctx;
}
int sha1file_truncate(struct sha1file *f, struct sha1file_checkpoint *checkpoint)
{
off_t offset = checkpoint->offset;
if (ftruncate(f->fd, offset) ||
lseek(f->fd, offset, SEEK_SET) != offset)
return -1;
f->total = offset;
f->ctx = checkpoint->ctx;
f->offset = 0; /* sha1flush() was called in checkpoint */
return 0;
}
void crc32_begin(struct sha1file *f)
{
f->crc32 = crc32(0, NULL, 0);
......
......@@ -17,6 +17,15 @@ struct sha1file {
unsigned char buffer[8192];
};
/* Checkpoint */
struct sha1file_checkpoint {
off_t offset;
git_SHA_CTX ctx;
};
extern void sha1file_checkpoint(struct sha1file *, struct sha1file_checkpoint *);
extern int sha1file_truncate(struct sha1file *, struct sha1file_checkpoint *);
/* sha1close flags */
#define CSUM_CLOSE 1
#define CSUM_FSYNC 2
......
......@@ -1143,17 +1143,11 @@ static int store_object(
return 0;
}
static void truncate_pack(off_t to, git_SHA_CTX *ctx)
static void truncate_pack(struct sha1file_checkpoint *checkpoint)
{
if (ftruncate(pack_data->pack_fd, to)
|| lseek(pack_data->pack_fd, to, SEEK_SET) != to)
if (sha1file_truncate(pack_file, checkpoint))
die_errno("cannot truncate pack to skip duplicate");
pack_size = to;
/* yes this is a layering violation */
pack_file->total = to;
pack_file->offset = 0;
pack_file->ctx = *ctx;
pack_size = checkpoint->offset;
}
static void stream_blob(uintmax_t len, unsigned char *sha1out, uintmax_t mark)
......@@ -1166,8 +1160,8 @@ static void stream_blob(uintmax_t len, unsigned char *sha1out, uintmax_t mark)
unsigned long hdrlen;
off_t offset;
git_SHA_CTX c;
git_SHA_CTX pack_file_ctx;
git_zstream s;
struct sha1file_checkpoint checkpoint;
int status = Z_OK;
/* Determine if we should auto-checkpoint. */
......@@ -1175,11 +1169,8 @@ static void stream_blob(uintmax_t len, unsigned char *sha1out, uintmax_t mark)
|| (pack_size + 60 + len) < pack_size)
cycle_packfile();
offset = pack_size;
/* preserve the pack_file SHA1 ctx in case we have to truncate later */
sha1flush(pack_file);
pack_file_ctx = pack_file->ctx;
sha1file_checkpoint(pack_file, &checkpoint);
offset = checkpoint.offset;
hdrlen = snprintf((char *)out_buf, out_sz, "blob %" PRIuMAX, len) + 1;
if (out_sz <= hdrlen)
......@@ -1245,14 +1236,14 @@ static void stream_blob(uintmax_t len, unsigned char *sha1out, uintmax_t mark)
if (e->idx.offset) {
duplicate_count_by_type[OBJ_BLOB]++;
truncate_pack(offset, &pack_file_ctx);
truncate_pack(&checkpoint);
} else if (find_sha1_pack(sha1, packed_git)) {
e->type = OBJ_BLOB;
e->pack_id = MAX_PACK_ID;
e->idx.offset = 1; /* just not zero! */
duplicate_count_by_type[OBJ_BLOB]++;
truncate_pack(offset, &pack_file_ctx);
truncate_pack(&checkpoint);
} else {
e->depth = 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment