2 * Copyright (C) the libgit2 contributors. All rights reserved.
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
11 #include "git2/repository.h"
12 #include "git2/indexer.h"
13 #include "git2/sys/odb_backend.h"
22 #include "git2/odb_backend.h"
24 /* re-freshen pack files no more than every 2 seconds */
25 #define FRESHEN_FREQUENCY 2
28 git_odb_backend parent
;
30 git_vector midx_packs
;
32 struct git_pack_file
*last_found
;
36 struct pack_writepack
{
37 struct git_odb_writepack parent
;
42 * The wonderful tale of a Packed Object lookup query
43 * ===================================================
44 * A riveting and epic story of epicness and ASCII
45 * art, presented by yours truly,
49 * Chapter 1: Once upon a time...
50 * Initialization of the Pack Backend
51 * --------------------------------------------------
53 * # git_odb_backend_pack
54 * | Creates the pack backend structure, initializes the
55 * | callback pointers to our default read() and exist() methods,
56 * | and tries to find the `pack` folder, if it exists. ODBs without a `pack`
57 * | folder are ignored altogether. If there is a `pack` folder, it tries to
58 * | preload all the known packfiles in the ODB.
60 * |-# pack_backend__refresh
61 * | The `multi-pack-index` is loaded if it exists and is valid.
62 * | Then we run a `dirent` callback through every file in the pack folder,
63 * | even those present in `multi-pack-index`. The unindexed packfiles are
64 * | then sorted according to a sorting callback.
66 * |-# refresh_multi_pack_index
67 * | Detect the presence of the `multi-pack-index` file. If it needs to be
68 * | refreshed, frees the old copy and tries to load the new one, together
69 * | with all the packfiles it indexes. If the process fails, fall back to
70 * | the old behavior, as if the `multi-pack-index` file was not there.
72 * |-# packfile_load__cb
73 * | | This callback is called from `dirent` with every single file
74 * | | inside the pack folder. We find the packs by actually locating
75 * | | their index (ends in ".idx"). From that index, we verify that
76 * | | the corresponding packfile exists and is valid, and if so, we
77 * | | add it to the pack list.
79 * | # git_mwindow_get_pack
80 * | Make sure that there's a packfile to back this index, and store
81 * | some very basic information regarding the packfile itself,
82 * | such as the full path, the size, and the modification time.
83 * | We don't actually open the packfile to check for internal consistency.
85 * |-# packfile_sort__cb
86 * Sort all the preloaded packs according to some specific criteria:
87 * we prioritize the "newer" packs because it's more likely they
88 * contain the objects we are looking for, and we prioritize local
89 * packs over remote ones.
93 * Chapter 2: To be, or not to be...
94 * A standard packed `exist` query for an OID
95 * --------------------------------------------------
97 * # pack_backend__exists / pack_backend__exists_prefix
98 * | Check if the given SHA1 oid (or a SHA1 oid prefix) exists in any of the
99 * | packs that have been loaded for our ODB.
101 * |-# pack_entry_find / pack_entry_find_prefix
102 * | If there is a multi-pack-index present, search the SHA1 oid in that
103 * | index first. If it is not found there, iterate through all the unindexed
104 * | packs that have been preloaded (starting by the pack where the latest
105 * | object was found) to try to find the OID in one of them.
107 * |-# git_midx_entry_find
108 * | Search for the SHA1 oid in the multi-pack-index. See
109 * | <https://github.com/git/git/blob/master/Documentation/technical/pack-format.txt>
110 * | for specifics on the multi-pack-index format and how do we find
113 * |-# git_pack_entry_find
114 * | Check the index of an individual unindexed pack to see if the SHA1
115 * | OID can be found. If we can find the offset to that SHA1 inside of the
116 * | index, that means the object is contained inside of the packfile and
117 * | we can stop searching. Before returning, we verify that the
118 * | packfile behind the index we are searching still exists on disk.
120 * |-# pack_entry_find_offset
121 * | Mmap the actual index file to disk if it hasn't been opened
122 * | yet, and run a binary search through it to find the OID.
123 * | See <https://github.com/git/git/blob/master/Documentation/technical/pack-format.txt>
124 * | for specifics on the Packfile Index format and how do we find
127 * |-# pack_index_open
128 * | Guess the name of the index based on the full path to the
129 * | packfile, open it and verify its contents. Only if the index
130 * | has not been opened already.
132 * |-# pack_index_check
133 * Mmap the index file and do a quick run through the header
134 * to guess the index version (right now we support v1 and v2),
135 * and to verify that the size of the index makes sense.
139 * Chapter 3: The neverending story...
140 * A standard packed `lookup` query for an OID
141 * --------------------------------------------------
143 * # pack_backend__read / pack_backend__read_prefix
144 * | Check if the given SHA1 oid (or a SHA1 oid prefix) exists in any of the
145 * | packs that have been loaded for our ODB. If it does, open the packfile and
148 * |-# git_packfile_unpack
149 * Armed with a packfile and the offset within it, we can finally unpack
150 * the object pointed at by the SHA1 oid. This involves mmapping part of
151 * the `.pack` file, and uncompressing the object within it (if it is
152 * stored in the undelfitied representation), or finding a base object and
153 * applying some deltas to its uncompressed representation (if it is stored
154 * in the deltified representation). See
155 * <https://github.com/git/git/blob/master/Documentation/technical/pack-format.txt>
156 * for specifics on the Packfile format and how do we read from it.
161 /***********************************************************
163 * FORWARD DECLARATIONS
165 ***********************************************************/
167 static int packfile_sort__cb(const void *a_
, const void *b_
);
169 static int packfile_load__cb(void *_data
, git_str
*path
);
171 static int packfile_byname_search_cmp(const void *path
, const void *pack_entry
);
173 static int pack_entry_find(struct git_pack_entry
*e
,
174 struct pack_backend
*backend
, const git_oid
*oid
);
176 /* Can find the offset of an object given
177 * a prefix of an identifier.
178 * Sets GIT_EAMBIGUOUS if short oid is ambiguous.
179 * This method assumes that len is between
180 * GIT_OID_MINPREFIXLEN and GIT_OID_HEXSZ.
182 static int pack_entry_find_prefix(
183 struct git_pack_entry
*e
,
184 struct pack_backend
*backend
,
185 const git_oid
*short_oid
,
190 /***********************************************************
192 * PACK WINDOW MANAGEMENT
194 ***********************************************************/
196 static int packfile_byname_search_cmp(const void *path_
, const void *p_
)
198 const git_str
*path
= (const git_str
*)path_
;
199 const struct git_pack_file
*p
= (const struct git_pack_file
*)p_
;
201 return strncmp(p
->pack_name
, git_str_cstr(path
), git_str_len(path
));
204 static int packfile_sort__cb(const void *a_
, const void *b_
)
206 const struct git_pack_file
*a
= a_
;
207 const struct git_pack_file
*b
= b_
;
211 * Local packs tend to contain objects specific to our
212 * variant of the project than remote ones. In addition,
213 * remote ones could be on a network mounted filesystem.
214 * Favor local ones for these reasons.
216 st
= a
->pack_local
- b
->pack_local
;
221 * Younger packs tend to contain more recent objects,
222 * and more recent objects tend to get accessed more
225 if (a
->mtime
< b
->mtime
)
227 else if (a
->mtime
== b
->mtime
)
234 static int packfile_load__cb(void *data
, git_str
*path
)
236 struct pack_backend
*backend
= data
;
237 struct git_pack_file
*pack
;
238 const char *path_str
= git_str_cstr(path
);
239 git_str index_prefix
= GIT_STR_INIT
;
240 size_t cmp_len
= git_str_len(path
);
243 if (cmp_len
<= strlen(".idx") || git__suffixcmp(path_str
, ".idx") != 0)
244 return 0; /* not an index */
246 cmp_len
-= strlen(".idx");
247 git_str_attach_notowned(&index_prefix
, path_str
, cmp_len
);
249 if (git_vector_search2(NULL
, &backend
->midx_packs
, packfile_byname_search_cmp
, &index_prefix
) == 0)
251 if (git_vector_search2(NULL
, &backend
->packs
, packfile_byname_search_cmp
, &index_prefix
) == 0)
254 error
= git_mwindow_get_pack(&pack
, path
->ptr
);
256 /* ignore missing .pack file as git does */
257 if (error
== GIT_ENOTFOUND
) {
263 error
= git_vector_insert(&backend
->packs
, pack
);
269 static int pack_entry_find(struct git_pack_entry
*e
, struct pack_backend
*backend
, const git_oid
*oid
)
271 struct git_pack_file
*last_found
= backend
->last_found
, *p
;
272 git_midx_entry midx_entry
;
276 git_midx_entry_find(&midx_entry
, backend
->midx
, oid
, GIT_OID_HEXSZ
) == 0 &&
277 midx_entry
.pack_index
< git_vector_length(&backend
->midx_packs
)) {
278 e
->offset
= midx_entry
.offset
;
279 git_oid_cpy(&e
->sha1
, &midx_entry
.sha1
);
280 e
->p
= git_vector_get(&backend
->midx_packs
, midx_entry
.pack_index
);
285 git_pack_entry_find(e
, last_found
, oid
, GIT_OID_HEXSZ
) == 0)
288 git_vector_foreach(&backend
->packs
, i
, p
) {
292 if (git_pack_entry_find(e
, p
, oid
, GIT_OID_HEXSZ
) == 0) {
293 backend
->last_found
= p
;
298 return git_odb__error_notfound(
299 "failed to find pack entry", oid
, GIT_OID_HEXSZ
);
302 static int pack_entry_find_prefix(
303 struct git_pack_entry
*e
,
304 struct pack_backend
*backend
,
305 const git_oid
*short_oid
,
310 git_oid found_full_oid
= {{0}};
312 struct git_pack_file
*last_found
= backend
->last_found
, *p
;
313 git_midx_entry midx_entry
;
316 error
= git_midx_entry_find(&midx_entry
, backend
->midx
, short_oid
, len
);
317 if (error
== GIT_EAMBIGUOUS
)
319 if (!error
&& midx_entry
.pack_index
< git_vector_length(&backend
->midx_packs
)) {
320 e
->offset
= midx_entry
.offset
;
321 git_oid_cpy(&e
->sha1
, &midx_entry
.sha1
);
322 e
->p
= git_vector_get(&backend
->midx_packs
, midx_entry
.pack_index
);
323 git_oid_cpy(&found_full_oid
, &e
->sha1
);
329 error
= git_pack_entry_find(e
, last_found
, short_oid
, len
);
330 if (error
== GIT_EAMBIGUOUS
)
333 if (found
&& git_oid_cmp(&e
->sha1
, &found_full_oid
))
334 return git_odb__error_ambiguous("found multiple pack entries");
335 git_oid_cpy(&found_full_oid
, &e
->sha1
);
340 git_vector_foreach(&backend
->packs
, i
, p
) {
344 error
= git_pack_entry_find(e
, p
, short_oid
, len
);
345 if (error
== GIT_EAMBIGUOUS
)
348 if (found
&& git_oid_cmp(&e
->sha1
, &found_full_oid
))
349 return git_odb__error_ambiguous("found multiple pack entries");
350 git_oid_cpy(&found_full_oid
, &e
->sha1
);
352 backend
->last_found
= p
;
357 return git_odb__error_notfound("no matching pack entry for prefix",
363 /***********************************************************
365 * MULTI-PACK-INDEX SUPPORT
367 * Functions needed to support the multi-pack-index.
369 ***********************************************************/
372 * Remove the multi-pack-index, and move all midx_packs to packs.
374 static int remove_multi_pack_index(struct pack_backend
*backend
)
376 size_t i
, j
= git_vector_length(&backend
->packs
);
377 struct pack_backend
*p
;
378 int error
= git_vector_size_hint(
380 j
+ git_vector_length(&backend
->midx_packs
));
384 git_vector_foreach(&backend
->midx_packs
, i
, p
)
385 git_vector_set(NULL
, &backend
->packs
, j
++, p
);
386 git_vector_clear(&backend
->midx_packs
);
388 git_midx_free(backend
->midx
);
389 backend
->midx
= NULL
;
395 * Loads a single .pack file referred to by the multi-pack-index. These must
396 * match the order in which they are declared in the multi-pack-index file,
397 * since these files are referred to by their index.
399 static int process_multi_pack_index_pack(
400 struct pack_backend
*backend
,
402 const char *packfile_name
)
405 struct git_pack_file
*pack
;
406 size_t found_position
;
407 git_str pack_path
= GIT_STR_INIT
, index_prefix
= GIT_STR_INIT
;
409 error
= git_str_joinpath(&pack_path
, backend
->pack_folder
, packfile_name
);
413 /* This is ensured by midx_parse_packfile_name() */
414 if (git_str_len(&pack_path
) <= strlen(".idx") || git__suffixcmp(git_str_cstr(&pack_path
), ".idx") != 0)
415 return git_odb__error_notfound("midx file contained a non-index", NULL
, 0);
417 git_str_attach_notowned(&index_prefix
, git_str_cstr(&pack_path
), git_str_len(&pack_path
) - strlen(".idx"));
419 if (git_vector_search2(&found_position
, &backend
->packs
, packfile_byname_search_cmp
, &index_prefix
) == 0) {
420 /* Pack was found in the packs list. Moving it to the midx_packs list. */
421 git_str_dispose(&pack_path
);
422 git_vector_set(NULL
, &backend
->midx_packs
, i
, git_vector_get(&backend
->packs
, found_position
));
423 git_vector_remove(&backend
->packs
, found_position
);
427 /* Pack was not found. Allocate a new one. */
428 error
= git_mwindow_get_pack(&pack
, git_str_cstr(&pack_path
));
429 git_str_dispose(&pack_path
);
433 git_vector_set(NULL
, &backend
->midx_packs
, i
, pack
);
438 * Reads the multi-pack-index. If this fails for whatever reason, the
439 * multi-pack-index object is freed, and all the packfiles that are related to
440 * it are moved to the unindexed packfiles vector.
442 static int refresh_multi_pack_index(struct pack_backend
*backend
)
445 git_str midx_path
= GIT_STR_INIT
;
446 const char *packfile_name
;
449 error
= git_str_joinpath(&midx_path
, backend
->pack_folder
, "multi-pack-index");
454 * Check whether the multi-pack-index has changed. If it has, close any
455 * old multi-pack-index and move all the packfiles to the unindexed
456 * packs. This is done to prevent losing any open packfiles in case
457 * refreshing the new multi-pack-index fails, or the file is deleted.
460 if (!git_midx_needs_refresh(backend
->midx
, git_str_cstr(&midx_path
))) {
461 git_str_dispose(&midx_path
);
464 error
= remove_multi_pack_index(backend
);
466 git_str_dispose(&midx_path
);
471 error
= git_midx_open(&backend
->midx
, git_str_cstr(&midx_path
));
472 git_str_dispose(&midx_path
);
476 git_vector_resize_to(&backend
->midx_packs
, git_vector_length(&backend
->midx
->packfile_names
));
478 git_vector_foreach(&backend
->midx
->packfile_names
, i
, packfile_name
) {
479 error
= process_multi_pack_index_pack(backend
, i
, packfile_name
);
482 * Something failed during reading multi-pack-index.
483 * Restore the state of backend as if the
484 * multi-pack-index was never there, and move all
485 * packfiles that have been processed so far to the
488 git_vector_resize_to(&backend
->midx_packs
, i
);
489 remove_multi_pack_index(backend
);
497 /***********************************************************
499 * PACKED BACKEND PUBLIC API
501 * Implement the git_odb_backend API calls
503 ***********************************************************/
504 static int pack_backend__refresh(git_odb_backend
*backend_
)
508 git_str path
= GIT_STR_INIT
;
509 struct pack_backend
*backend
= (struct pack_backend
*)backend_
;
511 if (backend
->pack_folder
== NULL
)
514 if (p_stat(backend
->pack_folder
, &st
) < 0 || !S_ISDIR(st
.st_mode
))
515 return git_odb__error_notfound("failed to refresh packfiles", NULL
, 0);
517 if (refresh_multi_pack_index(backend
) < 0) {
519 * It is okay if this fails. We will just not use the
520 * multi-pack-index in this case.
525 /* reload all packs */
526 git_str_sets(&path
, backend
->pack_folder
);
527 error
= git_fs_path_direach(&path
, 0, packfile_load__cb
, backend
);
529 git_str_dispose(&path
);
530 git_vector_sort(&backend
->packs
);
535 static int pack_backend__read_header(
536 size_t *len_p
, git_object_t
*type_p
,
537 struct git_odb_backend
*backend
, const git_oid
*oid
)
539 struct git_pack_entry e
;
542 GIT_ASSERT_ARG(len_p
);
543 GIT_ASSERT_ARG(type_p
);
544 GIT_ASSERT_ARG(backend
);
547 if ((error
= pack_entry_find(&e
, (struct pack_backend
*)backend
, oid
)) < 0)
550 return git_packfile_resolve_header(len_p
, type_p
, e
.p
, e
.offset
);
553 static int pack_backend__freshen(
554 git_odb_backend
*backend
, const git_oid
*oid
)
556 struct git_pack_entry e
;
560 if ((error
= pack_entry_find(&e
, (struct pack_backend
*)backend
, oid
)) < 0)
565 if (e
.p
->last_freshen
> now
- FRESHEN_FREQUENCY
)
568 if ((error
= git_futils_touch(e
.p
->pack_name
, &now
)) < 0)
571 e
.p
->last_freshen
= now
;
575 static int pack_backend__read(
576 void **buffer_p
, size_t *len_p
, git_object_t
*type_p
,
577 git_odb_backend
*backend
, const git_oid
*oid
)
579 struct git_pack_entry e
;
580 git_rawobj raw
= {NULL
};
583 if ((error
= pack_entry_find(&e
, (struct pack_backend
*)backend
, oid
)) < 0 ||
584 (error
= git_packfile_unpack(&raw
, e
.p
, &e
.offset
)) < 0)
587 *buffer_p
= raw
.data
;
594 static int pack_backend__read_prefix(
598 git_object_t
*type_p
,
599 git_odb_backend
*backend
,
600 const git_oid
*short_oid
,
605 if (len
< GIT_OID_MINPREFIXLEN
)
606 error
= git_odb__error_ambiguous("prefix length too short");
608 else if (len
>= GIT_OID_HEXSZ
) {
609 /* We can fall back to regular read method */
610 error
= pack_backend__read(buffer_p
, len_p
, type_p
, backend
, short_oid
);
612 git_oid_cpy(out_oid
, short_oid
);
614 struct git_pack_entry e
;
615 git_rawobj raw
= {NULL
};
617 if ((error
= pack_entry_find_prefix(
618 &e
, (struct pack_backend
*)backend
, short_oid
, len
)) == 0 &&
619 (error
= git_packfile_unpack(&raw
, e
.p
, &e
.offset
)) == 0)
621 *buffer_p
= raw
.data
;
624 git_oid_cpy(out_oid
, &e
.sha1
);
631 static int pack_backend__exists(git_odb_backend
*backend
, const git_oid
*oid
)
633 struct git_pack_entry e
;
634 return pack_entry_find(&e
, (struct pack_backend
*)backend
, oid
) == 0;
637 static int pack_backend__exists_prefix(
638 git_oid
*out
, git_odb_backend
*backend
, const git_oid
*short_id
, size_t len
)
641 struct pack_backend
*pb
= (struct pack_backend
*)backend
;
642 struct git_pack_entry e
= {0};
644 error
= pack_entry_find_prefix(&e
, pb
, short_id
, len
);
645 git_oid_cpy(out
, &e
.sha1
);
649 static int pack_backend__foreach(git_odb_backend
*_backend
, git_odb_foreach_cb cb
, void *data
)
652 struct git_pack_file
*p
;
653 struct pack_backend
*backend
;
656 GIT_ASSERT_ARG(_backend
);
659 backend
= (struct pack_backend
*)_backend
;
661 /* Make sure we know about the packfiles */
662 if ((error
= pack_backend__refresh(_backend
)) != 0)
665 if (backend
->midx
&& (error
= git_midx_foreach_entry(backend
->midx
, cb
, data
)) != 0)
667 git_vector_foreach(&backend
->packs
, i
, p
) {
668 if ((error
= git_pack_foreach_entry(p
, cb
, data
)) != 0)
675 static int pack_backend__writepack_append(struct git_odb_writepack
*_writepack
, const void *data
, size_t size
, git_indexer_progress
*stats
)
677 struct pack_writepack
*writepack
= (struct pack_writepack
*)_writepack
;
679 GIT_ASSERT_ARG(writepack
);
681 return git_indexer_append(writepack
->indexer
, data
, size
, stats
);
684 static int pack_backend__writepack_commit(struct git_odb_writepack
*_writepack
, git_indexer_progress
*stats
)
686 struct pack_writepack
*writepack
= (struct pack_writepack
*)_writepack
;
688 GIT_ASSERT_ARG(writepack
);
690 return git_indexer_commit(writepack
->indexer
, stats
);
693 static void pack_backend__writepack_free(struct git_odb_writepack
*_writepack
)
695 struct pack_writepack
*writepack
;
700 writepack
= (struct pack_writepack
*)_writepack
;
702 git_indexer_free(writepack
->indexer
);
703 git__free(writepack
);
706 static int pack_backend__writepack(struct git_odb_writepack
**out
,
707 git_odb_backend
*_backend
,
709 git_indexer_progress_cb progress_cb
,
710 void *progress_payload
)
712 git_indexer_options opts
= GIT_INDEXER_OPTIONS_INIT
;
713 struct pack_backend
*backend
;
714 struct pack_writepack
*writepack
;
717 GIT_ASSERT_ARG(_backend
);
721 opts
.progress_cb
= progress_cb
;
722 opts
.progress_cb_payload
= progress_payload
;
724 backend
= (struct pack_backend
*)_backend
;
726 writepack
= git__calloc(1, sizeof(struct pack_writepack
));
727 GIT_ERROR_CHECK_ALLOC(writepack
);
729 if (git_indexer_new(&writepack
->indexer
,
730 backend
->pack_folder
, 0, odb
, &opts
) < 0) {
731 git__free(writepack
);
735 writepack
->parent
.backend
= _backend
;
736 writepack
->parent
.append
= pack_backend__writepack_append
;
737 writepack
->parent
.commit
= pack_backend__writepack_commit
;
738 writepack
->parent
.free
= pack_backend__writepack_free
;
740 *out
= (git_odb_writepack
*)writepack
;
745 static int get_idx_path(
747 struct pack_backend
*backend
,
748 struct git_pack_file
*p
)
753 error
= git_fs_path_prettify(idx_path
, p
->pack_name
, backend
->pack_folder
);
756 path_len
= git_str_len(idx_path
);
757 if (path_len
<= strlen(".pack") || git__suffixcmp(git_str_cstr(idx_path
), ".pack") != 0)
758 return git_odb__error_notfound("packfile does not end in .pack", NULL
, 0);
759 path_len
-= strlen(".pack");
760 error
= git_str_splice(idx_path
, path_len
, strlen(".pack"), ".idx", strlen(".idx"));
767 static int pack_backend__writemidx(git_odb_backend
*_backend
)
769 struct pack_backend
*backend
;
770 git_midx_writer
*w
= NULL
;
771 struct git_pack_file
*p
;
775 GIT_ASSERT_ARG(_backend
);
777 backend
= (struct pack_backend
*)_backend
;
779 error
= git_midx_writer_new(&w
, backend
->pack_folder
);
783 git_vector_foreach(&backend
->midx_packs
, i
, p
) {
784 git_str idx_path
= GIT_STR_INIT
;
785 error
= get_idx_path(&idx_path
, backend
, p
);
788 error
= git_midx_writer_add(w
, git_str_cstr(&idx_path
));
789 git_str_dispose(&idx_path
);
793 git_vector_foreach(&backend
->packs
, i
, p
) {
794 git_str idx_path
= GIT_STR_INIT
;
795 error
= get_idx_path(&idx_path
, backend
, p
);
798 error
= git_midx_writer_add(w
, git_str_cstr(&idx_path
));
799 git_str_dispose(&idx_path
);
805 * Invalidate the previous midx before writing the new one.
807 error
= remove_multi_pack_index(backend
);
810 error
= git_midx_writer_commit(w
);
813 error
= refresh_multi_pack_index(backend
);
816 git_midx_writer_free(w
);
820 static void pack_backend__free(git_odb_backend
*_backend
)
822 struct pack_backend
*backend
;
823 struct git_pack_file
*p
;
829 backend
= (struct pack_backend
*)_backend
;
831 git_vector_foreach(&backend
->midx_packs
, i
, p
)
832 git_mwindow_put_pack(p
);
833 git_vector_foreach(&backend
->packs
, i
, p
)
834 git_mwindow_put_pack(p
);
836 git_midx_free(backend
->midx
);
837 git_vector_free(&backend
->midx_packs
);
838 git_vector_free(&backend
->packs
);
839 git__free(backend
->pack_folder
);
843 static int pack_backend__alloc(struct pack_backend
**out
, size_t initial_size
)
845 struct pack_backend
*backend
= git__calloc(1, sizeof(struct pack_backend
));
846 GIT_ERROR_CHECK_ALLOC(backend
);
848 if (git_vector_init(&backend
->midx_packs
, 0, NULL
) < 0) {
852 if (git_vector_init(&backend
->packs
, initial_size
, packfile_sort__cb
) < 0) {
853 git_vector_free(&backend
->midx_packs
);
858 backend
->parent
.version
= GIT_ODB_BACKEND_VERSION
;
860 backend
->parent
.read
= &pack_backend__read
;
861 backend
->parent
.read_prefix
= &pack_backend__read_prefix
;
862 backend
->parent
.read_header
= &pack_backend__read_header
;
863 backend
->parent
.exists
= &pack_backend__exists
;
864 backend
->parent
.exists_prefix
= &pack_backend__exists_prefix
;
865 backend
->parent
.refresh
= &pack_backend__refresh
;
866 backend
->parent
.foreach
= &pack_backend__foreach
;
867 backend
->parent
.writepack
= &pack_backend__writepack
;
868 backend
->parent
.writemidx
= &pack_backend__writemidx
;
869 backend
->parent
.freshen
= &pack_backend__freshen
;
870 backend
->parent
.free
= &pack_backend__free
;
876 int git_odb_backend_one_pack(git_odb_backend
**backend_out
, const char *idx
)
878 struct pack_backend
*backend
= NULL
;
879 struct git_pack_file
*packfile
= NULL
;
881 if (pack_backend__alloc(&backend
, 1) < 0)
884 if (git_mwindow_get_pack(&packfile
, idx
) < 0 ||
885 git_vector_insert(&backend
->packs
, packfile
) < 0)
887 pack_backend__free((git_odb_backend
*)backend
);
891 *backend_out
= (git_odb_backend
*)backend
;
895 int git_odb_backend_pack(git_odb_backend
**backend_out
, const char *objects_dir
)
898 struct pack_backend
*backend
= NULL
;
899 git_str path
= GIT_STR_INIT
;
901 if (pack_backend__alloc(&backend
, 8) < 0)
904 if (!(error
= git_str_joinpath(&path
, objects_dir
, "pack")) &&
905 git_fs_path_isdir(git_str_cstr(&path
)))
907 backend
->pack_folder
= git_str_detach(&path
);
908 error
= pack_backend__refresh((git_odb_backend
*)backend
);
912 pack_backend__free((git_odb_backend
*)backend
);
916 *backend_out
= (git_odb_backend
*)backend
;
918 git_str_dispose(&path
);