Skip to content

Commit 5046831

Browse files
committed
Merge branch 'ns/tmp-objdir' into en/remerge-diff
* ns/tmp-objdir: tmp-objdir: disable ref updates when replacing the primary odb tmp-objdir: new API for creating temporary writable databases
2 parents 597af31 + ecd81df commit 5046831

File tree

11 files changed

+183
-15
lines changed

11 files changed

+183
-15
lines changed

builtin/prune.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,22 @@ static int prune_tmp_file(const char *fullpath)
2626
return error("Could not stat '%s'", fullpath);
2727
if (st.st_mtime > expire)
2828
return 0;
29-
if (show_only || verbose)
30-
printf("Removing stale temporary file %s\n", fullpath);
31-
if (!show_only)
32-
unlink_or_warn(fullpath);
29+
if (S_ISDIR(st.st_mode)) {
30+
if (show_only || verbose)
31+
printf("Removing stale temporary directory %s\n", fullpath);
32+
if (!show_only) {
33+
struct strbuf remove_dir_buf = STRBUF_INIT;
34+
35+
strbuf_addstr(&remove_dir_buf, fullpath);
36+
remove_dir_recursively(&remove_dir_buf, 0);
37+
strbuf_release(&remove_dir_buf);
38+
}
39+
} else {
40+
if (show_only || verbose)
41+
printf("Removing stale temporary file %s\n", fullpath);
42+
if (!show_only)
43+
unlink_or_warn(fullpath);
44+
}
3345
return 0;
3446
}
3547

builtin/receive-pack.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2206,7 +2206,7 @@ static const char *unpack(int err_fd, struct shallow_info *si)
22062206
strvec_push(&child.args, alt_shallow_file);
22072207
}
22082208

2209-
tmp_objdir = tmp_objdir_create();
2209+
tmp_objdir = tmp_objdir_create("incoming");
22102210
if (!tmp_objdir) {
22112211
if (err_fd > 0)
22122212
close(err_fd);

environment.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "commit.h"
1818
#include "strvec.h"
1919
#include "object-store.h"
20+
#include "tmp-objdir.h"
2021
#include "chdir-notify.h"
2122
#include "shallow.h"
2223

@@ -169,6 +170,10 @@ void setup_git_env(const char *git_dir)
169170
args.graft_file = getenv_safe(&to_free, GRAFT_ENVIRONMENT);
170171
args.index_file = getenv_safe(&to_free, INDEX_ENVIRONMENT);
171172
args.alternate_db = getenv_safe(&to_free, ALTERNATE_DB_ENVIRONMENT);
173+
if (getenv(GIT_QUARANTINE_ENVIRONMENT)) {
174+
args.disable_ref_updates = 1;
175+
}
176+
172177
repo_set_gitdir(the_repository, git_dir, &args);
173178
strvec_clear(&to_free);
174179

@@ -332,10 +337,14 @@ static void update_relative_gitdir(const char *name,
332337
void *data)
333338
{
334339
char *path = reparent_relative_path(old_cwd, new_cwd, get_git_dir());
340+
struct tmp_objdir *tmp_objdir = tmp_objdir_unapply_primary_odb();
341+
335342
trace_printf_key(&trace_setup_key,
336343
"setup: move $GIT_DIR to '%s'",
337344
path);
338345
set_git_dir_1(path);
346+
if (tmp_objdir)
347+
tmp_objdir_reapply_primary_odb(tmp_objdir, old_cwd, new_cwd);
339348
free(path);
340349
}
341350

object-file.c

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,49 @@ void add_to_alternates_memory(const char *reference)
680680
'\n', NULL, 0);
681681
}
682682

683+
struct object_directory *set_temporary_primary_odb(const char *dir, int will_destroy)
684+
{
685+
struct object_directory *new_odb;
686+
687+
/*
688+
* Make sure alternates are initialized, or else our entry may be
689+
* overwritten when they are.
690+
*/
691+
prepare_alt_odb(the_repository);
692+
693+
/*
694+
* Make a new primary odb and link the old primary ODB in as an
695+
* alternate
696+
*/
697+
new_odb = xcalloc(1, sizeof(*new_odb));
698+
new_odb->path = xstrdup(dir);
699+
700+
/*
701+
* Disable ref updates while a temporary odb is active, since
702+
* the objects in the database may roll back.
703+
*/
704+
new_odb->disable_ref_updates = 1;
705+
new_odb->will_destroy = will_destroy;
706+
new_odb->next = the_repository->objects->odb;
707+
the_repository->objects->odb = new_odb;
708+
return new_odb->next;
709+
}
710+
711+
void restore_primary_odb(struct object_directory *restore_odb, const char *old_path)
712+
{
713+
struct object_directory *cur_odb = the_repository->objects->odb;
714+
715+
if (strcmp(old_path, cur_odb->path))
716+
BUG("expected %s as primary object store; found %s",
717+
old_path, cur_odb->path);
718+
719+
if (cur_odb->next != restore_odb)
720+
BUG("we expect the old primary object store to be the first alternate");
721+
722+
the_repository->objects->odb = restore_odb;
723+
free_object_directory(cur_odb);
724+
}
725+
683726
/*
684727
* Compute the exact path an alternate is at and returns it. In case of
685728
* error NULL is returned and the human readable error is added to `err`
@@ -1806,8 +1849,11 @@ int hash_object_file(const struct git_hash_algo *algo, const void *buf,
18061849
/* Finalize a file on disk, and close it. */
18071850
static void close_loose_object(int fd)
18081851
{
1809-
if (fsync_object_files)
1810-
fsync_or_die(fd, "loose object file");
1852+
if (!the_repository->objects->odb->will_destroy) {
1853+
if (fsync_object_files)
1854+
fsync_or_die(fd, "loose object file");
1855+
}
1856+
18111857
if (close(fd) != 0)
18121858
die_errno(_("error when closing loose object file"));
18131859
}

object-store.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,18 @@ struct object_directory {
2727
uint32_t loose_objects_subdir_seen[8]; /* 256 bits */
2828
struct oidtree *loose_objects_cache;
2929

30+
/*
31+
* This is a temporary object store created by the tmp_objdir
32+
* facility. Disable ref updates since the objects in the store
33+
* might be discarded on rollback.
34+
*/
35+
int disable_ref_updates;
36+
37+
/*
38+
* This object store is ephemeral, so there is no need to fsync.
39+
*/
40+
int will_destroy;
41+
3042
/*
3143
* Path to the alternative object store. If this is a relative path,
3244
* it is relative to the current working directory.
@@ -58,6 +70,17 @@ void add_to_alternates_file(const char *dir);
5870
*/
5971
void add_to_alternates_memory(const char *dir);
6072

73+
/*
74+
* Replace the current writable object directory with the specified temporary
75+
* object directory; returns the former primary object directory.
76+
*/
77+
struct object_directory *set_temporary_primary_odb(const char *dir, int will_destroy);
78+
79+
/*
80+
* Restore a previous ODB replaced by set_temporary_main_odb.
81+
*/
82+
void restore_primary_odb(struct object_directory *restore_odb, const char *old_path);
83+
6184
/*
6285
* Populate and return the loose object cache array corresponding to the
6386
* given object ID.
@@ -68,6 +91,9 @@ struct oidtree *odb_loose_cache(struct object_directory *odb,
6891
/* Empty the loose object cache for the specified object directory. */
6992
void odb_clear_loose_cache(struct object_directory *odb);
7093

94+
/* Clear and free the specified object directory */
95+
void free_object_directory(struct object_directory *odb);
96+
7197
struct packed_git {
7298
struct hashmap_entry packmap_ent;
7399
struct packed_git *next;

object.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -513,7 +513,7 @@ struct raw_object_store *raw_object_store_new(void)
513513
return o;
514514
}
515515

516-
static void free_object_directory(struct object_directory *odb)
516+
void free_object_directory(struct object_directory *odb)
517517
{
518518
free(odb->path);
519519
odb_clear_loose_cache(odb);

refs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2145,7 +2145,7 @@ int ref_transaction_prepare(struct ref_transaction *transaction,
21452145
break;
21462146
}
21472147

2148-
if (getenv(GIT_QUARANTINE_ENVIRONMENT)) {
2148+
if (refs->repo->objects->odb->disable_ref_updates) {
21492149
strbuf_addstr(err,
21502150
_("ref updates forbidden inside quarantine environment"));
21512151
return -1;

repository.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ void repo_set_gitdir(struct repository *repo,
8282
expand_base_dir(&repo->objects->odb->path, o->object_dir,
8383
repo->commondir, "objects");
8484

85+
repo->objects->odb->disable_ref_updates = o->disable_ref_updates;
86+
8587
free(repo->objects->alternate_db);
8688
repo->objects->alternate_db = xstrdup_or_null(o->alternate_db);
8789
expand_base_dir(&repo->graft_file, o->graft_file,

repository.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ struct set_gitdir_args {
162162
const char *graft_file;
163163
const char *index_file;
164164
const char *alternate_db;
165+
int disable_ref_updates;
165166
};
166167

167168
void repo_set_gitdir(struct repository *repo, const char *root,

tmp-objdir.c

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "cache.h"
22
#include "tmp-objdir.h"
3+
#include "chdir-notify.h"
34
#include "dir.h"
45
#include "sigchain.h"
56
#include "string-list.h"
@@ -11,6 +12,8 @@
1112
struct tmp_objdir {
1213
struct strbuf path;
1314
struct strvec env;
15+
struct object_directory *prev_odb;
16+
int will_destroy;
1417
};
1518

1619
/*
@@ -38,6 +41,9 @@ static int tmp_objdir_destroy_1(struct tmp_objdir *t, int on_signal)
3841
if (t == the_tmp_objdir)
3942
the_tmp_objdir = NULL;
4043

44+
if (!on_signal && t->prev_odb)
45+
restore_primary_odb(t->prev_odb, t->path.buf);
46+
4147
/*
4248
* This may use malloc via strbuf_grow(), but we should
4349
* have pre-grown t->path sufficiently so that this
@@ -52,6 +58,7 @@ static int tmp_objdir_destroy_1(struct tmp_objdir *t, int on_signal)
5258
*/
5359
if (!on_signal)
5460
tmp_objdir_free(t);
61+
5562
return err;
5663
}
5764

@@ -121,19 +128,24 @@ static int setup_tmp_objdir(const char *root)
121128
return ret;
122129
}
123130

124-
struct tmp_objdir *tmp_objdir_create(void)
131+
struct tmp_objdir *tmp_objdir_create(const char *prefix)
125132
{
126133
static int installed_handlers;
127134
struct tmp_objdir *t;
128135

129136
if (the_tmp_objdir)
130137
BUG("only one tmp_objdir can be used at a time");
131138

132-
t = xmalloc(sizeof(*t));
139+
t = xcalloc(1, sizeof(*t));
133140
strbuf_init(&t->path, 0);
134141
strvec_init(&t->env);
135142

136-
strbuf_addf(&t->path, "%s/incoming-XXXXXX", get_object_directory());
143+
/*
144+
* Use a string starting with tmp_ so that the builtin/prune.c code
145+
* can recognize any stale objdirs left behind by a crash and delete
146+
* them.
147+
*/
148+
strbuf_addf(&t->path, "%s/tmp_objdir-%s-XXXXXX", get_object_directory(), prefix);
137149

138150
/*
139151
* Grow the strbuf beyond any filename we expect to be placed in it.
@@ -269,6 +281,13 @@ int tmp_objdir_migrate(struct tmp_objdir *t)
269281
if (!t)
270282
return 0;
271283

284+
if (t->prev_odb) {
285+
if (the_repository->objects->odb->will_destroy)
286+
BUG("migrating an ODB that was marked for destruction");
287+
restore_primary_odb(t->prev_odb, t->path.buf);
288+
t->prev_odb = NULL;
289+
}
290+
272291
strbuf_addbuf(&src, &t->path);
273292
strbuf_addstr(&dst, get_object_directory());
274293

@@ -292,3 +311,33 @@ void tmp_objdir_add_as_alternate(const struct tmp_objdir *t)
292311
{
293312
add_to_alternates_memory(t->path.buf);
294313
}
314+
315+
void tmp_objdir_replace_primary_odb(struct tmp_objdir *t, int will_destroy)
316+
{
317+
if (t->prev_odb)
318+
BUG("the primary object database is already replaced");
319+
t->prev_odb = set_temporary_primary_odb(t->path.buf, will_destroy);
320+
t->will_destroy = will_destroy;
321+
}
322+
323+
struct tmp_objdir *tmp_objdir_unapply_primary_odb(void)
324+
{
325+
if (!the_tmp_objdir || !the_tmp_objdir->prev_odb)
326+
return NULL;
327+
328+
restore_primary_odb(the_tmp_objdir->prev_odb, the_tmp_objdir->path.buf);
329+
the_tmp_objdir->prev_odb = NULL;
330+
return the_tmp_objdir;
331+
}
332+
333+
void tmp_objdir_reapply_primary_odb(struct tmp_objdir *t, const char *old_cwd,
334+
const char *new_cwd)
335+
{
336+
char *path;
337+
338+
path = reparent_relative_path(old_cwd, new_cwd, t->path.buf);
339+
strbuf_reset(&t->path);
340+
strbuf_addstr(&t->path, path);
341+
free(path);
342+
tmp_objdir_replace_primary_odb(t, t->will_destroy);
343+
}

tmp-objdir.h

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
*
1111
* Example:
1212
*
13-
* struct tmp_objdir *t = tmp_objdir_create();
13+
* struct tmp_objdir *t = tmp_objdir_create("incoming");
1414
* if (!run_command_v_opt_cd_env(cmd, 0, NULL, tmp_objdir_env(t)) &&
1515
* !tmp_objdir_migrate(t))
1616
* printf("success!\n");
@@ -22,9 +22,10 @@
2222
struct tmp_objdir;
2323

2424
/*
25-
* Create a new temporary object directory; returns NULL on failure.
25+
* Create a new temporary object directory with the specified prefix;
26+
* returns NULL on failure.
2627
*/
27-
struct tmp_objdir *tmp_objdir_create(void);
28+
struct tmp_objdir *tmp_objdir_create(const char *prefix);
2829

2930
/*
3031
* Return a list of environment strings, suitable for use with
@@ -51,4 +52,26 @@ int tmp_objdir_destroy(struct tmp_objdir *);
5152
*/
5253
void tmp_objdir_add_as_alternate(const struct tmp_objdir *);
5354

55+
/*
56+
* Replaces the writable object store in the current process with the temporary
57+
* object directory and makes the former main object store an alternate.
58+
* If will_destroy is nonzero, the object directory may not be migrated.
59+
*/
60+
void tmp_objdir_replace_primary_odb(struct tmp_objdir *, int will_destroy);
61+
62+
/*
63+
* If the primary object database was replaced by a temporary object directory,
64+
* restore it to its original value while keeping the directory contents around.
65+
* Returns NULL if the primary object database was not replaced.
66+
*/
67+
struct tmp_objdir *tmp_objdir_unapply_primary_odb(void);
68+
69+
/*
70+
* Reapplies the former primary temporary object database, after potentially
71+
* changing its relative path.
72+
*/
73+
void tmp_objdir_reapply_primary_odb(struct tmp_objdir *, const char *old_cwd,
74+
const char *new_cwd);
75+
76+
5477
#endif /* TMP_OBJDIR_H */

0 commit comments

Comments
 (0)