mirror of
https://github.com/git/git.git
synced 2026-10-09 00:49:37 +02:00
When writing a cruft pack with an expiration, pack-objects first collects the recent objects and then walks from them to rescue whatever they reach, expired or not. A pack the caller did not list is marked kept while collecting, so that its objects are not copied into the cruft pack, and unmarked before the walk, so that the walk can go through it. The walk does not see the unmarking. Whether an object sits in a kept pack is answered from a cache that is built on first use and only dropped when asked about a different kind of kept pack. Collecting builds it while the unlisted pack is still marked, the walk asks the same kind of question, and so the unlisted pack stays in it: the walk stops there, and whatever lies beyond it in an expired pack is left out of the cruft pack, to go when that pack is deleted. This went unnoticed because of "--honor-pack-keep". repack passes it, and when there is a ".keep" file it makes the collecting side ask about on-disk and in-core kept packs together while the walk asks about in-core ones alone; the cache is rebuilt each time the question changes, and by accident the walk sees the current marks. Take the ".keep" file away and the objects are lost today. A later commit stops repack from passing "--honor-pack-keep" at all, so fix this first. Drop the cache after re-marking. The loop over the object sources that does so lives in packfile.c, as repo_invalidate_kept_pack_caches(), next to has_object_kept_pack() which reads the cache. Like it, the loop assumes every source is a files backend; keeping that assumption in packfile.c rather than adding it to pack-objects means the two can move together once packfile management is pushed down into that backend. The test builds an unreachable chain whose middle commit sits in a pack pack-objects is not told about and whose oldest objects have expired; without the fix the cruft pack holds only the recent tip. Signed-off-by: Qin ShiCheng <qeesung@live.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
89 lines
2.5 KiB
C
89 lines
2.5 KiB
C
#ifndef ODB_SOURCE_PACKED_H
|
|
#define ODB_SOURCE_PACKED_H
|
|
|
|
#include "odb/source.h"
|
|
#include "packfile-list.h"
|
|
#include "strmap.h"
|
|
|
|
/*
|
|
* A store that manages packfiles for a given object database.
|
|
*/
|
|
struct odb_source_packed {
|
|
struct odb_source base;
|
|
|
|
/*
|
|
* The list of packfiles in the order in which they have been most
|
|
* recently used.
|
|
*/
|
|
struct packfile_list packs;
|
|
|
|
/*
|
|
* Cache of packfiles which are marked as "kept", either because there
|
|
* is an on-disk ".keep" file or because they are marked as "kept" in
|
|
* memory.
|
|
*
|
|
* Should not be accessed directly, but via
|
|
* `packfile_store_get_kept_pack_cache()`. The list of packs gets
|
|
* invalidated when the stored flags and the flags passed to
|
|
* `packfile_store_get_kept_pack_cache()` mismatch, or explicitly via
|
|
* `repo_invalidate_kept_pack_caches()`.
|
|
*/
|
|
struct {
|
|
struct packed_git **packs;
|
|
unsigned flags;
|
|
} kept_cache;
|
|
|
|
/* The multi-pack index that belongs to this specific packfile store. */
|
|
struct multi_pack_index *midx;
|
|
|
|
/*
|
|
* A map of packfile names to packed_git structs for tracking which
|
|
* packs have been loaded already.
|
|
*/
|
|
struct strmap packs_by_path;
|
|
|
|
/*
|
|
* Whether packfiles have already been populated with this store's
|
|
* packs.
|
|
*/
|
|
bool initialized;
|
|
|
|
/*
|
|
* Usually, packfiles will be reordered to the front of the `packs`
|
|
* list whenever an object is looked up via them. This has the effect
|
|
* that packs that contain a lot of accessed objects will be located
|
|
* towards the front.
|
|
*
|
|
* This is usually desirable, but there are exceptions. One exception
|
|
* is when the looking up multiple objects in a loop for each packfile.
|
|
* In that case, we may easily end up with an infinite loop as the
|
|
* packfiles get reordered to the front repeatedly.
|
|
*
|
|
* Setting this field to `true` thus disables these reorderings.
|
|
*/
|
|
bool skip_mru_updates;
|
|
};
|
|
|
|
/*
|
|
* Allocate and initialize a new empty packfile store for the given object
|
|
* database.
|
|
*/
|
|
struct odb_source_packed *odb_source_packed_new(struct object_database *odb,
|
|
const char *path,
|
|
bool local);
|
|
|
|
/*
|
|
* Cast the given object database source to the packed backend. This will cause
|
|
* a BUG in case the source doesn't use this backend.
|
|
*/
|
|
static inline struct odb_source_packed *odb_source_packed_downcast(struct odb_source *source)
|
|
{
|
|
if (source->type != ODB_SOURCE_PACKED)
|
|
BUG("trying to downcast source of type '%s' to '%s'",
|
|
odb_source_type_to_name(source->type),
|
|
odb_source_type_to_name(ODB_SOURCE_PACKED));
|
|
return container_of(source, struct odb_source_packed, base);
|
|
}
|
|
|
|
#endif
|