Skip to content

Commit 4e8b95e

Browse files
committed
Merge branch 'ps/odb-files-alternates-cleanups' into jch
The object database "files" backend has been optimized to check packfiles across all alternate object directories before falling back to checking loose objects, significantly reducing the number of 'stat(3p)' system calls. Additional refactoring drops the generic 'local' flag from the object database source interface in favor of backend-specific fields, and simplifies the retry loop for missing objects. * ps/odb-files-alternates-cleanups: odb/source: drop `local` flag odb: don't try re-fetching corrupt objects odb: remove read loop for found objects odb/source-files: make the second read an implementation detail odb/source-files: fix performance when streaming objects with alternates odb/source-files: fix performance when reading objects with alternates
2 parents 83c03e1 + f211a3f commit 4e8b95e

13 files changed

Lines changed: 109 additions & 120 deletions

‎midx.c‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,7 @@ int prepare_midx_pack(struct multi_pack_index *m,
470470
strbuf_addf(&pack_name, "%s/pack/%s", packed->base.path,
471471
m->pack_names[pack_int_id]);
472472
p = packfile_store_load_pack(packed,
473-
pack_name.buf, packed->base.local);
473+
pack_name.buf, packed->local);
474474
strbuf_release(&pack_name);
475475

476476
if (!p) {

‎odb.c‎

Lines changed: 18 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -265,8 +265,6 @@ static enum odb_read_status do_oid_object_info_extended(struct object_database *
265265
struct strbuf corrupt_err = STRBUF_INIT;
266266
const struct object_id *real = oid;
267267
enum odb_read_status ret;
268-
int already_retried = 0;
269-
bool corrupt = false;
270268

271269
if (flags & OBJECT_INFO_LOOKUP_REPLACE)
272270
real = lookup_replace_object(odb->repo, oid);
@@ -277,54 +275,29 @@ static enum odb_read_status do_oid_object_info_extended(struct object_database *
277275
if (!odb_source_read_object_info(odb->inmemory_objects, oid, oi, flags, NULL))
278276
return 0;
279277

280-
while (1) {
278+
ret = odb_source_read_object_info(odb->source, real, oi, flags,
279+
&corrupt_err);
280+
if (ret == ODB_READ_NOT_FOUND &&
281+
odb->repo->fetch_if_missing &&
282+
!(flags & OBJECT_INFO_SKIP_FETCH_OBJECT) &&
283+
repo_has_promisor_remote(odb->repo)) {
284+
/* Try to fetch the missing object from a promisor remote. */
285+
promisor_remote_get_direct(odb->repo, real, 1);
281286
ret = odb_source_read_object_info(odb->source, real, oi, flags,
282-
corrupt_err.len ? NULL : &corrupt_err);
283-
if (!ret)
284-
goto out;
285-
if (ret != ODB_READ_NOT_FOUND)
286-
corrupt = true;
287-
288-
/*
289-
* When the object hasn't been found we try a second read and
290-
* tell the sources so. This may cause them to invalidate
291-
* caches or reload on-disk state.
292-
*/
293-
if (!(flags & OBJECT_INFO_QUICK)) {
294-
ret = odb_source_read_object_info(odb->source, real, oi,
295-
flags | OBJECT_INFO_SECOND_READ,
296-
corrupt_err.len ? NULL : &corrupt_err);
297-
if (!ret)
298-
goto out;
299-
if (ret != ODB_READ_NOT_FOUND)
300-
corrupt = true;
301-
}
302-
303-
/* Check if it is a missing object */
304-
if (odb->repo->fetch_if_missing && repo_has_promisor_remote(odb->repo) &&
305-
!already_retried &&
306-
!(flags & OBJECT_INFO_SKIP_FETCH_OBJECT)) {
307-
promisor_remote_get_direct(odb->repo, real, 1);
308-
already_retried = 1;
309-
continue;
310-
}
287+
&corrupt_err);
288+
}
311289

312-
if (flags & OBJECT_INFO_DIE_IF_CORRUPT) {
313-
if ((flags & OBJECT_INFO_LOOKUP_REPLACE) && !oideq(real, oid))
314-
die(_("replacement %s not found for %s"),
315-
oid_to_hex(real), oid_to_hex(oid));
316-
if (corrupt) {
317-
if (corrupt_err.len)
318-
die("%s", corrupt_err.buf);
319-
die(_("object %s is corrupt"), oid_to_hex(real));
320-
}
290+
if (ret < 0 && (flags & OBJECT_INFO_DIE_IF_CORRUPT)) {
291+
if ((flags & OBJECT_INFO_LOOKUP_REPLACE) && !oideq(real, oid))
292+
die(_("replacement %s not found for %s"),
293+
oid_to_hex(real), oid_to_hex(oid));
294+
if (ret != ODB_READ_NOT_FOUND) {
295+
if (corrupt_err.len)
296+
die("%s", corrupt_err.buf);
297+
die(_("object %s is corrupt"), oid_to_hex(real));
321298
}
322-
323-
ret = corrupt ? ODB_READ_ERROR : ODB_READ_NOT_FOUND;
324-
goto out;
325299
}
326300

327-
out:
328301
strbuf_release(&corrupt_err);
329302
return ret;
330303
}

‎odb.h‎

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -383,18 +383,6 @@ enum object_info_flags {
383383
/* Die if object corruption (not just an object being missing) was detected. */
384384
OBJECT_INFO_DIE_IF_CORRUPT = (1 << 3),
385385

386-
/*
387-
* We have already tried reading the object, but it couldn't be found
388-
* via any of the attached sources, and are now doing a second read.
389-
* This second read asks the individual sources to also evaluate
390-
* whether any on-disk state may have changed that may have caused the
391-
* object to appear.
392-
*
393-
* This flag is for internal use, only. The second read only occurs
394-
* when `OBJECT_INFO_QUICK` was not passed.
395-
*/
396-
OBJECT_INFO_SECOND_READ = (1 << 4),
397-
398386
/*
399387
* This is meant for bulk prefetching of missing blobs in a partial
400388
* clone. Implies OBJECT_INFO_SKIP_FETCH_OBJECT and OBJECT_INFO_QUICK.

‎odb/source-files.c‎

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ struct odb_files_dir *odb_files_dir_new(struct object_database *odb,
3333
CALLOC_ARRAY(dir, 1);
3434
dir->abspath = absolute_pathdup(path);
3535
dir->local = local;
36-
dir->loose = odb_source_loose_new(odb, path, local);
36+
dir->loose = odb_source_loose_new(odb, path);
3737
dir->packed = odb_source_packed_new(odb, path, local);
3838

3939
return dir;
@@ -426,22 +426,31 @@ static enum odb_read_status odb_source_files_read_object_info(struct odb_source
426426
{
427427
struct odb_source_files *files = odb_source_files_downcast(source);
428428
enum odb_read_status status = ODB_READ_NOT_FOUND;
429+
enum odb_read_status ret;
430+
bool retry = false;
429431

432+
retry:
430433
/*
431434
* Reading an object may fail even though the object exists, for
432435
* example because it is corrupt. Report this failure to the caller in
433436
* case none of the directories was able to read the object, and
434437
* prefer the first such error in case multiple reads have failed.
435438
*/
436439
for (struct odb_files_dir *dir = files->dirs; dir; dir = dir->next) {
437-
enum odb_read_status ret;
440+
if (retry)
441+
odb_source_prepare(&dir->packed->base, ODB_PREPARE_FLUSH_CACHES);
438442

439443
ret = odb_source_read_object_info(&dir->packed->base, oid, oi, flags,
440444
status == ODB_READ_NOT_FOUND ? errmsg : NULL);
441445
if (!ret)
442446
return 0;
443447
if (ret != ODB_READ_NOT_FOUND && status == ODB_READ_NOT_FOUND)
444448
status = ret;
449+
}
450+
451+
for (struct odb_files_dir *dir = files->dirs; dir; dir = dir->next) {
452+
if (retry)
453+
break;
445454

446455
ret = odb_source_read_object_info(&dir->loose->base, oid, oi, flags,
447456
status == ODB_READ_NOT_FOUND ? errmsg : NULL);
@@ -451,6 +460,11 @@ static enum odb_read_status odb_source_files_read_object_info(struct odb_source
451460
status = ret;
452461
}
453462

463+
if (!retry && !(flags & OBJECT_INFO_QUICK)) {
464+
retry = true;
465+
goto retry;
466+
}
467+
454468
return status;
455469
}
456470

@@ -461,8 +475,10 @@ static int odb_source_files_read_object_stream(struct odb_stream **out,
461475
struct odb_source_files *files = odb_source_files_downcast(source);
462476

463477
for (struct odb_files_dir *dir = files->dirs; dir; dir = dir->next)
464-
if (!odb_source_read_object_stream(out, &dir->packed->base, oid) ||
465-
!odb_source_read_object_stream(out, &dir->loose->base, oid))
478+
if (!odb_source_read_object_stream(out, &dir->packed->base, oid))
479+
return 0;
480+
for (struct odb_files_dir *dir = files->dirs; dir; dir = dir->next)
481+
if (!odb_source_read_object_stream(out, &dir->loose->base, oid))
466482
return 0;
467483

468484
return -1;
@@ -1249,7 +1265,7 @@ struct odb_source_files *odb_source_files_new(struct object_database *odb,
12491265
object_dir = xstrfmt("%s/objects", odb->repo->commondir);
12501266

12511267
CALLOC_ARRAY(files, 1);
1252-
odb_source_init(&files->base, odb, ODB_SOURCE_FILES, object_dir, true);
1268+
odb_source_init(&files->base, odb, ODB_SOURCE_FILES, object_dir);
12531269

12541270
hashmap_init(&files->dirs_by_path, odb_files_dir_by_path_cmp, files, 0);
12551271
files->dirs_paths_icase = -1;

‎odb/source-inmemory.c‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,12 @@ static int odb_source_inmemory_for_each_object(struct odb_source *source,
161161
};
162162
struct object_id null_oid = { 0 };
163163

164-
if ((opts->flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY) ||
165-
(opts->flags & ODB_FOR_EACH_OBJECT_LOCAL_ONLY && !source->local))
164+
/*
165+
* In-memory objects are neither promisor objects nor do they live in
166+
* the local object directory, so there is nothing to iterate over.
167+
*/
168+
if (opts->flags & (ODB_FOR_EACH_OBJECT_PROMISOR_ONLY |
169+
ODB_FOR_EACH_OBJECT_LOCAL_ONLY))
166170
return 0;
167171
if (!inmemory->objects)
168172
return 0;
@@ -369,7 +373,7 @@ struct odb_source_inmemory *odb_source_inmemory_new(struct object_database *odb)
369373
struct odb_source_inmemory *source;
370374

371375
CALLOC_ARRAY(source, 1);
372-
odb_source_init(&source->base, odb, ODB_SOURCE_INMEMORY, "source", false);
376+
odb_source_init(&source->base, odb, ODB_SOURCE_INMEMORY, "source");
373377

374378
source->base.free = odb_source_inmemory_free;
375379
source->base.close = odb_source_inmemory_close;

‎odb/source-loose.c‎

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -222,16 +222,6 @@ static enum odb_read_status odb_source_loose_read_object_info(struct odb_source
222222
{
223223
struct odb_source_loose *loose = odb_source_loose_downcast(source);
224224
static struct strbuf buf = STRBUF_INIT;
225-
226-
/*
227-
* The second read shouldn't cause new loose objects to show up, unless
228-
* there was a race condition with a secondary process. We don't care
229-
* about this case though, so we simply skip reading loose objects a
230-
* second time.
231-
*/
232-
if (flags & OBJECT_INFO_SECOND_READ)
233-
return ODB_READ_NOT_FOUND;
234-
235225
odb_loose_path(loose, &buf, oid);
236226
return read_object_info_from_path(loose, buf.buf, oid, oi, flags, errmsg);
237227
}
@@ -474,8 +464,6 @@ static int odb_source_loose_for_each_object(struct odb_source *source,
474464
/* There are no loose promisor objects, so we can return immediately. */
475465
if ((opts->flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY))
476466
return 0;
477-
if ((opts->flags & ODB_FOR_EACH_OBJECT_LOCAL_ONLY) && !source->local)
478-
return 0;
479467

480468
if (opts->prefix)
481469
return oidtree_each(odb_source_loose_cache(loose, opts->prefix),
@@ -1118,13 +1106,12 @@ static int odb_source_loose_fsck(struct odb_source *source,
11181106
}
11191107

11201108
struct odb_source_loose *odb_source_loose_new(struct object_database *odb,
1121-
const char *path,
1122-
bool local)
1109+
const char *path)
11231110
{
11241111
struct odb_source_loose *loose;
11251112

11261113
CALLOC_ARRAY(loose, 1);
1127-
odb_source_init(&loose->base, odb, ODB_SOURCE_LOOSE, path, local);
1114+
odb_source_init(&loose->base, odb, ODB_SOURCE_LOOSE, path);
11281115

11291116
loose->base.free = odb_source_loose_free;
11301117
loose->base.close = odb_source_loose_close;

‎odb/source-loose.h‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@ struct odb_source_loose {
3434
};
3535

3636
struct odb_source_loose *odb_source_loose_new(struct object_database *odb,
37-
const char *path,
38-
bool local);
37+
const char *path);
3938

4039
/*
4140
* Cast the given object database source to the loose backend. This will cause

‎odb/source-packed.c‎

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,11 @@ static int find_pack_entry(struct odb_source_packed *store,
5252
* packs, and repreparing the on-disk pack set does not reload the
5353
* borrowed, cached MIDX, so scan its packs directly for the survivor.
5454
*
55-
* Do this only on the second read, by which point repreparing packs has
56-
* already had a chance to find an object merely relocated into a new,
57-
* uncovered pack; only a genuine hidden duplicate reaches here.
55+
* Skip the scan for quick lookups, which are expected to accept false
56+
* negatives in favor of speed.
5857
*/
5958
if (midx_result == MIDX_FILL_OWNER_UNAVAILABLE &&
60-
(flags & OBJECT_INFO_SECOND_READ)) {
59+
!(flags & OBJECT_INFO_QUICK)) {
6160
struct multi_pack_index *m = store->midx;
6261
uint32_t i;
6362

@@ -86,14 +85,6 @@ static enum odb_read_status odb_source_packed_read_object_info(struct odb_source
8685
struct pack_entry e;
8786
int ret;
8887

89-
/*
90-
* In case the first read didn't surface the object, we have to reload
91-
* packfiles. This may cause us to discover new packfiles that have
92-
* been added since the last time we have prepared the packfile store.
93-
*/
94-
if (flags & OBJECT_INFO_SECOND_READ)
95-
odb_source_prepare(source, ODB_PREPARE_FLUSH_CACHES);
96-
9788
if (!find_pack_entry(packed, oid, &e, flags, &bad_pack)) {
9889
/*
9990
* The lookup may have failed because the object is known to be
@@ -749,7 +740,7 @@ static void prepare_pack(const char *full_name, size_t full_name_len,
749740
midx_contains_pack(data->source->midx, file_name))) {
750741
char *trimmed_path = xstrndup(full_name, full_name_len);
751742
packfile_store_load_pack(data->source,
752-
trimmed_path, data->source->base.local);
743+
trimmed_path, data->source->local);
753744
free(trimmed_path);
754745
}
755746

@@ -997,8 +988,9 @@ struct odb_source_packed *odb_source_packed_new(struct object_database *odb,
997988
struct odb_source_packed *packed;
998989

999990
CALLOC_ARRAY(packed, 1);
1000-
odb_source_init(&packed->base, odb, ODB_SOURCE_PACKED, path, local);
991+
odb_source_init(&packed->base, odb, ODB_SOURCE_PACKED, path);
1001992
strmap_init(&packed->packs_by_path);
993+
packed->local = local;
1002994

1003995
packed->base.free = odb_source_packed_free;
1004996
packed->base.close = odb_source_packed_close;

‎odb/source-packed.h‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ struct odb_source_packed {
4141
*/
4242
struct strmap packs_by_path;
4343

44+
/*
45+
* Whether this store is part of the local object directory of the
46+
* owning repository. Packfiles loaded via this store inherit this
47+
* flag via `pack_local`. Stores for alternates are not local.
48+
*/
49+
bool local;
50+
4451
/*
4552
* Whether packfiles have already been populated with this store's
4653
* packs.

‎odb/source.c‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,10 @@ struct odb_source *odb_source_new(struct object_database *odb,
3232
void odb_source_init(struct odb_source *source,
3333
struct object_database *odb,
3434
enum odb_source_type type,
35-
const char *path,
36-
bool local)
35+
const char *path)
3736
{
3837
source->odb = odb;
3938
source->type = type;
40-
source->local = local;
4139
source->path = xstrdup(path);
4240
}
4341

0 commit comments

Comments
 (0)