Skip to content

Commit 1429b29

Browse files
committed
Merge branch 'jt/odb-transaction-per-source' into jch
Transaction to create objects (or not) is currently tied to the repository, but in the future a repository can have multiple object sources, which may have different transaction mechanisms. Make the odb transaction API per object source. * jt/odb-transaction-per-source: odb: transparently handle common transaction behavior odb: prepare `struct odb_transaction` to become generic object-file: rename transaction functions odb: store ODB source in `struct odb_transaction`
2 parents e247cbb + 3f67e3d commit 1429b29

4 files changed

Lines changed: 74 additions & 49 deletions

File tree

object-file.c

Lines changed: 38 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -725,32 +725,36 @@ struct transaction_packfile {
725725
uint32_t nr_written;
726726
};
727727

728-
struct odb_transaction {
729-
struct object_database *odb;
728+
struct odb_transaction_files {
729+
struct odb_transaction base;
730730

731731
struct tmp_objdir *objdir;
732732
struct transaction_packfile packfile;
733733
};
734734

735-
static void prepare_loose_object_transaction(struct odb_transaction *transaction)
735+
static void prepare_loose_object_transaction(struct odb_transaction *base)
736736
{
737+
struct odb_transaction_files *transaction = (struct odb_transaction_files *)base;
738+
737739
/*
738740
* We lazily create the temporary object directory
739741
* the first time an object might be added, since
740742
* callers may not know whether any objects will be
741-
* added at the time they call object_file_transaction_begin.
743+
* added at the time they call odb_transaction_files_begin.
742744
*/
743745
if (!transaction || transaction->objdir)
744746
return;
745747

746-
transaction->objdir = tmp_objdir_create(transaction->odb->repo, "bulk-fsync");
748+
transaction->objdir = tmp_objdir_create(base->source->odb->repo, "bulk-fsync");
747749
if (transaction->objdir)
748750
tmp_objdir_replace_primary_odb(transaction->objdir, 0);
749751
}
750752

751-
static void fsync_loose_object_transaction(struct odb_transaction *transaction,
753+
static void fsync_loose_object_transaction(struct odb_transaction *base,
752754
int fd, const char *filename)
753755
{
756+
struct odb_transaction_files *transaction = (struct odb_transaction_files *)base;
757+
754758
/*
755759
* If we have an active ODB transaction, we issue a call that
756760
* cleans the filesystem page cache but avoids a hardware flush
@@ -769,7 +773,7 @@ static void fsync_loose_object_transaction(struct odb_transaction *transaction,
769773
/*
770774
* Cleanup after batch-mode fsync_object_files.
771775
*/
772-
static void flush_loose_object_transaction(struct odb_transaction *transaction)
776+
static void flush_loose_object_transaction(struct odb_transaction_files *transaction)
773777
{
774778
struct strbuf temp_path = STRBUF_INIT;
775779
struct tempfile *temp;
@@ -787,7 +791,7 @@ static void flush_loose_object_transaction(struct odb_transaction *transaction)
787791
* the final name is visible.
788792
*/
789793
strbuf_addf(&temp_path, "%s/bulk_fsync_XXXXXX",
790-
repo_get_object_directory(transaction->odb->repo));
794+
repo_get_object_directory(transaction->base.source->odb->repo));
791795
temp = xmks_tempfile(temp_path.buf);
792796
fsync_or_die(get_tempfile_fd(temp), get_tempfile_path(temp));
793797
delete_tempfile(&temp);
@@ -1355,11 +1359,11 @@ static int index_core(struct index_state *istate,
13551359
return ret;
13561360
}
13571361

1358-
static int already_written(struct odb_transaction *transaction,
1362+
static int already_written(struct odb_transaction_files *transaction,
13591363
struct object_id *oid)
13601364
{
13611365
/* The object may already exist in the repository */
1362-
if (odb_has_object(transaction->odb, oid,
1366+
if (odb_has_object(transaction->base.source->odb, oid,
13631367
HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR))
13641368
return 1;
13651369

@@ -1373,14 +1377,14 @@ static int already_written(struct odb_transaction *transaction,
13731377
}
13741378

13751379
/* Lazily create backing packfile for the state */
1376-
static void prepare_packfile_transaction(struct odb_transaction *transaction,
1380+
static void prepare_packfile_transaction(struct odb_transaction_files *transaction,
13771381
unsigned flags)
13781382
{
13791383
struct transaction_packfile *state = &transaction->packfile;
13801384
if (!(flags & INDEX_WRITE_OBJECT) || state->f)
13811385
return;
13821386

1383-
state->f = create_tmp_packfile(transaction->odb->repo,
1387+
state->f = create_tmp_packfile(transaction->base.source->odb->repo,
13841388
&state->pack_tmp_name);
13851389
reset_pack_idx_option(&state->pack_idx_opts);
13861390

@@ -1481,10 +1485,10 @@ static int stream_blob_to_pack(struct transaction_packfile *state,
14811485
return 0;
14821486
}
14831487

1484-
static void flush_packfile_transaction(struct odb_transaction *transaction)
1488+
static void flush_packfile_transaction(struct odb_transaction_files *transaction)
14851489
{
14861490
struct transaction_packfile *state = &transaction->packfile;
1487-
struct repository *repo = transaction->odb->repo;
1491+
struct repository *repo = transaction->base.source->odb->repo;
14881492
unsigned char hash[GIT_MAX_RAWSZ];
14891493
struct strbuf packname = STRBUF_INIT;
14901494
char *idx_tmp_name = NULL;
@@ -1509,7 +1513,7 @@ static void flush_packfile_transaction(struct odb_transaction *transaction)
15091513
}
15101514

15111515
strbuf_addf(&packname, "%s/pack/pack-%s.",
1512-
repo_get_object_directory(transaction->odb->repo),
1516+
repo_get_object_directory(transaction->base.source->odb->repo),
15131517
hash_to_hex_algop(hash, repo->hash_algo));
15141518

15151519
stage_tmp_packfiles(repo, &packname, state->pack_tmp_name,
@@ -1549,7 +1553,7 @@ static void flush_packfile_transaction(struct odb_transaction *transaction)
15491553
* binary blobs, they generally do not want to get any conversion, and
15501554
* callers should avoid this code path when filters are requested.
15511555
*/
1552-
static int index_blob_packfile_transaction(struct odb_transaction *transaction,
1556+
static int index_blob_packfile_transaction(struct odb_transaction_files *transaction,
15531557
struct object_id *result_oid, int fd,
15541558
size_t size, const char *path,
15551559
unsigned flags)
@@ -1568,7 +1572,7 @@ static int index_blob_packfile_transaction(struct odb_transaction *transaction,
15681572

15691573
header_len = format_object_header((char *)obuf, sizeof(obuf),
15701574
OBJ_BLOB, size);
1571-
transaction->odb->repo->hash_algo->init_fn(&ctx);
1575+
transaction->base.source->odb->repo->hash_algo->init_fn(&ctx);
15721576
git_hash_update(&ctx, obuf, header_len);
15731577

15741578
/* Note: idx is non-NULL when we are writing */
@@ -1644,10 +1648,11 @@ int index_fd(struct index_state *istate, struct object_id *oid,
16441648
ret = index_core(istate, oid, fd, xsize_t(st->st_size),
16451649
type, path, flags);
16461650
} else {
1651+
struct object_database *odb = the_repository->objects;
16471652
struct odb_transaction *transaction;
16481653

1649-
transaction = odb_transaction_begin(the_repository->objects);
1650-
ret = index_blob_packfile_transaction(the_repository->objects->transaction,
1654+
transaction = odb_transaction_begin(odb);
1655+
ret = index_blob_packfile_transaction((struct odb_transaction_files *)odb->transaction,
16511656
oid, fd,
16521657
xsize_t(st->st_size),
16531658
path, flags);
@@ -2028,33 +2033,27 @@ int read_loose_object(struct repository *repo,
20282033
return ret;
20292034
}
20302035

2031-
struct odb_transaction *object_file_transaction_begin(struct odb_source *source)
2036+
static void odb_transaction_files_commit(struct odb_transaction *base)
20322037
{
2033-
struct object_database *odb = source->odb;
2038+
struct odb_transaction_files *transaction = (struct odb_transaction_files *)base;
20342039

2035-
if (odb->transaction)
2036-
return NULL;
2037-
2038-
CALLOC_ARRAY(odb->transaction, 1);
2039-
odb->transaction->odb = odb;
2040-
2041-
return odb->transaction;
2040+
flush_loose_object_transaction(transaction);
2041+
flush_packfile_transaction(transaction);
20422042
}
20432043

2044-
void object_file_transaction_commit(struct odb_transaction *transaction)
2044+
struct odb_transaction *odb_transaction_files_begin(struct odb_source *source)
20452045
{
2046-
if (!transaction)
2047-
return;
2046+
struct odb_transaction_files *transaction;
2047+
struct object_database *odb = source->odb;
20482048

2049-
/*
2050-
* Ensure the transaction ending matches the pending transaction.
2051-
*/
2052-
ASSERT(transaction == transaction->odb->transaction);
2049+
if (odb->transaction)
2050+
return NULL;
20532051

2054-
flush_loose_object_transaction(transaction);
2055-
flush_packfile_transaction(transaction);
2056-
transaction->odb->transaction = NULL;
2057-
free(transaction);
2052+
transaction = xcalloc(1, sizeof(*transaction));
2053+
transaction->base.source = source;
2054+
transaction->base.commit = odb_transaction_files_commit;
2055+
2056+
return &transaction->base;
20582057
}
20592058

20602059
struct odb_source_loose *odb_source_loose_new(struct odb_source *source)

object-file.h

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -204,16 +204,10 @@ struct odb_transaction;
204204

205205
/*
206206
* Tell the object database to optimize for adding
207-
* multiple objects. object_file_transaction_commit must be called
207+
* multiple objects. odb_transaction_files_commit must be called
208208
* to make new objects visible. If a transaction is already
209209
* pending, NULL is returned.
210210
*/
211-
struct odb_transaction *object_file_transaction_begin(struct odb_source *source);
212-
213-
/*
214-
* Tell the object database to make any objects from the
215-
* current transaction visible.
216-
*/
217-
void object_file_transaction_commit(struct odb_transaction *transaction);
211+
struct odb_transaction *odb_transaction_files_begin(struct odb_source *source);
218212

219213
#endif /* OBJECT_FILE_H */

odb.c

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1184,10 +1184,25 @@ void odb_reprepare(struct object_database *o)
11841184

11851185
struct odb_transaction *odb_transaction_begin(struct object_database *odb)
11861186
{
1187-
return object_file_transaction_begin(odb->sources);
1187+
if (odb->transaction)
1188+
return NULL;
1189+
1190+
odb->transaction = odb_transaction_files_begin(odb->sources);
1191+
1192+
return odb->transaction;
11881193
}
11891194

11901195
void odb_transaction_commit(struct odb_transaction *transaction)
11911196
{
1192-
object_file_transaction_commit(transaction);
1197+
if (!transaction)
1198+
return;
1199+
1200+
/*
1201+
* Ensure the transaction ending matches the pending transaction.
1202+
*/
1203+
ASSERT(transaction == transaction->source->odb->transaction);
1204+
1205+
transaction->commit(transaction);
1206+
transaction->source->odb->transaction = NULL;
1207+
free(transaction);
11931208
}

odb.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,24 @@ struct odb_source {
7777
struct packed_git;
7878
struct packfile_store;
7979
struct cached_object_entry;
80+
81+
/*
82+
* A transaction may be started for an object database prior to writing new
83+
* objects via odb_transaction_begin(). These objects are not committed until
84+
* odb_transaction_commit() is invoked. Only a single transaction may be pending
85+
* at a time.
86+
*
87+
* Each ODB source is expected to implement its own transaction handling.
88+
*/
8089
struct odb_transaction;
90+
typedef void (*odb_transaction_commit_fn)(struct odb_transaction *transaction);
91+
struct odb_transaction {
92+
/* The ODB source the transaction is opened against. */
93+
struct odb_source *source;
94+
95+
/* The ODB source specific callback invoked to commit a transaction. */
96+
odb_transaction_commit_fn commit;
97+
};
8198

8299
/*
83100
* The object database encapsulates access to objects in a repository. It

0 commit comments

Comments
 (0)