New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
zhash_insert()/zhashx_insert() return EEXIST #5217
Conversation
Did you see my comment in #5216 and look at the referenced czmq issue? I was hoping that would spark a discussion about the right way to fix this. These are simple containers that do not change much upstream and that we use quite a bit. Maybe it would be OK to change our copy to not assert on allocation error? |
Yeah, I saw it ... I guess I had started as an exercise to see how pervasive the issue was and just continued until I finished since it didn't take long, figuring "consistency" was better than nothing if we can't get to fixing it for real. Lets chat more in that issue. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In several cases simply changing the code to (void)zhashx_insert()
is appropriate since the key is known not to be in the hash.
src/broker/groups.c
Outdated
errno = ENOMEM; | ||
errno = EEXIST; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is inside a block that has already checked whether the group name is in the hash, so I think the insert return code can be ignored.
src/broker/runat.c
Outdated
if (zhashx_insert (r->entries, name, entry) < 0) { | ||
errno = EEXIST; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here, just ignore the error
src/broker/service.c
Outdated
if (zhash_insert (sh->services, name, svc) < 0) { | ||
errno = ENOMEM; | ||
errno = EEXIST; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here, ignore the error
src/common/librlist/rlist.c
Outdated
if (zhashx_insert (properties, name, ids) < 0) { | ||
idset_destroy (ids); | ||
errno = ENOMEM; | ||
errno = EEXIST; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just ignore return value and delete the comment above that explains the check.
src/common/librouter/disconnect.c
Outdated
if (zhashx_insert (dcon->hash, key, dmsg) < 0) { | ||
errno = EEXIST; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inside block that already checked. Just ignore return value.
if (zhashx_insert (queues, name, &duration) < 0) { // dups duration | ||
errno = ENOMEM; | ||
errno = EEXIST; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fix the caller too - it hardwires "out of memory".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ahh good catch on this one and one below. Having the queues_insert()
just return void is probably for best.
if (zhashx_insert (queues, name, limits) < 0) { // dups limits | ||
errno = ENOMEM; | ||
errno = EEXIST; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fix queues_insert caller error message too
if (zhashx_insert (perilog_config.processes, &proc->id, proc) < 0) { | ||
errno = EEXIST; | ||
free (proc); | ||
return NULL; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Set errno after free to avoid it getting clobbered.
src/modules/job-manager/queue.c
Outdated
if (zhashx_insert (queue->named, name, q) < 0) { | ||
jobq_destroy (q); | ||
errprintf (error, "error adding new queue"); | ||
errno = EEXIST; | ||
return -1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
already checked with zhashx_lookup. Just ignore return value of insert.
src/modules/kvs-watch/kvs-watch.c
Outdated
if (zhash_insert (ctx->namespaces, ns, nsm) < 0) { | ||
namespace_destroy (nsm); | ||
errno = EEXIST; | ||
return NULL; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
already checked, ignore return value.
6f61be5
to
075578d
Compare
re-pushed per @garlick comments above, mostly updating to ignore return from I also noticed a dumb issue in |
src/cmd/flux-exec.c
Outdated
if (!zhashx_freefn (exitsets, buf, idset_destroy_wrapper)) | ||
log_err_exit ("zhashx_freefn"); | ||
log_msg_exit ("zhashx_freefn"); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like this return value should be ignored, since zhashx_freefn() only returns NULL when the item doesn't exist, but we just inserted it so we know it does.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sounds good, tweaked that last commit to ignore the return value instead.
9a28203
to
e3fdf2a
Compare
Sorry I guess I didn't get back to this for a final approval. Want to rebase and fix that conflict and then I'll give it a quick final pass? |
e3fdf2a
to
d5c0576
Compare
@garlick doh! i had missed that there was a conflict given a recent merge, thanks for the heads up. rebased and re-pushed. I just realized I re-pushed before doing a run of the testsuite locally. Hopefully I did not re-push too aggressively :P |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Thanks!
bab0da9
to
5d9bdfe
Compare
Problem: A comment noted an invalid errno to be returned to the user.
Problem: zhash_insert() and zhashx_insert() return -1 when a duplicate entry exists, NOT when the process is out of memory. However, a number of locations assume it returns when out of memory and set errno = ENOMEM as a result. Do not assume zhash_insert()/zhashx_insert() fail on memory allocation errors. Always assume duplicate entry. When necessary set/return errno = EEXIST instead of ENOMEM. When a hash insert comes directly after a hash lookup, assume EEXIST isn't possible and do not check return value of insert call. Fixes flux-framework#5216
Problem: zhashx_freefn() only returns an error on an invalid hash entry. However, we know a successful insert just occurred so we don't have to check for an error. Ignore return value from zhashx_freefn().
5d9bdfe
to
017b9bf
Compare
Codecov Report
@@ Coverage Diff @@
## master #5217 +/- ##
==========================================
+ Coverage 83.72% 83.75% +0.03%
==========================================
Files 448 448
Lines 75876 75855 -21
==========================================
+ Hits 63527 63533 +6
+ Misses 12349 12322 -27
|
Problem: zhash_insert() and zhashx_insert() return -1 when a duplicate entry exists, NOT when the process is out of memory. However, a number of locations assume it returns when out of memory and set errno = ENOMEM as a result.
Do not assume zhash_insert()/zhashx_insert() fail on memory allocation errors. Always ssume duplicate entry. When necessary set/return errno = EEXIST instead of ENOMEM.
Fixes #5216
Notes:
My initial reason for doing this was just to make things consistent b/c there was inconsistency in
flux-core
. Don't know how necessary this is ... Maybe this was just a pointless excercise ... but since I did it, here's the PR :PThere were obviously borderline cases. Maybe another approach would be to set errno = ENOMEM when a
zhash_insert()
is done directly after azhash_lookup()
?