Commit cf0b1793 authored by Junio C Hamano's avatar Junio C Hamano

Merge branch 'sb/object-store'

Refactoring the internal global data structure to make it possible
to open multiple repositories, work with and then close them.

Rerolled by Duy on top of a separate preliminary clean-up topic.
The resulting structure of the topics looked very sensible.

* sb/object-store: (27 commits)
  sha1_file: allow sha1_loose_object_info to handle arbitrary repositories
  sha1_file: allow map_sha1_file to handle arbitrary repositories
  sha1_file: allow map_sha1_file_1 to handle arbitrary repositories
  sha1_file: allow open_sha1_file to handle arbitrary repositories
  sha1_file: allow stat_sha1_file to handle arbitrary repositories
  sha1_file: allow sha1_file_name to handle arbitrary repositories
  sha1_file: add repository argument to sha1_loose_object_info
  sha1_file: add repository argument to map_sha1_file
  sha1_file: add repository argument to map_sha1_file_1
  sha1_file: add repository argument to open_sha1_file
  sha1_file: add repository argument to stat_sha1_file
  sha1_file: add repository argument to sha1_file_name
  sha1_file: allow prepare_alt_odb to handle arbitrary repositories
  sha1_file: allow link_alt_odb_entries to handle arbitrary repositories
  sha1_file: add repository argument to prepare_alt_odb
  sha1_file: add repository argument to link_alt_odb_entries
  sha1_file: add repository argument to read_info_alternates
  sha1_file: add repository argument to link_alt_odb_entry
  sha1_file: add raw_object_store argument to alt_odb_usable
  pack: move approximate object count to object store
  ...
parents 5ff42d42 4a7c05f7
......@@ -1862,7 +1862,7 @@ static void am_run(struct am_state *state, int resume)
*/
if (!state->rebasing) {
am_destroy(state);
close_all_packs();
close_all_packs(the_repository->objects);
run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
}
}
......
......@@ -27,6 +27,7 @@
#include "connected.h"
#include "packfile.h"
#include "list-objects-filter-options.h"
#include "object-store.h"
/*
* Overall FIXMEs:
......@@ -1217,7 +1218,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
transport_disconnect(transport);
if (option_dissociate) {
close_all_packs();
close_all_packs(the_repository->objects);
dissociate_from_references();
}
......
......@@ -7,10 +7,12 @@
#include "cache.h"
#include "config.h"
#include "dir.h"
#include "repository.h"
#include "builtin.h"
#include "parse-options.h"
#include "quote.h"
#include "packfile.h"
#include "object-store.h"
static unsigned long garbage;
static off_t size_garbage;
......@@ -120,9 +122,9 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)
struct strbuf loose_buf = STRBUF_INIT;
struct strbuf pack_buf = STRBUF_INIT;
struct strbuf garbage_buf = STRBUF_INIT;
if (!packed_git)
if (!get_packed_git(the_repository))
prepare_packed_git();
for (p = packed_git; p; p = p->next) {
for (p = get_packed_git(the_repository); p; p = p->next) {
if (!p->pack_local)
continue;
if (open_pack_index(p))
......
......@@ -1516,7 +1516,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
string_list_clear(&list, 0);
close_all_packs();
close_all_packs(the_repository->objects);
argv_array_pushl(&argv_gc_auto, "gc", "--auto", NULL);
if (verbosity < 0)
......
#include "builtin.h"
#include "cache.h"
#include "repository.h"
#include "config.h"
#include "commit.h"
#include "tree.h"
......@@ -16,6 +17,7 @@
#include "streaming.h"
#include "decorate.h"
#include "packfile.h"
#include "object-store.h"
#define REACHABLE 0x0001
#define SEEN 0x0002
......@@ -719,9 +721,12 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
for_each_loose_object(mark_loose_for_connectivity, NULL, 0);
for_each_packed_object(mark_packed_for_connectivity, NULL, 0);
} else {
struct alternate_object_database *alt_odb_list;
fsck_object_dir(get_object_directory());
prepare_alt_odb();
prepare_alt_odb(the_repository);
alt_odb_list = the_repository->objects->alt_odb_list;
for (alt = alt_odb_list; alt; alt = alt->next)
fsck_object_dir(alt->path);
......@@ -733,7 +738,8 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
prepare_packed_git();
if (show_progress) {
for (p = packed_git; p; p = p->next) {
for (p = get_packed_git(the_repository); p;
p = p->next) {
if (open_pack_index(p))
continue;
total += p->num_objects;
......@@ -741,7 +747,8 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
progress = start_progress(_("Checking objects"), total);
}
for (p = packed_git; p; p = p->next) {
for (p = get_packed_git(the_repository); p;
p = p->next) {
/* verify gives error messages itself */
if (verify_pack(p, fsck_obj_buffer,
progress, count))
......
......@@ -11,6 +11,7 @@
*/
#include "builtin.h"
#include "repository.h"
#include "config.h"
#include "tempfile.h"
#include "lockfile.h"
......@@ -20,6 +21,7 @@
#include "argv-array.h"
#include "commit.h"
#include "packfile.h"
#include "object-store.h"
#define FAILED_RUN "failed to run %s"
......@@ -173,7 +175,7 @@ static int too_many_packs(void)
return 0;
prepare_packed_git();
for (cnt = 0, p = packed_git; p; p = p->next) {
for (cnt = 0, p = get_packed_git(the_repository); p; p = p->next) {
if (!p->pack_local)
continue;
if (p->pack_keep)
......
......@@ -22,6 +22,7 @@
#include "pathspec.h"
#include "submodule.h"
#include "submodule-config.h"
#include "object-store.h"
static char const * const grep_usage[] = {
N_("git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]"),
......@@ -439,7 +440,7 @@ static int grep_submodule(struct grep_opt *opt, struct repository *superproject,
* object.
*/
grep_read_lock();
add_to_alternates_memory(submodule.objectdir);
add_to_alternates_memory(submodule.objects->objectdir);
grep_read_unlock();
if (oid) {
......
......@@ -13,6 +13,7 @@
#include "streaming.h"
#include "thread-utils.h"
#include "packfile.h"
#include "object-store.h"
static const char index_pack_usage[] =
"git index-pack [-v] [-o <index-file>] [--keep | --keep=<msg>] [--verify] [--strict] (<pack-file> | --stdin [--fix-thin] [<pack-file>])";
......
......@@ -412,7 +412,7 @@ static void finish(struct commit *head_commit,
* We ignore errors in 'gc --auto', since the
* user should see them.
*/
close_all_packs();
close_all_packs(the_repository->objects);
run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
}
}
......
#include "builtin.h"
#include "cache.h"
#include "repository.h"
#include "config.h"
#include "attr.h"
#include "object.h"
......@@ -28,6 +29,7 @@
#include "argv-array.h"
#include "list.h"
#include "packfile.h"
#include "object-store.h"
static const char *pack_usage[] = {
N_("git pack-objects --stdout [<options>...] [< <ref-list> | < <object-list>]"),
......@@ -1023,8 +1025,7 @@ static int want_object_in_pack(const struct object_id *oid,
if (want != -1)
return want;
}
list_for_each(pos, &packed_git_mru) {
list_for_each(pos, get_packed_git_mru(the_repository)) {
struct packed_git *p = list_entry(pos, struct packed_git, mru);
off_t offset;
......@@ -1042,7 +1043,8 @@ static int want_object_in_pack(const struct object_id *oid,
}
want = want_found_object(exclude, p);
if (!exclude && want > 0)
list_move(&p->mru, &packed_git_mru);
list_move(&p->mru,
get_packed_git_mru(the_repository));
if (want != -1)
return want;
}
......@@ -2669,7 +2671,7 @@ static void add_objects_in_unpacked_packs(struct rev_info *revs)
memset(&in_pack, 0, sizeof(in_pack));
for (p = packed_git; p; p = p->next) {
for (p = get_packed_git(the_repository); p; p = p->next) {
struct object_id oid;
struct object *o;
......@@ -2732,7 +2734,8 @@ static int has_sha1_pack_kept_or_nonlocal(const struct object_id *oid)
static struct packed_git *last_found = (void *)1;
struct packed_git *p;
p = (last_found != (void *)1) ? last_found : packed_git;
p = (last_found != (void *)1) ? last_found :
get_packed_git(the_repository);
while (p) {
if ((!p->pack_local || p->pack_keep) &&
......@@ -2741,7 +2744,7 @@ static int has_sha1_pack_kept_or_nonlocal(const struct object_id *oid)
return 1;
}
if (p == last_found)
p = packed_git;
p = get_packed_git(the_repository);
else
p = p->next;
if (p == last_found)
......@@ -2777,7 +2780,7 @@ static void loosen_unused_packed_objects(struct rev_info *revs)
uint32_t i;
struct object_id oid;
for (p = packed_git; p; p = p->next) {
for (p = get_packed_git(the_repository); p; p = p->next) {
if (!p->pack_local || p->pack_keep)
continue;
......@@ -3148,7 +3151,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
prepare_packed_git();
if (ignore_packed_keep) {
struct packed_git *p;
for (p = packed_git; p; p = p->next)
for (p = get_packed_git(the_repository); p; p = p->next)
if (p->pack_local && p->pack_keep)
break;
if (!p) /* no keep-able packs found */
......@@ -3161,7 +3164,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
* also covers non-local objects
*/
struct packed_git *p;
for (p = packed_git; p; p = p->next) {
for (p = get_packed_git(the_repository); p; p = p->next) {
if (!p->pack_local) {
have_non_local_packs = 1;
break;
......
......@@ -7,7 +7,9 @@
*/
#include "builtin.h"
#include "repository.h"
#include "packfile.h"
#include "object-store.h"
#define BLKSIZE 512
......@@ -571,7 +573,7 @@ static struct pack_list * add_pack(struct packed_git *p)
static struct pack_list * add_pack_file(const char *filename)
{
struct packed_git *p = packed_git;
struct packed_git *p = get_packed_git(the_repository);
if (strlen(filename) < 40)
die("Bad pack filename: %s", filename);
......@@ -586,7 +588,7 @@ static struct pack_list * add_pack_file(const char *filename)
static void load_all(void)
{
struct packed_git *p = packed_git;
struct packed_git *p = get_packed_git(the_repository);
while (p) {
add_pack(p);
......
......@@ -2027,7 +2027,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
proc.git_cmd = 1;
proc.argv = argv_gc_auto;
close_all_packs();
close_all_packs(the_repository->objects);
if (!start_command(&proc)) {
if (use_sideband)
copy_to_sideband(proc.err, -1, NULL);
......
......@@ -16,6 +16,7 @@
#include "revision.h"
#include "diffcore.h"
#include "diff.h"
#include "object-store.h"
#define OPT_QUIET (1 << 0)
#define OPT_CACHED (1 << 1)
......
......@@ -940,12 +940,6 @@ extern void check_repository_format(void);
#define DATA_CHANGED 0x0020
#define TYPE_CHANGED 0x0040
/*
* Put in `buf` the name of the file in the local object database that
* would be used to store a loose object with the specified sha1.
*/
extern void sha1_file_name(struct strbuf *buf, const unsigned char *sha1);
/*
* Return an abbreviated sha1 unique within this repository's object database.
* The result will be at least `len` characters long, and will be NUL
......@@ -1236,7 +1230,6 @@ extern int force_object_loose(const struct object_id *oid, time_t mtime);
extern int git_open_cloexec(const char *name, int flags);
#define git_open(name) git_open_cloexec(name, O_RDONLY)
extern void *map_sha1_file(const unsigned char *sha1, unsigned long *size);
extern int unpack_sha1_header(git_zstream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz);
extern int parse_sha1_header(const char *hdr, unsigned long *sizep);
......@@ -1564,57 +1557,6 @@ extern int has_dirs_only_path(const char *name, int len, int prefix_len);
extern void schedule_dir_for_removal(const char *name, int len);
extern void remove_scheduled_dirs(void);
extern struct alternate_object_database {
struct alternate_object_database *next;
/* see alt_scratch_buf() */
struct strbuf scratch;
size_t base_len;
/*
* Used to store the results of readdir(3) calls when searching
* for unique abbreviated hashes. This cache is never
* invalidated, thus it's racy and not necessarily accurate.
* That's fine for its purpose; don't use it for tasks requiring
* greater accuracy!
*/
char loose_objects_subdir_seen[256];
struct oid_array loose_objects_cache;
char path[FLEX_ARRAY];
} *alt_odb_list;
extern void prepare_alt_odb(void);
extern char *compute_alternate_path(const char *path, struct strbuf *err);
typedef int alt_odb_fn(struct alternate_object_database *, void *);
extern int foreach_alt_odb(alt_odb_fn, void*);
/*
* Allocate a "struct alternate_object_database" but do _not_ actually
* add it to the list of alternates.
*/
struct alternate_object_database *alloc_alt_odb(const char *dir);
/*
* Add the directory to the on-disk alternates file; the new entry will also
* take effect in the current process.
*/
extern void add_to_alternates_file(const char *dir);
/*
* Add the directory to the in-memory list of alternates (along with any
* recursive alternates it points to), but do not modify the on-disk alternates
* file.
*/
extern void add_to_alternates_memory(const char *dir);
/*
* Returns a scratch strbuf pre-filled with the alternate object directory,
* including a trailing slash, which can be used to access paths in the
* alternate. Always use this over direct access to alt->scratch, as it
* cleans up any previous use of the scratch buffer.
*/
extern struct strbuf *alt_scratch_buf(struct alternate_object_database *alt);
struct pack_window {
struct pack_window *next;
unsigned char *base;
......@@ -1624,35 +1566,6 @@ struct pack_window {
unsigned int inuse_cnt;
};
extern struct packed_git {
struct packed_git *next;
struct list_head mru;
struct pack_window *windows;
off_t pack_size;
const void *index_data;
size_t index_size;
uint32_t num_objects;
uint32_t num_bad_objects;
unsigned char *bad_object_sha1;
int index_version;
time_t mtime;
int pack_fd;
unsigned pack_local:1,
pack_keep:1,
freshened:1,
do_not_close:1,
pack_promisor:1;
unsigned char sha1[20];
struct revindex_entry *revindex;
/* something like ".git/objects/pack/xxxxx.pack" */
char pack_name[FLEX_ARRAY]; /* more */
} *packed_git;
/*
* A most-recently-used ordered version of the packed_git list.
*/
extern struct list_head packed_git_mru;
struct pack_entry {
off_t offset;
unsigned char sha1[20];
......
......@@ -14,6 +14,7 @@
#include "fmt-merge-msg.h"
#include "commit.h"
#include "argv-array.h"
#include "object-store.h"
int trust_executable_bit = 1;
int trust_ctime = 1;
......@@ -270,9 +271,9 @@ const char *get_git_work_tree(void)
char *get_object_directory(void)
{
if (!the_repository->objectdir)
if (!the_repository->objects->objectdir)
BUG("git environment hasn't been setup");
return the_repository->objectdir;
return the_repository->objects->objectdir;
}
int odb_mkstemp(struct strbuf *temp_filename, const char *pattern)
......
......@@ -154,6 +154,7 @@ Format of STDIN stream:
#include "builtin.h"
#include "cache.h"
#include "repository.h"
#include "config.h"
#include "lockfile.h"
#include "object.h"
......@@ -168,6 +169,7 @@ Format of STDIN stream:
#include "dir.h"
#include "run-command.h"
#include "packfile.h"
#include "object-store.h"
#define PACK_ID_BITS 16
#define MAX_PACK_ID ((1<<PACK_ID_BITS)-1)
......@@ -1110,7 +1112,8 @@ static int store_object(
if (e->idx.offset) {
duplicate_count_by_type[type]++;
return 1;
} else if (find_sha1_pack(oid.hash, packed_git)) {
} else if (find_sha1_pack(oid.hash,
get_packed_git(the_repository))) {
e->type = type;
e->pack_id = MAX_PACK_ID;
e->idx.offset = 1; /* just not zero! */
......@@ -1307,7 +1310,8 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)
duplicate_count_by_type[OBJ_BLOB]++;
truncate_pack(&checkpoint);
} else if (find_sha1_pack(oid.hash, packed_git)) {
} else if (find_sha1_pack(oid.hash,
get_packed_git(the_repository))) {
e->type = OBJ_BLOB;
e->pack_id = MAX_PACK_ID;
e->idx.offset = 1; /* just not zero! */
......
#include "cache.h"
#include "config.h"
#include "repository.h"
#include "refs.h"
#include "pkt-line.h"
#include "object.h"
......@@ -10,6 +11,7 @@
#include "url.h"
#include "argv-array.h"
#include "packfile.h"
#include "object-store.h"
static const char content_type[] = "Content-Type";
static const char content_length[] = "Content-Length";
......@@ -518,13 +520,13 @@ static void get_info_packs(struct strbuf *hdr, char *arg)
select_getanyfile(hdr);
prepare_packed_git();
for (p = packed_git; p; p = p->next) {
for (p = get_packed_git(the_repository); p; p = p->next) {
if (p->pack_local)
cnt++;
}
strbuf_grow(&buf, cnt * 53 + 2);
for (p = packed_git; p; p = p->next) {
for (p = get_packed_git(the_repository); p; p = p->next) {
if (p->pack_local)
strbuf_addf(&buf, "P %s\n", p->pack_name + objdirlen + 6);
}
......
......@@ -12,6 +12,7 @@
#include "sigchain.h"
#include "argv-array.h"
#include "packfile.h"
#include "object-store.h"
#ifdef EXPAT_NEEDS_XMLPARSE_H
#include <xmlparse.h>
......
#include "cache.h"
#include "repository.h"
#include "commit.h"
#include "walker.h"
#include "http.h"
#include "list.h"
#include "transport.h"
#include "packfile.h"
#include "object-store.h"
struct alt_base {
char *base;
......@@ -545,7 +547,7 @@ static int fetch_object(struct walker *walker, unsigned char *sha1)
ret = error("File %s has bad hash", hex);
} else if (req->rename < 0) {
struct strbuf buf = STRBUF_INIT;
sha1_file_name(&buf, req->sha1);
sha1_file_name(the_repository, &buf, req->sha1);
ret = error("unable to write sha1 filename %s", buf.buf);
strbuf_release(&buf);
}
......
......@@ -14,6 +14,7 @@
#include "packfile.h"
#include "protocol.h"
#include "string-list.h"
#include "object-store.h"
static struct trace_key trace_curl = TRACE_KEY_INIT(CURL);
static int trace_curl_data = 1;
......@@ -2248,7 +2249,7 @@ struct http_object_request *new_http_object_request(const char *base_url,
hashcpy(freq->sha1, sha1);
freq->localfile = -1;
sha1_file_name(&filename, sha1);
sha1_file_name(the_repository, &filename, sha1);
snprintf(freq->tmpfile, sizeof(freq->tmpfile),
"%s.temp", filename.buf);
......@@ -2397,8 +2398,7 @@ int finish_http_object_request(struct http_object_request *freq)
unlink_or_warn(freq->tmpfile);
return -1;
}
sha1_file_name(&filename, freq->sha1);
sha1_file_name(the_repository, &filename, freq->sha1);
freq->rename = finalize_object_file(freq->tmpfile, filename.buf);
strbuf_release(&filename);
......
#ifndef OBJECT_STORE_H
#define OBJECT_STORE_H
struct alternate_object_database {
struct alternate_object_database *next;
/* see alt_scratch_buf() */
struct strbuf scratch;
size_t base_len;
/*
* Used to store the results of readdir(3) calls when searching
* for unique abbreviated hashes. This cache is never
* invalidated, thus it's racy and not necessarily accurate.
* That's fine for its purpose; don't use it for tasks requiring
* greater accuracy!
*/
char loose_objects_subdir_seen[256];
struct oid_array loose_objects_cache;
/*
* Path to the alternative object store. If this is a relative path,
* it is relative to the current working directory.
*/
char path[FLEX_ARRAY];
};
void prepare_alt_odb(struct repository *r);
char *compute_alternate_path(const char *path, struct strbuf *err);
typedef int alt_odb_fn(struct alternate_object_database *, void *);
int foreach_alt_odb(alt_odb_fn, void*);
/*
* Allocate a "struct alternate_object_database" but do _not_ actually
* add it to the list of alternates.
*/
struct alternate_object_database *alloc_alt_odb(const char *dir);
/*
* Add the directory to the on-disk alternates file; the new entry will also
* take effect in the current process.
*/
void add_to_alternates_file(const char *dir);
/*
* Add the directory to the in-memory list of alternates (along with any
* recursive alternates it points to), but do not modify the on-disk alternates
* file.
*/
void add_to_alternates_memory(const char *dir);
/*
* Returns a scratch strbuf pre-filled with the alternate object directory,
* including a trailing slash, which can be used to access paths in the
* alternate. Always use this over direct access to alt->scratch, as it
* cleans up any previous use of the scratch buffer.
*/
struct strbuf *alt_scratch_buf(struct alternate_object_database *alt);
struct packed_git {
struct packed_git *next;
struct list_head mru;
struct pack_window *windows;
off_t pack_size;
const void *index_data;
size_t index_size;
uint32_t num_objects;
uint32_t num_bad_objects;
unsigned char *bad_object_sha1;
int index_version;
time_t mtime;
int pack_fd;
unsigned pack_local:1,
pack_keep:1,
freshened:1,
do_not_close:1,
pack_promisor:1;
unsigned char sha1[20];
struct revindex_entry *revindex;
/* something like ".git/objects/pack/xxxxx.pack" */
char pack_name[FLEX_ARRAY]; /* more */
};
struct raw_object_store {
/*
* Path to the repository's object store.
* Cannot be NULL after initialization.
*/
char *objectdir;
/* Path to extra alternate object database if not NULL */
char *alternate_db;
struct alternate_object_database *alt_odb_list;
struct alternate_object_database **alt_odb_tail;
/*
* private data
*
* should only be accessed directly by packfile.c
*/
struct packed_git *packed_git;
/* A most-recently-used ordered version of the packed_git list. */
struct list_head packed_git_mru;
/*
* A fast, rough count of the number of objects in the repository.
* These two fields are not meant for direct access. Use
* approximate_object_count() instead.
*/
unsigned long approximate_object_count;
unsigned approximate_object_count_valid : 1;
/*
* Whether packed_git has already been populated with this repository's
* packs.
*/
unsigned packed_git_initialized : 1;
};
struct raw_object_store *raw_object_store_new(void);
void raw_object_store_clear(struct raw_object_store *o);
/*
* Put in `buf` the name of the file in the local object database that
* would be used to store a loose object with the specified sha1.
*/
void sha1_file_name(struct repository *r, struct strbuf *buf, const unsigned char *sha1);
void *map_sha1_file(struct repository *r, const unsigned char *sha1, unsigned long *size);
#endif /* OBJECT_STORE_H */
......@@ -4,6 +4,8 @@
#include "tree.h"
#include "commit.h"
#include "tag.h"
#include "object-store.h"
#include "packfile.h"
static struct object **obj_hash;
static int nr_objs, obj_hash_size;
......@@ -445,3 +447,43 @@ void clear_commit_marks_all(unsigned int flags)
obj->flags &= ~flags;
}
}
struct raw_object_store *raw_object_store_new(void)
{
struct raw_object_store *o = xmalloc(sizeof(*o));
memset(o, 0, sizeof(*o));
INIT_LIST_HEAD(&o->packed_git_mru);
return o;
}
static void free_alt_odb(struct alternate_object_database *alt)
{
strbuf_release(&alt->scratch);
oid_array_clear(&alt->loose_objects_cache);
free(alt);
}
static void free_alt_odbs(struct raw_object_store *o)
{
while (o->alt_odb_list) {
struct alternate_object_database *next;
next = o->alt_odb_list->next;
free_alt_odb(o->alt_odb_list);
o->alt_odb_list = next;
}
}
void raw_object_store_clear(struct raw_object_store *o)
{
FREE_AND_NULL(o->objectdir);
FREE_AND_NULL(o->alternate_db);
free_alt_odbs(o);
o->alt_odb_tail = NULL;
INIT_LIST_HEAD(&o->packed_git_mru);
close_all_packs(o);
o->packed_git = NULL;
}