-
Notifications
You must be signed in to change notification settings - Fork 381
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
Add a facility for unlocked director iteration #4142
base: master
Are you sure you want to change the base?
Conversation
febd306
to
f79bd4c
Compare
After rebasing on the newly understood 4e2c50d, I have successfully run my stress test on this patch without any issues. |
Here's a macro which does that: /*
* this macro might look a bit daunting, but it is really just two things:
*
* - the outer for loop is only to declare the local "next" variable
* and execute the inner for loop once
*
* - the inner for loop is VTAILQ_FOREACH_SAFE with calls to
* vdire_{start,end}_iter() added at the right places:
* start is called at initialization and end when var becomes NULL
* and the loop ends
*
* problem: none of break, goto or return must be used from the loop body
*/
#define _VDIRE_FOREACH(var, vdire, next) \
for (struct vcldir *next = (void *)&next; \
next == (void *)&next; \
next = NULL) \
for (vdire_start_iter(vdire), \
(var) = VTAILQ_FIRST(&(vdire)->directors); \
((var) || (vdire_end_iter(vdire), 0)) && \
((next) = VTAILQ_NEXT(var, directors_list), 1); \
(var) = (next))
#define VDIRE_FOREACH(var, vdire) \
_VDIRE_FOREACH(var, vdire, VUNIQ_NAME(_vdirenext)) As stated in the comment, none of |
Putting this out of draft status despite not having worked on it any more, because it has received no feedback and I think it's actually important - now having seen one production case where this is at least a potential candidate. |
bugwash: good idea by phk: New iterators encountering retired backends should wait until they are cleared, otherwise a constant stream of iterators could prevent retirement. I do not think this is a realistic scenario at this point, but we might as well do this right from the start. another feedback question is if we can simplify this patch with an r/w lock. I am sure that I did look at this for quite some time and came to the conclusion that it does not do much to help us, but I will revisit this question. |
done: 41c42a0
I do not see the simplification. With an rwlock, |
6eb58c3
to
804fbee
Compare
I'm OK with this, as long as this iterator API is only for use by the CLI thread, and this should be documented in the code with an We should (probably) hand the resigned_list to a worker thread, rather than bog down the CLI thread with potentially many cleanup calls. I think the iterator should skip directors which have already been retired, no point in the CLI processing them if they are already (potentially long since) gone. Apart from that: OK with me. |
Pondering varnishcache#4140 made me realize that our central per-vcl director list constitutes a classic case of iterating a mutable list. That besides the already known fact that running potentially expensive iterator functions while holding the vcl_mtx is a very bad idea. So this patch is a suggestion on how to get out of this situation. It does not go all the way (it still leaves unsolved a similar problem of iterating over all backends of _all vcls_), but shows an attempt on how to tackle the "iterate over one VCL's backends". We add a fittingly named 'vdire' facility which manages the director list and, in particular, director retirement. The main change is that, while iterators are active on the director list, vcl_mtx is _not_ held and any request of a director to retire only ends up in a resignation, which manifests by this director being put on a second list. When all iterators have completed, the resignation list is worked and the actual retirement carried out.
This is to prevent a potential pileup of resigned directors with a constant stream of iterators coming on
The next force-push has these changes (besides the rebase and typo fix): skip resigned backendswe can identify these by a zero refcount. It is is already illegal to assign a director with a zero backend. diff --git a/bin/varnishd/cache/cache_vcl.c b/bin/varnishd/cache/cache_vcl.c
index 12ed136a7..918537e50 100644
--- a/bin/varnishd/cache/cache_vcl.c
+++ b/bin/varnishd/cache/cache_vcl.c
@@ -469,6 +469,8 @@ vdire_iter(struct cli *cli, const char *pat, const struct vcl *vcl,
vdire_start_iter(vdire);
VTAILQ_FOREACH(vdir, &vdire->directors, directors_list) {
+ if (vdir->refcnt == 0)
+ continue;
if (pat != NULL && fnmatch(pat, vdir->cli_name, 0))
continue;
found++; this is done only for
|
Pondering #4140 made me realize that our central per-vcl director list constitutes a classic case of iterating a mutable list. That besides the already known fact that running potentially expensive iterator functions while holding the vcl_mtx is a very bad idea.
So this patch is a suggestion on how to get out of this situation. It does not go all the way (it still leaves unsolved a similar problem of iterating over all backends of all vcls), but shows an attempt on how to tackle the "iterate over one VCL's backends".
We add a fittingly named 'vdire' facility which manages the director list and, in particular, director retirement. The main change is that, while iterators are active on the director list, vcl_mtx is not held and any request of a director to retire only ends up in a resignation, which manifests by this director being put on a second list.
When all iterators have completed, the resignation list is worked and the actual retirement carried out.
NOTE: I am particularly not happy about the vdire_(start|end)_iter() interface being exposed. What I would like to see is a FOREACH macro which does both the start and end. Having to use an iterator with a callback is clumsy, and having to directly call start/end with a VTAILQ_FOREACH feels like crossing interfaces.See #4142 (comment)