Mercurial > nomad
changeset 780:d1c336241209
objstore: ignore all deleted dirent targets during lookup
Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author | Josef 'Jeff' Sipek <jeffpc@josefsipek.net> |
---|---|
date | Sun, 29 Mar 2020 17:37:14 -0400 |
parents | 4767ca9d2c3e |
children | ca83139c8103 |
files | src/objstore/obj_dir.c |
diffstat | 1 files changed, 93 insertions(+), 17 deletions(-) [+] |
line wrap: on
line diff
--- a/src/objstore/obj_dir.c Mon Mar 30 23:03:34 2020 -0400 +++ b/src/objstore/obj_dir.c Sun Mar 29 17:37:14 2020 -0400 @@ -150,6 +150,7 @@ struct ndirent_mem ent; struct ndirent_tgt tgt; struct buffer tgtbuf; + size_t i; int ret; ret = dir_lookup_entry(dirver, name, raw, true, &ent, NULL, NULL); @@ -159,9 +160,23 @@ buffer_init_static(&tgtbuf, &raw[ent.tgtoff], DIR_BLOCK_SIZE - ent.tgtoff, false); - ret = unpack_dirent_tgt(&tgtbuf, &tgt); - if (ret) - return ret; + /* + * There is exactly one non-deleted target, and zero or more deleted + * ones. Find the right one and return it. + */ + ASSERT(!ent.conflicts); + ASSERT(!ent.all_deleted); + + for (i = 0; i < ent.ntgts; i++) { + ret = unpack_dirent_tgt(&tgtbuf, &tgt); + if (ret) + return ret; + + if (!tgt.deleted) + break; + } + + VERIFY3U(i, <, ent.ntgts); if (tgt.type == NDIRENT_TYPE_GRAFT) noid_set(child, &tgt.graft, 0, 0); @@ -177,6 +192,31 @@ return 0; } +static int __dir_lookup_all_realloc(size_t ntgts, struct noid **oids, + uint8_t **types, bool first) +{ + void *tmp; + + if (first) { + *oids = NULL; + *types = NULL; + } + + tmp = mem_reallocarray(*oids, ntgts, sizeof(struct noid)); + if (!tmp) + return -ENOMEM; + + *oids = tmp; + + tmp = mem_reallocarray(*types, ntgts, sizeof(uint8_t)); + if (!tmp) + return -ENOMEM; + + *types = tmp; + + return 0; +} + ssize_t dir_lookup_all(struct objver *dirver, const char *name, struct noid **child, uint8_t **type) { @@ -185,44 +225,66 @@ struct buffer tgtbuf; struct noid *oids; uint8_t *types; - size_t i; + size_t ntgts; + size_t i, j; int ret; ret = dir_lookup_entry(dirver, name, raw, false, &ent, NULL, NULL); if (ret) return ret; - oids = malloc(sizeof(struct noid) * ent.ntgts); - types = malloc(sizeof(uint8_t) * ent.ntgts); + /* + * There is one or more non-deleted target and zero or more deleted + * ones. Find all the non-deleted ones and return them. + */ + ASSERT(!ent.all_deleted); - if (!oids || !types) { - ret = -ENOMEM; + /* start with 2 if there are conflicts; 1 is enough otherwise */ + ntgts = ent.conflicts ? 2 : 1; + + ret = __dir_lookup_all_realloc(ntgts, &oids, &types, true); + if (ret) goto err; - } buffer_init_static(&tgtbuf, &raw[ent.tgtoff], DIR_BLOCK_SIZE - ent.tgtoff, false); - for (i = 0; i < ent.ntgts; i++) { + for (i = 0, j = 0; i < ent.ntgts; i++) { struct ndirent_tgt tgt; ret = unpack_dirent_tgt(&tgtbuf, &tgt); if (ret) goto err; + if (tgt.deleted) + continue; /* deleted - skip */ + + /* grow the arrays if needed */ + if (j == ntgts) { + ntgts++; + + ret = __dir_lookup_all_realloc(ntgts, &oids, &types, + false); + if (ret) + goto err; + } + if (tgt.type == NDIRENT_TYPE_GRAFT) - noid_set(&oids[i], &tgt.graft, 0, 0); + noid_set(&oids[j], &tgt.graft, 0, 0); else - noid_set(&oids[i], &dirver->obj->clone->uuid, tgt.host, + noid_set(&oids[j], &dirver->obj->clone->uuid, tgt.host, tgt.uniq); - types[i] = tgt.type; + types[j] = tgt.type; + j++; } + ASSERT3U(j, ==, ntgts); + *child = oids; *type = types; - return ent.ntgts; + return ntgts; err: free(oids); @@ -289,14 +351,28 @@ if (!dirent.conflicts) { struct ndirent_tgt tgt; struct buffer tgtbuf; + size_t i; buffer_init_static(&tgtbuf, &raw[dirent.tgtoff], DIR_BLOCK_SIZE - dirent.tgtoff, false); - ret = unpack_dirent_tgt(&tgtbuf, &tgt); - if (ret) - goto err; + /* + * There is exactly one non-deleted target, and zero + * or more deleted ones. Find the right one and + * return it. + */ + + for (i = 0; i < dirent.ntgts; i++) { + ret = unpack_dirent_tgt(&tgtbuf, &tgt); + if (ret) + goto err; + + if (!tgt.deleted) + break; + } + + VERIFY3U(i, <, dirent.ntgts); child->type = tgt.type;