1 #include "git-compat-util.h"
4 #include "object-store.h"
6 #include "repository.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();
29 static int insert_oid_pair(kh_oid_map_t
*map
, const struct object_id
*key
, const struct object_id
*value
)
33 struct object_id
*stored
;
35 pos
= kh_put_oid_map(map
, *key
, &ret
);
37 /* This item already exists in the map. */
41 stored
= xmalloc(sizeof(*stored
));
42 oidcpy(stored
, value
);
43 kh_value(map
, pos
) = stored
;
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
;
54 inserted
|= insert_oid_pair(map
->to_compat
, oid
, compat_oid
);
55 inserted
|= insert_oid_pair(map
->to_storage
, compat_oid
, oid
);
57 oidtree_insert(odb
->loose_objects_cache
, compat_oid
);
62 static int load_one_loose_object_map(struct repository
*repo
, struct object_directory
*dir
)
64 struct strbuf buf
= STRBUF_INIT
, path
= STRBUF_INIT
;
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");
81 strbuf_release(&path
);
86 if (strbuf_getwholeline(&buf
, fp
, '\n') || strcmp(buf
.buf
, loose_object_header
))
88 while (!strbuf_getline_lf(&buf
, fp
)) {
90 struct object_id oid
, compat_oid
;
91 if (parse_oid_hex_algop(buf
.buf
, &oid
, &p
, repo
->hash_algo
) ||
93 parse_oid_hex_algop(p
, &compat_oid
, &p
, repo
->compat_hash_algo
) ||
94 p
!= buf
.buf
+ buf
.len
)
96 insert_loose_map(dir
, &oid
, &compat_oid
);
100 strbuf_release(&path
);
101 return errno
? -1 : 0;
103 strbuf_release(&buf
);
104 strbuf_release(&path
);
108 int repo_read_loose_object_map(struct repository
*repo
)
110 struct object_directory
*dir
;
112 if (!should_use_loose_object_map(repo
))
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) {
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
;
131 struct strbuf buf
= STRBUF_INIT
, path
= STRBUF_INIT
;
133 if (!should_use_loose_object_map(repo
))
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)
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
))
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)
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
);
159 strbuf_release(&path
);
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
);
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
;
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);
183 if (fstat(fd
, &st
) < 0)
185 if (!st
.st_size
&& write_in_full(fd
, loose_object_header
, strlen(loose_object_header
)) < 0)
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)
193 adjust_shared_perm(path
.buf
);
194 rollback_lock_file(&lock
);
195 strbuf_release(&buf
);
196 strbuf_release(&path
);
199 error_errno(_("failed to write loose object index %s"), path
.buf
);
201 rollback_lock_file(&lock
);
202 strbuf_release(&buf
);
203 strbuf_release(&path
);
207 int repo_add_loose_object_map(struct repository
*repo
, const struct object_id
*oid
,
208 const struct object_id
*compat_oid
)
212 if (!should_use_loose_object_map(repo
))
215 inserted
= insert_loose_map(repo
->objects
->odb
, oid
, compat_oid
);
217 return write_one_object(repo
, oid
, compat_oid
);
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
;
230 for (dir
= repo
->objects
->odb
; dir
; dir
= dir
->next
) {
231 struct loose_object_map
*loose_map
= dir
->loose_map
;
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
));
246 void loose_object_map_clear(struct loose_object_map
**map
)
248 struct loose_object_map
*m
= *map
;
249 struct object_id
*oid
;
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
);