Merge branch 'js/for-each-repo-keep-going'
[git/gitster.git] / loose.c
blobf6faa6216a0812b7909a034e8abac5ee00e355c2
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 "wrapper.h"
7 #include "gettext.h"
8 #include "loose.h"
9 #include "lockfile.h"
10 #include "oidtree.h"
12 static const char *loose_object_header = "# loose-object-idx\n";
14 static inline int should_use_loose_object_map(struct repository *repo)
16 return repo->compat_hash_algo && repo->gitdir;
19 void loose_object_map_init(struct loose_object_map **map)
21 struct loose_object_map *m;
22 m = xmalloc(sizeof(**map));
23 m->to_compat = kh_init_oid_map();
24 m->to_storage = kh_init_oid_map();
25 *map = m;
28 static int insert_oid_pair(kh_oid_map_t *map, const struct object_id *key, const struct object_id *value)
30 khiter_t pos;
31 int ret;
32 struct object_id *stored;
34 pos = kh_put_oid_map(map, *key, &ret);
36 /* This item already exists in the map. */
37 if (ret == 0)
38 return 0;
40 stored = xmalloc(sizeof(*stored));
41 oidcpy(stored, value);
42 kh_value(map, pos) = stored;
43 return 1;
46 static int insert_loose_map(struct object_directory *odb,
47 const struct object_id *oid,
48 const struct object_id *compat_oid)
50 struct loose_object_map *map = odb->loose_map;
51 int inserted = 0;
53 inserted |= insert_oid_pair(map->to_compat, oid, compat_oid);
54 inserted |= insert_oid_pair(map->to_storage, compat_oid, oid);
55 if (inserted)
56 oidtree_insert(odb->loose_objects_cache, compat_oid);
58 return inserted;
61 static int load_one_loose_object_map(struct repository *repo, struct object_directory *dir)
63 struct strbuf buf = STRBUF_INIT, path = STRBUF_INIT;
64 FILE *fp;
66 if (!dir->loose_map)
67 loose_object_map_init(&dir->loose_map);
68 if (!dir->loose_objects_cache) {
69 ALLOC_ARRAY(dir->loose_objects_cache, 1);
70 oidtree_init(dir->loose_objects_cache);
73 insert_loose_map(dir, repo->hash_algo->empty_tree, repo->compat_hash_algo->empty_tree);
74 insert_loose_map(dir, repo->hash_algo->empty_blob, repo->compat_hash_algo->empty_blob);
75 insert_loose_map(dir, repo->hash_algo->null_oid, repo->compat_hash_algo->null_oid);
77 strbuf_git_common_path(&path, repo, "objects/loose-object-idx");
78 fp = fopen(path.buf, "rb");
79 if (!fp) {
80 strbuf_release(&path);
81 return 0;
84 errno = 0;
85 if (strbuf_getwholeline(&buf, fp, '\n') || strcmp(buf.buf, loose_object_header))
86 goto err;
87 while (!strbuf_getline_lf(&buf, fp)) {
88 const char *p;
89 struct object_id oid, compat_oid;
90 if (parse_oid_hex_algop(buf.buf, &oid, &p, repo->hash_algo) ||
91 *p++ != ' ' ||
92 parse_oid_hex_algop(p, &compat_oid, &p, repo->compat_hash_algo) ||
93 p != buf.buf + buf.len)
94 goto err;
95 insert_loose_map(dir, &oid, &compat_oid);
98 strbuf_release(&buf);
99 strbuf_release(&path);
100 return errno ? -1 : 0;
101 err:
102 strbuf_release(&buf);
103 strbuf_release(&path);
104 return -1;
107 int repo_read_loose_object_map(struct repository *repo)
109 struct object_directory *dir;
111 if (!should_use_loose_object_map(repo))
112 return 0;
114 prepare_alt_odb(repo);
116 for (dir = repo->objects->odb; dir; dir = dir->next) {
117 if (load_one_loose_object_map(repo, dir) < 0) {
118 return -1;
121 return 0;
124 int repo_write_loose_object_map(struct repository *repo)
126 kh_oid_map_t *map = repo->objects->odb->loose_map->to_compat;
127 struct lock_file lock;
128 int fd;
129 khiter_t iter;
130 struct strbuf buf = STRBUF_INIT, path = STRBUF_INIT;
132 if (!should_use_loose_object_map(repo))
133 return 0;
135 strbuf_git_common_path(&path, repo, "objects/loose-object-idx");
136 fd = hold_lock_file_for_update_timeout(&lock, path.buf, LOCK_DIE_ON_ERROR, -1);
137 iter = kh_begin(map);
138 if (write_in_full(fd, loose_object_header, strlen(loose_object_header)) < 0)
139 goto errout;
141 for (; iter != kh_end(map); iter++) {
142 if (kh_exist(map, iter)) {
143 if (oideq(&kh_key(map, iter), the_hash_algo->empty_tree) ||
144 oideq(&kh_key(map, iter), the_hash_algo->empty_blob))
145 continue;
146 strbuf_addf(&buf, "%s %s\n", oid_to_hex(&kh_key(map, iter)), oid_to_hex(kh_value(map, iter)));
147 if (write_in_full(fd, buf.buf, buf.len) < 0)
148 goto errout;
149 strbuf_reset(&buf);
152 strbuf_release(&buf);
153 if (commit_lock_file(&lock) < 0) {
154 error_errno(_("could not write loose object index %s"), path.buf);
155 strbuf_release(&path);
156 return -1;
158 strbuf_release(&path);
159 return 0;
160 errout:
161 rollback_lock_file(&lock);
162 strbuf_release(&buf);
163 error_errno(_("failed to write loose object index %s\n"), path.buf);
164 strbuf_release(&path);
165 return -1;
168 static int write_one_object(struct repository *repo, const struct object_id *oid,
169 const struct object_id *compat_oid)
171 struct lock_file lock;
172 int fd;
173 struct stat st;
174 struct strbuf buf = STRBUF_INIT, path = STRBUF_INIT;
176 strbuf_git_common_path(&path, repo, "objects/loose-object-idx");
177 hold_lock_file_for_update_timeout(&lock, path.buf, LOCK_DIE_ON_ERROR, -1);
179 fd = open(path.buf, O_WRONLY | O_CREAT | O_APPEND, 0666);
180 if (fd < 0)
181 goto errout;
182 if (fstat(fd, &st) < 0)
183 goto errout;
184 if (!st.st_size && write_in_full(fd, loose_object_header, strlen(loose_object_header)) < 0)
185 goto errout;
187 strbuf_addf(&buf, "%s %s\n", oid_to_hex(oid), oid_to_hex(compat_oid));
188 if (write_in_full(fd, buf.buf, buf.len) < 0)
189 goto errout;
190 if (close(fd))
191 goto errout;
192 adjust_shared_perm(path.buf);
193 rollback_lock_file(&lock);
194 strbuf_release(&buf);
195 strbuf_release(&path);
196 return 0;
197 errout:
198 error_errno(_("failed to write loose object index %s\n"), path.buf);
199 close(fd);
200 rollback_lock_file(&lock);
201 strbuf_release(&buf);
202 strbuf_release(&path);
203 return -1;
206 int repo_add_loose_object_map(struct repository *repo, const struct object_id *oid,
207 const struct object_id *compat_oid)
209 int inserted = 0;
211 if (!should_use_loose_object_map(repo))
212 return 0;
214 inserted = insert_loose_map(repo->objects->odb, oid, compat_oid);
215 if (inserted)
216 return write_one_object(repo, oid, compat_oid);
217 return 0;
220 int repo_loose_object_map_oid(struct repository *repo,
221 const struct object_id *src,
222 const struct git_hash_algo *to,
223 struct object_id *dest)
225 struct object_directory *dir;
226 kh_oid_map_t *map;
227 khiter_t pos;
229 for (dir = repo->objects->odb; dir; dir = dir->next) {
230 struct loose_object_map *loose_map = dir->loose_map;
231 if (!loose_map)
232 continue;
233 map = (to == repo->compat_hash_algo) ?
234 loose_map->to_compat :
235 loose_map->to_storage;
236 pos = kh_get_oid_map(map, *src);
237 if (pos < kh_end(map)) {
238 oidcpy(dest, kh_value(map, pos));
239 return 0;
242 return -1;
245 void loose_object_map_clear(struct loose_object_map **map)
247 struct loose_object_map *m = *map;
248 struct object_id *oid;
250 if (!m)
251 return;
253 kh_foreach_value(m->to_compat, oid, free(oid));
254 kh_foreach_value(m->to_storage, oid, free(oid));
255 kh_destroy_oid_map(m->to_compat);
256 kh_destroy_oid_map(m->to_storage);
257 free(m);
258 *map = NULL;