Skip to content

Commit b182f1b

Browse files
jltoblergitster
authored andcommitted
object-file: generalize packfile writes to use odb_write_stream
The `index_blob_packfile_transaction()` function streams blob data directly from an fd. This makes it difficult to reuse as part of a generic transactional object writing interface. Refactor the packfile write path to operate on a `struct odb_write_stream`, allowing callers to supply data from arbitrary sources. Signed-off-by: Justin Tobler <jltobler@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 8144c23 commit b182f1b

1 file changed

Lines changed: 70 additions & 29 deletions

File tree

object-file.c

Lines changed: 70 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1433,18 +1433,18 @@ static int hash_blob_stream(const struct git_hash_algo *hash_algo,
14331433
}
14341434

14351435
/*
1436-
* Read the contents from fd for size bytes, streaming it to the
1436+
* Read the contents from the stream provided, streaming it to the
14371437
* packfile in state while updating the hash in ctx.
14381438
*/
14391439
static void stream_blob_to_pack(struct transaction_packfile *state,
1440-
struct git_hash_ctx *ctx, int fd, size_t size,
1441-
const char *path)
1440+
struct git_hash_ctx *ctx, size_t size,
1441+
struct odb_write_stream *stream)
14421442
{
14431443
git_zstream s;
1444-
unsigned char ibuf[16384];
14451444
unsigned char obuf[16384];
14461445
unsigned hdrlen;
14471446
int status = Z_OK;
1447+
size_t total = 0;
14481448

14491449
git_deflate_init(&s, pack_compression_level);
14501450

@@ -1453,24 +1453,19 @@ static void stream_blob_to_pack(struct transaction_packfile *state,
14531453
s.avail_out = sizeof(obuf) - hdrlen;
14541454

14551455
while (status != Z_STREAM_END) {
1456-
if (size && !s.avail_in) {
1457-
size_t rsize = size < sizeof(ibuf) ? size : sizeof(ibuf);
1458-
ssize_t read_result = read_in_full(fd, ibuf, rsize);
1459-
if (read_result < 0)
1460-
die_errno("failed to read from '%s'", path);
1461-
if ((size_t)read_result != rsize)
1462-
die("failed to read %u bytes from '%s'",
1463-
(unsigned)rsize, path);
1456+
if (!stream->is_finished && !s.avail_in) {
1457+
unsigned long rsize;
1458+
unsigned const char *buf = stream->read(stream, &rsize);
14641459

14651460
if (rsize)
1466-
git_hash_update(ctx, ibuf, rsize);
1461+
git_hash_update(ctx, buf, rsize);
14671462

1468-
s.next_in = ibuf;
1463+
s.next_in = (unsigned char *)buf;
14691464
s.avail_in = rsize;
1470-
size -= rsize;
1465+
total += rsize;
14711466
}
14721467

1473-
status = git_deflate(&s, size ? 0 : Z_FINISH);
1468+
status = git_deflate(&s, stream->is_finished ? Z_FINISH : 0);
14741469

14751470
if (!s.avail_out || status == Z_STREAM_END) {
14761471
size_t written = s.next_out - obuf;
@@ -1490,6 +1485,10 @@ static void stream_blob_to_pack(struct transaction_packfile *state,
14901485
die("unexpected deflate failure: %d", status);
14911486
}
14921487
}
1488+
1489+
if (total != size)
1490+
die("unexpected number of bytes read");
1491+
14931492
git_deflate_end(&s);
14941493
}
14951494

@@ -1543,6 +1542,40 @@ static void flush_packfile_transaction(struct odb_transaction_files *transaction
15431542
odb_reprepare(repo->objects);
15441543
}
15451544

1545+
struct read_object_fd_data {
1546+
int fd;
1547+
size_t size;
1548+
unsigned char buf[16384];
1549+
};
1550+
1551+
static const void *read_object_fd(struct odb_write_stream *stream,
1552+
unsigned long *len)
1553+
{
1554+
struct read_object_fd_data *data = stream->data;
1555+
ssize_t read_result;
1556+
size_t rsize;
1557+
1558+
if (stream->is_finished) {
1559+
*len = 0;
1560+
return NULL;
1561+
}
1562+
1563+
rsize = data->size < sizeof(data->buf) ? data->size : sizeof(data->buf);
1564+
read_result = read_in_full(data->fd, data->buf, rsize);
1565+
if (read_result < 0)
1566+
die_errno("failed to read blob data");
1567+
if ((size_t)read_result != rsize)
1568+
die("failed to read %u bytes of blob data", (unsigned)rsize);
1569+
1570+
data->size -= rsize;
1571+
if (!data->size)
1572+
stream->is_finished = 1;
1573+
1574+
*len = rsize;
1575+
1576+
return data->buf;
1577+
}
1578+
15461579
/*
15471580
* This writes the specified object to a packfile. Objects written here
15481581
* during the same transaction are written to the same packfile. The
@@ -1561,10 +1594,13 @@ static void flush_packfile_transaction(struct odb_transaction_files *transaction
15611594
* binary blobs, they generally do not want to get any conversion, and
15621595
* callers should avoid this code path when filters are requested.
15631596
*/
1564-
static int index_blob_packfile_transaction(struct odb_transaction_files *transaction,
1565-
struct object_id *result_oid, int fd,
1566-
size_t size, const char *path)
1597+
static int index_blob_packfile_transaction(struct odb_transaction *base,
1598+
struct odb_write_stream *stream,
1599+
size_t size, struct object_id *result_oid)
15671600
{
1601+
struct odb_transaction_files *transaction = container_of(base,
1602+
struct odb_transaction_files,
1603+
base);
15681604
struct transaction_packfile *state = &transaction->packfile;
15691605
struct git_hash_ctx ctx;
15701606
unsigned char obuf[16384];
@@ -1593,7 +1629,7 @@ static int index_blob_packfile_transaction(struct odb_transaction_files *transac
15931629
hashfile_checkpoint(state->f, &checkpoint);
15941630
idx->offset = state->offset;
15951631
crc32_begin(state->f);
1596-
stream_blob_to_pack(state, &ctx, fd, size, path);
1632+
stream_blob_to_pack(state, &ctx, size, stream);
15971633
git_hash_final_oid(result_oid, &ctx);
15981634

15991635
idx->crc32 = crc32_end(state->f);
@@ -1634,15 +1670,20 @@ int index_fd(struct index_state *istate, struct object_id *oid,
16341670
} else {
16351671
if (flags & INDEX_WRITE_OBJECT) {
16361672
struct object_database *odb = the_repository->objects;
1637-
struct odb_transaction_files *files_transaction;
1638-
struct odb_transaction *transaction;
1639-
1640-
transaction = odb_transaction_begin(odb);
1641-
files_transaction = container_of(odb->transaction,
1642-
struct odb_transaction_files,
1643-
base);
1644-
ret = index_blob_packfile_transaction(files_transaction, oid, fd,
1645-
xsize_t(st->st_size), path);
1673+
struct odb_transaction *transaction = odb_transaction_begin(odb);
1674+
struct read_object_fd_data data = {
1675+
.fd = fd,
1676+
.size = xsize_t(st->st_size),
1677+
};
1678+
struct odb_write_stream in_stream = {
1679+
.read = read_object_fd,
1680+
.data = &data,
1681+
};
1682+
1683+
ret = index_blob_packfile_transaction(odb->transaction,
1684+
&in_stream,
1685+
xsize_t(st->st_size),
1686+
oid);
16461687
odb_transaction_commit(transaction);
16471688
} else {
16481689
if (hash_blob_stream(the_repository->hash_algo, oid, fd,

0 commit comments

Comments
 (0)