Skip to content
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

vdire: plug the remaining vcl temperature change races #4259

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 93 additions & 10 deletions bin/varnishd/cache/cache_vcl.c
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,36 @@ vdire_end_iter(struct vdire *vdire)
vcldir_retire(vdir, temp);
}

/*
* like vdire_start_iter, but also prepare for backend_event_*()
* by setting the checkpoint
*/
static void
vdire_start_event(struct vdire *vdire, const struct vcltemp *temp)
{

CHECK_OBJ_NOTNULL(vdire, VDIRE_MAGIC);
AN(temp);

Lck_AssertHeld(vdire->mtx);

// https://github.com/varnishcache/varnish-cache/pull/4142#issuecomment-2593091097
ASSERT_CLI();

AZ(vdire->checkpoint);
vdire->checkpoint = VTAILQ_LAST(&vdire->directors, vcldir_head);
AN(vdire->tempp);
*vdire->tempp = temp;
vdire->iterating++;
}

static void
vdire_end_event(struct vdire *vdire)
{
vdire->checkpoint = NULL;
vdire_end_iter(vdire);
}

// if there are no iterators, remove from directors and retire
// otherwise put on resigning list to work when iterators end
void
Expand Down Expand Up @@ -557,8 +587,13 @@ VCL_IterDirector(struct cli *cli, const char *pat,
return (found);
}

/*
* vdire_start_event() must have been called before
*
* send event to directors pre checkpoint
*/
static void
vcl_BackendEvent(const struct vcl *vcl, enum vcl_event_e e)
backend_event_base(const struct vcl *vcl, enum vcl_event_e e)
{
struct vcldir *vdir;
struct vdire *vdire;
Expand All @@ -567,11 +602,54 @@ vcl_BackendEvent(const struct vcl *vcl, enum vcl_event_e e)
CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
AZ(vcl->busy);
vdire = vcl->vdire;
AN(vdire->iterating);

vdire_start_iter(vdire);
VTAILQ_FOREACH(vdir, &vdire->directors, directors_list)
if (vdire->checkpoint == NULL)
return;

VTAILQ_FOREACH(vdir, &vdire->directors, directors_list) {
VDI_Event(vdir->dir, e);
vdire_end_iter(vdire);
if (vdir == vdire->checkpoint)
break;
}
}

/*
* vdire_start_event() must have been called before
*
* set a new temperature.
* send event to directors added post checkpoint, but before
* the new temperature
*/
static void
backend_event_delta(const struct vcl *vcl, enum vcl_event_e e, const struct vcltemp *temp)
{
struct vcldir *vdir, *end;
struct vdire *vdire;

ASSERT_CLI();
CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
AZ(vcl->busy);
vdire = vcl->vdire;
AN(temp);
AN(vdire->iterating);

Lck_Lock(vdire->mtx);
if (vdire->checkpoint == NULL)
vdir = VTAILQ_FIRST(&vdire->directors);
else
vdir = VTAILQ_NEXT(vdire->checkpoint, directors_list);
AN(vdire->tempp);
*vdire->tempp = temp;
end = VTAILQ_LAST(&vdire->directors, vcldir_head);
Lck_Unlock(vdire->mtx);

while (vdir != NULL) {
VDI_Event(vdir->dir, e);
if (vdir == end)
break;
vdir = VTAILQ_NEXT(vdire->checkpoint, directors_list);
}
}

static void
Expand Down Expand Up @@ -742,10 +820,12 @@ vcl_set_state(struct vcl *vcl, const char *state, struct vsb **msg)
break;
if (vcl->busy == 0 && vcl->temp->is_warm) {
Lck_Lock(&vcl_mtx);
vcl->temp = VTAILQ_EMPTY(&vcl->ref_list) ?
VCL_TEMP_COLD : VCL_TEMP_COOLING;
vdire_start_event(vcl->vdire, VTAILQ_EMPTY(&vcl->ref_list) ?
VCL_TEMP_COLD : VCL_TEMP_COOLING);
Lck_Unlock(&vcl_mtx);
vcl_BackendEvent(vcl, VCL_EVENT_COLD);
backend_event_base(vcl, VCL_EVENT_COLD);
vdire_end_event(vcl->vdire);
// delta directors at VCL_TEMP_COLD do not need an event
AZ(vcl_send_event(vcl, VCL_EVENT_COLD, msg));
AZ(*msg);
}
Expand All @@ -769,16 +849,19 @@ vcl_set_state(struct vcl *vcl, const char *state, struct vsb **msg)
}
else {
Lck_Lock(&vcl_mtx);
vcl->temp = VCL_TEMP_WARM;
vdire_start_event(vcl->vdire, VCL_TEMP_WARM);
Lck_Unlock(&vcl_mtx);
i = vcl_send_event(vcl, VCL_EVENT_WARM, msg);
if (i == 0) {
vcl_BackendEvent(vcl, VCL_EVENT_WARM);
backend_event_base(vcl, VCL_EVENT_WARM);
// delta directors are already warm
vdire_end_event(vcl->vdire);
break;
}
AZ(vcl_send_event(vcl, VCL_EVENT_COLD, &nomsg));
AZ(nomsg);
vcl->temp = VCL_TEMP_COLD;
backend_event_delta(vcl, VCL_EVENT_COLD, VCL_TEMP_COLD);
vdire_end_event(vcl->vdire);
}
break;
default:
Expand Down
2 changes: 2 additions & 0 deletions bin/varnishd/cache/cache_vcl.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ struct vdire {
// to signal when iterators can enter again
pthread_cond_t cond;
const struct vcltemp **tempp;
// last director present when vdire_start_event is called
struct vcldir *checkpoint;
};

struct vcl {
Expand Down