loose: don't rely on repository global state
[git/gitster.git] / loose.c
blob897ba389daa18cbb72ca8ce2ecbeb77ecdad1a55
1 #include "git-compat-util.h"
2 #include "hash.h"
3 #include "path.h"
4 #include "object-store.h"
5 #include "hex.h"
6 #include "repository.h"
7 #include "wrapper.h"
8 #include "gettext.h"
9 #include "loose.h"
10 #include "lockfile.h"
11 #include "oidtree.h"
13 static const char *loose_object_header = "# loose-object-idx\n";
15 static inline int should_use_loose_object_map(struct repository *repo)
17 return repo->compat_hash_algo && repo->gitdir;
20 void loose_object_map_init(struct loose_object_map **map)
22 struct loose_object_map *m;
23 m = xmalloc(sizeof(**map));
24 m->to_compat = kh_init_oid_map();
25 m->to_storage = kh_init_oid_map();
26 *map = m;
29 static int insert_oid_pair(kh_oid_map_t *map, const struct object_id *key, const struct object_id *value)
31 khiter_t pos;
32 int ret;
33 struct object_id *stored;
35 pos = kh_put_oid_map(map, *key, &ret);
37 /* This item already exists in the map. */
38 if (ret == 0)
39 return 0;
41 stored = xmalloc(sizeof(*stored));
42 oidcpy(stored, value);
43 kh_value(map, pos) = stored;
44 return 1;
47 static int insert_loose_map(struct object_directory *odb,
48 const struct object_id *oid,
49 const struct object_id *compat_oid)
51 struct loose_object_map *map = odb->loose_map;
52 int inserted = 0;
54 inserted |= insert_oid_pair(map->to_compat, oid, compat_oid);
55 inserted |= insert_oid_pair(map->to_storage, compat_oid, oid);
56 if (inserted)
57 oidtree_insert(odb->loose_objects_cache, compat_oid);
59 return inserted;
62 static int load_one_loose_object_map(struct repository *repo, struct object_directory *dir)
64 struct strbuf buf = STRBUF_INIT, path = STRBUF_INIT;
65 FILE *fp;
67 if (!dir->loose_map)
68 loose_object_map_init(&dir->loose_map);
69 if (!dir->loose_objects_cache) {
70 ALLOC_ARRAY(dir->loose_objects_cache, 1);
71 oidtree_init(dir->loose_objects_cache);
74 insert_loose_map(dir, repo->hash_algo->empty_tree, repo->compat_hash_algo->empty_tree);
75 insert_loose_map(dir, repo->hash_algo->empty_blob, repo->compat_hash_algo->empty_blob);
76 insert_loose_map(dir, repo->hash_algo->null_oid, repo->compat_hash_algo->null_oid);
78 strbuf_git_common_path(&path, repo, "objects/loose-object-idx");
79 fp = fopen(path.buf, "rb");
80 if (!fp) {
81 strbuf_release(&path);
82 return 0;
85 errno = 0;
86 if (strbuf_getwholeline(&buf, fp, '\n') || strcmp(buf.buf, loose_object_header))
87 goto err;
88 while (!strbuf_getline_lf(&buf, fp)) {
89 const char *p;
90 struct object_id oid, compat_oid;
91 if (parse_oid_hex_algop(buf.buf, &oid, &p, repo->hash_algo) ||
92 *p++ != ' ' ||
93 parse_oid_hex_algop(p, &compat_oid, &p, repo->compat_hash_algo) ||
94 p != buf.buf + buf.len)
95 goto err;
96 insert_loose_map(dir, &oid, &compat_oid);
99 strbuf_release(&buf);
100 strbuf_release(&path);
101 return errno ? -1 : 0;
102 err:
103 strbuf_release(&buf);
104 strbuf_release(&path);
105 return -1;
108 int repo_read_loose_object_map(struct repository *repo)
110 struct object_directory *dir;
112 if (!should_use_loose_object_map(repo))
113 return 0;
115 prepare_alt_odb(repo);
117 for (dir = repo->objects->odb; dir; dir = dir->next) {
118 if (load_one_loose_object_map(repo, dir) < 0) {
119 return -1;
122 return 0;
125 int repo_write_loose_object_map(struct repository *repo)
127 kh_oid_map_t *map = repo->objects->odb->loose_map->to_compat;
128 struct lock_file lock;
129 int fd;
130 khiter_t iter;
131 struct strbuf buf = STRBUF_INIT, path = STRBUF_INIT;
133 if (!should_use_loose_object_map(repo))
134 return 0;
136 strbuf_git_common_path(&path, repo, "objects/loose-object-idx");
137 fd = hold_lock_file_for_update_timeout(&lock, path.buf, LOCK_DIE_ON_ERROR, -1);
138 iter = kh_begin(map);
139 if (write_in_full(fd, loose_object_header, strlen(loose_object_header)) < 0)
140 goto errout;
142 for (; iter != kh_end(map); iter++) {
143 if (kh_exist(map, iter)) {
144 if (oideq(&kh_key(map, iter), repo->hash_algo->empty_tree) ||
145 oideq(&kh_key(map, iter), repo->hash_algo->empty_blob))
146 continue;
147 strbuf_addf(&buf, "%s %s\n", oid_to_hex(&kh_key(map, iter)), oid_to_hex(kh_value(map, iter)));
148 if (write_in_full(fd, buf.buf, buf.len) < 0)
149 goto errout;
150 strbuf_reset(&buf);
153 strbuf_release(&buf);
154 if (commit_lock_file(&lock) < 0) {
155 error_errno(_("could not write loose object index %s"), path.buf);
156 strbuf_release(&path);
157 return -1;
159 strbuf_release(&path);
160 return 0;
161 errout:
162 rollback_lock_file(&lock);
163 strbuf_release(&buf);
164 error_errno(_("failed to write loose object index %s"), path.buf);
165 strbuf_release(&path);
166 return -1;
169 static int write_one_object(struct repository *repo, const struct object_id *oid,
170 const struct object_id *compat_oid)
172 struct lock_file lock;
173 int fd;
174 struct stat st;
175 struct strbuf buf = STRBUF_INIT, path = STRBUF_INIT;
177 strbuf_git_common_path(&path, repo, "objects/loose-object-idx");
178 hold_lock_file_for_update_timeout(&lock, path.buf, LOCK_DIE_ON_ERROR, -1);
180 fd = open(path.buf, O_WRONLY | O_CREAT | O_APPEND, 0666);
181 if (fd < 0)
182 goto errout;
183 if (fstat(fd, &st) < 0)
184 goto errout;
185 if (!st.st_size && write_in_full(fd, loose_object_header, strlen(loose_object_header)) < 0)
186 goto errout;
188 strbuf_addf(&buf, "%s %s\n", oid_to_hex(oid), oid_to_hex(compat_oid));
189 if (write_in_full(fd, buf.buf, buf.len) < 0)
190 goto errout;
191 if (close(fd))
192 goto errout;
193 adjust_shared_perm(path.buf);
194 rollback_lock_file(&lock);
195 strbuf_release(&buf);
196 strbuf_release(&path);
197 return 0;
198 errout:
199 error_errno(_("failed to write loose object index %s"), path.buf);
200 close(fd);
201 rollback_lock_file(&lock);
202 strbuf_release(&buf);
203 strbuf_release(&path);
204 return -1;
207 int repo_add_loose_object_map(struct repository *repo, const struct object_id *oid,
208 const struct object_id *compat_oid)
210 int inserted = 0;
212 if (!should_use_loose_object_map(repo))
213 return 0;
215 inserted = insert_loose_map(repo->objects->odb, oid, compat_oid);
216 if (inserted)
217 return write_one_object(repo, oid, compat_oid);
218 return 0;
221 int repo_loose_object_map_oid(struct repository *repo,
222 const struct object_id *src,
223 const struct git_hash_algo *to,
224 struct object_id *dest)
226 struct object_directory *dir;
227 kh_oid_map_t *map;
228 khiter_t pos;
230 for (dir = repo->objects->odb; dir; dir = dir->next) {
231 struct loose_object_map *loose_map = dir->loose_map;
232 if (!loose_map)
233 continue;
234 map = (to == repo->compat_hash_algo) ?
235 loose_map->to_compat :
236 loose_map->to_storage;
237 pos = kh_get_oid_map(map, *src);
238 if (pos < kh_end(map)) {
239 oidcpy(dest, kh_value(map, pos));
240 return 0;
243 return -1;
246 void loose_object_map_clear(struct loose_object_map **map)
248 struct loose_object_map *m = *map;
249 struct object_id *oid;
251 if (!m)
252 return;
254 kh_foreach_value(m->to_compat, oid, free(oid));
255 kh_foreach_value(m->to_storage, oid, free(oid));
256 kh_destroy_oid_map(m->to_compat);
257 kh_destroy_oid_map(m->to_storage);
258 free(m);
259 *map = NULL;