char *seen = NULL;
char *ps_matched = NULL;
struct lock_file lock_file = LOCK_INIT;
+ struct odb_transaction *transaction;
repo_config(repo, add_config, NULL);
string_list_clear(&only_match_skip_worktree, 0);
}
- begin_odb_transaction();
+ transaction = begin_odb_transaction(repo->objects);
ps_matched = xcalloc(pathspec.nr, 1);
if (add_renormalize)
if (chmod_arg && pathspec.nr)
exit_status |= chmod_pathspec(repo, &pathspec, chmod_arg[0], show_only);
- end_odb_transaction();
+ end_odb_transaction(transaction);
finish:
if (write_locked_index(repo->index, &lock_file,
{
int i;
unsigned char *hdr = fill(sizeof(struct pack_header));
+ struct odb_transaction *transaction;
if (get_be32(hdr) != PACK_SIGNATURE)
die("bad pack file");
progress = start_progress(the_repository,
_("Unpacking objects"), nr_objects);
CALLOC_ARRAY(obj_list, nr_objects);
- begin_odb_transaction();
+ transaction = begin_odb_transaction(the_repository->objects);
for (i = 0; i < nr_objects; i++) {
unpack_one(i);
display_progress(progress, i + 1);
}
- end_odb_transaction();
+ end_odb_transaction(transaction);
stop_progress(&progress);
if (delta_list)
* objects invisible while a transaction is active, so flush the
* transaction here before reporting a change made by update-index.
*/
- flush_odb_transaction();
+ flush_odb_transaction(the_repository->objects->transaction);
va_start(vp, fmt);
vprintf(fmt, vp);
putchar('\n');
strbuf_getline_fn getline_fn;
int parseopt_state = PARSE_OPT_UNKNOWN;
struct repository *r = the_repository;
+ struct odb_transaction *transaction;
struct option options[] = {
OPT_BIT('q', NULL, &refresh_args.flags,
N_("continue refresh even when index needs update"),
* Allow the object layer to optimize adding multiple objects in
* a batch.
*/
- begin_odb_transaction();
+ transaction = begin_odb_transaction(the_repository->objects);
while (ctx.argc) {
if (parseopt_state != PARSE_OPT_DONE)
parseopt_state = parse_options_step(&ctx, options,
/*
* By now we have added all of the new objects
*/
- end_odb_transaction();
+ end_odb_transaction(transaction);
if (split_index > 0) {
if (repo_config_get_split_index(the_repository) == 0)
uint32_t nr_written;
};
-static struct odb_transaction {
+struct odb_transaction {
+ struct object_database *odb;
+
int nesting;
struct tmp_objdir *objdir;
struct bulk_checkin_packfile packfile;
-} transaction;
+};
static void finish_tmp_packfile(struct strbuf *basename,
const char *pack_tmp_name,
/*
* Cleanup after batch-mode fsync_object_files.
*/
-static void flush_batch_fsync(void)
+static void flush_batch_fsync(struct odb_transaction *transaction)
{
struct strbuf temp_path = STRBUF_INIT;
struct tempfile *temp;
- if (!transaction.objdir)
+ if (!transaction->objdir)
return;
/*
* Make the object files visible in the primary ODB after their data is
* fully durable.
*/
- tmp_objdir_migrate(transaction.objdir);
- transaction.objdir = NULL;
+ tmp_objdir_migrate(transaction->objdir);
+ transaction->objdir = NULL;
}
static int already_written(struct bulk_checkin_packfile *state, struct object_id *oid)
return 0;
}
-void prepare_loose_object_bulk_checkin(void)
+void prepare_loose_object_bulk_checkin(struct odb_transaction *transaction)
{
/*
* We lazily create the temporary object directory
* callers may not know whether any objects will be
* added at the time they call begin_odb_transaction.
*/
- if (!transaction.nesting || transaction.objdir)
+ if (!transaction || transaction->objdir)
return;
- transaction.objdir = tmp_objdir_create(the_repository, "bulk-fsync");
- if (transaction.objdir)
- tmp_objdir_replace_primary_odb(transaction.objdir, 0);
+ transaction->objdir = tmp_objdir_create(the_repository, "bulk-fsync");
+ if (transaction->objdir)
+ tmp_objdir_replace_primary_odb(transaction->objdir, 0);
}
-void fsync_loose_object_bulk_checkin(int fd, const char *filename)
+void fsync_loose_object_bulk_checkin(struct odb_transaction *transaction,
+ int fd, const char *filename)
{
/*
* If we have an active ODB transaction, we issue a call that
* before renaming the objects to their final names as part of
* flush_batch_fsync.
*/
- if (!transaction.objdir ||
+ if (!transaction || !transaction->objdir ||
git_fsync(fd, FSYNC_WRITEOUT_ONLY) < 0) {
if (errno == ENOSYS)
warning(_("core.fsyncMethod = batch is unsupported on this platform"));
}
}
-int index_blob_bulk_checkin(struct object_id *oid,
- int fd, size_t size,
+int index_blob_bulk_checkin(struct odb_transaction *transaction,
+ struct object_id *oid, int fd, size_t size,
const char *path, unsigned flags)
{
- int status = deflate_blob_to_pack(&transaction.packfile, oid, fd, size,
- path, flags);
- if (!transaction.nesting)
- flush_bulk_checkin_packfile(&transaction.packfile);
+ int status;
+
+ if (transaction) {
+ status = deflate_blob_to_pack(&transaction->packfile, oid, fd,
+ size, path, flags);
+ } else {
+ struct bulk_checkin_packfile state = { 0 };
+
+ status = deflate_blob_to_pack(&state, oid, fd, size, path, flags);
+ flush_bulk_checkin_packfile(&state);
+ }
+
return status;
}
-void begin_odb_transaction(void)
+struct odb_transaction *begin_odb_transaction(struct object_database *odb)
{
- transaction.nesting += 1;
+ if (!odb->transaction) {
+ CALLOC_ARRAY(odb->transaction, 1);
+ odb->transaction->odb = odb;
+ }
+
+ odb->transaction->nesting += 1;
+
+ return odb->transaction;
}
-void flush_odb_transaction(void)
+void flush_odb_transaction(struct odb_transaction *transaction)
{
- flush_batch_fsync();
- flush_bulk_checkin_packfile(&transaction.packfile);
+ if (!transaction)
+ return;
+
+ flush_batch_fsync(transaction);
+ flush_bulk_checkin_packfile(&transaction->packfile);
}
-void end_odb_transaction(void)
+void end_odb_transaction(struct odb_transaction *transaction)
{
- transaction.nesting -= 1;
- if (transaction.nesting < 0)
+ if (!transaction || transaction->nesting == 0)
BUG("Unbalanced ODB transaction nesting");
- if (transaction.nesting)
+ transaction->nesting -= 1;
+
+ if (transaction->nesting)
return;
- flush_odb_transaction();
+ flush_odb_transaction(transaction);
+ transaction->odb->transaction = NULL;
+ free(transaction);
}
#define BULK_CHECKIN_H
#include "object.h"
+#include "odb.h"
-void prepare_loose_object_bulk_checkin(void);
-void fsync_loose_object_bulk_checkin(int fd, const char *filename);
+struct odb_transaction;
+
+void prepare_loose_object_bulk_checkin(struct odb_transaction *transaction);
+void fsync_loose_object_bulk_checkin(struct odb_transaction *transaction,
+ int fd, const char *filename);
/*
* This creates one packfile per large blob unless bulk-checkin
* binary blobs, they generally do not want to get any conversion, and
* callers should avoid this code path when filters are requested.
*/
-int index_blob_bulk_checkin(struct object_id *oid,
- int fd, size_t size,
+int index_blob_bulk_checkin(struct odb_transaction *transaction,
+ struct object_id *oid, int fd, size_t size,
const char *path, unsigned flags);
/*
* and objects are only visible after the outermost transaction
* is complete or the transaction is flushed.
*/
-void begin_odb_transaction(void);
+struct odb_transaction *begin_odb_transaction(struct object_database *odb);
/*
* Make any objects that are currently part of a pending object
* database transaction visible. It is valid to call this function
* even if no transaction is active.
*/
-void flush_odb_transaction(void);
+void flush_odb_transaction(struct odb_transaction *transaction);
/*
* Tell the object database to make any objects from the
* current transaction visible if this is the final nested
* transaction.
*/
-void end_odb_transaction(void);
+void end_odb_transaction(struct odb_transaction *transaction);
#endif
int cache_tree_update(struct index_state *istate, int flags)
{
+ struct odb_transaction *transaction;
int skip, i;
i = verify_cache(istate, flags);
trace_performance_enter();
trace2_region_enter("cache_tree", "update", the_repository);
- begin_odb_transaction();
+ transaction = begin_odb_transaction(the_repository->objects);
i = update_one(istate->cache_tree, istate->cache, istate->cache_nr,
"", 0, &skip, flags);
- end_odb_transaction();
+ end_odb_transaction(transaction);
trace2_region_leave("cache_tree", "update", the_repository);
trace_performance_leave("cache_tree_update");
if (i < 0)
goto out;
if (batch_fsync_enabled(FSYNC_COMPONENT_LOOSE_OBJECT))
- fsync_loose_object_bulk_checkin(fd, filename);
+ fsync_loose_object_bulk_checkin(source->odb->transaction, fd, filename);
else if (fsync_object_files > 0)
fsync_or_die(fd, filename);
else
static struct strbuf filename = STRBUF_INIT;
if (batch_fsync_enabled(FSYNC_COMPONENT_LOOSE_OBJECT))
- prepare_loose_object_bulk_checkin();
+ prepare_loose_object_bulk_checkin(source->odb->transaction);
odb_loose_path(source, &filename, oid);
int hdrlen;
if (batch_fsync_enabled(FSYNC_COMPONENT_LOOSE_OBJECT))
- prepare_loose_object_bulk_checkin();
+ prepare_loose_object_bulk_checkin(source->odb->transaction);
/* Since oid is not determined, save tmp file to odb path. */
strbuf_addf(&filename, "%s/", source->path);
ret = index_core(istate, oid, fd, xsize_t(st->st_size),
type, path, flags);
else
- ret = index_blob_bulk_checkin(oid, fd, xsize_t(st->st_size), path,
- flags);
+ ret = index_blob_bulk_checkin(the_repository->objects->transaction,
+ oid, fd, xsize_t(st->st_size),
+ path, flags);
close(fd);
return ret;
}
struct packed_git;
struct cached_object_entry;
+struct odb_transaction;
/*
* The object database encapsulates access to objects in a repository. It
/* Repository that owns this database. */
struct repository *repo;
+ /*
+ * State of current current object database transaction. Only one
+ * transaction may be pending at a time. Is NULL when no transaction is
+ * configured.
+ */
+ struct odb_transaction *transaction;
+
/*
* Set of all object directories; the main directory is first (and
* cannot be NULL after initialization). Subsequent directories are
const struct pathspec *pathspec, char *ps_matched,
int include_sparse, int flags)
{
+ struct odb_transaction *transaction;
struct update_callback_data data;
struct rev_info rev;
* This function is invoked from commands other than 'add', which
* may not have their own transaction active.
*/
- begin_odb_transaction();
+ transaction = begin_odb_transaction(repo->objects);
run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
- end_odb_transaction();
+ end_odb_transaction(transaction);
release_revisions(&rev);
return !!data.add_errors;