int SES_Schedule(struct sess *sp) { struct sesspool *pp; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); AZ(sp->wrk); pp = sp->sesspool; CHECK_OBJ_NOTNULL(pp, SESSPOOL_MAGIC); AN(pp->pool); AZ(sp->wrk); sp->task.func = ses_pool_task; sp->task.priv = sp; if (Pool_Task(pp->pool, &sp->task, POOL_QUEUE_FRONT)) { VSC_C_main->client_drop_late++; sp->t_idle = VTIM_real(); if (sp->req != NULL && sp->req->vcl != NULL) { /* * A session parked on a busy object can come here * after it wakes up. Loose the VCL reference. */ VCL_Rel(&sp->req->vcl); } SES_Delete(sp, "dropped", sp->t_idle); return (1); } return (0); }
void VBF_Fetch(struct worker *wrk, struct req *req, struct objcore *oc, struct object *oldobj, enum vbf_fetch_mode_e mode) { struct busyobj *bo; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(req, REQ_MAGIC); CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC); CHECK_OBJ_ORNULL(oldobj, OBJECT_MAGIC); bo = VBO_GetBusyObj(wrk, req); CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); bo->refcount = 2; oc->busyobj = bo; CHECK_OBJ_NOTNULL(bo->vcl, VCL_CONF_MAGIC); if (mode == VBF_PASS) bo->do_pass = 1; bo->vary = req->vary_b; req->vary_b = NULL; HSH_Ref(oc); bo->fetch_objcore = oc; if (oldobj != NULL) { if (http_GetHdr(oldobj->http, H_Last_Modified, NULL) || http_GetHdr(oldobj->http, H_ETag, NULL)) { HSH_Ref(oldobj->objcore); bo->ims_obj = oldobj; } } AZ(bo->req); bo->req = req; bo->fetch_task.priv = bo; bo->fetch_task.func = vbf_fetch_thread; if (Pool_Task(wrk->pool, &bo->fetch_task, POOL_QUEUE_FRONT)) vbf_fetch_thread(wrk, bo); if (mode == VBF_BACKGROUND) { VBO_waitstate(bo, BOS_REQ_DONE); } else { VBO_waitstate(bo, BOS_FETCHING); if (!bo->do_stream) VBO_waitstate(bo, BOS_FINISHED); assert(bo->state != BOS_FAILED || (oc->flags & OC_F_FAILED)); } VBO_DerefBusyObj(wrk, &bo); }
void SES_Handle(struct sess *sp, double now) { struct sesspool *pp; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); pp = sp->sesspool; CHECK_OBJ_NOTNULL(pp, SESSPOOL_MAGIC); AN(pp->pool); sp->task.func = ses_sess_pool_task; sp->task.priv = sp; if (Pool_Task(pp->pool, &sp->task, POOL_QUEUE_FRONT)) SES_Delete(sp, SC_OVERLOAD, now); }
int SES_Reschedule_Req(struct req *req) { struct sess *sp; struct pool *pp; CHECK_OBJ_NOTNULL(req, REQ_MAGIC); sp = req->sp; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); pp = sp->pool; CHECK_OBJ_NOTNULL(pp, POOL_MAGIC); AN(req->task.func); return (Pool_Task(pp, &req->task, TASK_QUEUE_REQ)); }
int SES_Reschedule_Req(struct req *req) { struct sess *sp; struct sesspool *pp; CHECK_OBJ_NOTNULL(req, REQ_MAGIC); sp = req->sp; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); pp = sp->sesspool; CHECK_OBJ_NOTNULL(pp, SESSPOOL_MAGIC); AN(pp->pool); req->task.func = SES_Proto_Req; req->task.priv = req; return (Pool_Task(pp->pool, &req->task, POOL_QUEUE_FRONT)); }
struct busyobj * VBF_Fetch(struct worker *wrk, struct req *req, struct objcore *oc, int pass) { struct busyobj *bo; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(req, REQ_MAGIC); CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC); bo = VBO_GetBusyObj(wrk, req); CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); bo->refcount = 2; oc->busyobj = bo; CHECK_OBJ_NOTNULL(bo->vcl, VCL_CONF_MAGIC); bo->do_pass = pass; bo->vary = req->vary_b; req->vary_b = NULL; AZ(bo->fetch_objcore); bo->fetch_objcore = oc; AZ(bo->req); bo->req = req; bo->fetch_task.priv = bo; bo->fetch_task.func = vbf_fetch_thread; if (Pool_Task(wrk->pool, &bo->fetch_task, POOL_QUEUE_FRONT)) vbf_fetch_thread(wrk, bo); Lck_Lock(&bo->mtx); while (1) { if (bo->req == NULL) break; (void)Lck_CondWait(&bo->cond, &bo->mtx, NULL); } Lck_Unlock(&bo->mtx); return (bo); }
ses_handle(struct waited *wp, enum wait_event ev, double now) { struct sess *sp; struct pool *pp; struct pool_task *tp; const struct transport *xp; CHECK_OBJ_NOTNULL(wp, WAITED_MAGIC); CAST_OBJ_NOTNULL(sp, wp->priv1, SESS_MAGIC); CAST_OBJ_NOTNULL(xp, (const void*)wp->priv2, TRANSPORT_MAGIC); AN(wp->priv2); assert((void *)sp->ws->f == wp); wp->magic = 0; wp = NULL; WS_Release(sp->ws, 0); switch (ev) { case WAITER_TIMEOUT: SES_Delete(sp, SC_RX_TIMEOUT, now); break; case WAITER_REMCLOSE: SES_Delete(sp, SC_REM_CLOSE, now); break; case WAITER_ACTION: pp = sp->pool; CHECK_OBJ_NOTNULL(pp, POOL_MAGIC); assert(sizeof *tp <= WS_Reserve(sp->ws, sizeof *tp)); tp = (void*)sp->ws->f; tp->func = xp->unwait; tp->priv = sp; if (Pool_Task(pp, tp, TASK_QUEUE_REQ)) SES_Delete(sp, SC_OVERLOAD, now); break; case WAITER_CLOSE: WRONG("Should not see WAITER_CLOSE on client side"); break; default: WRONG("Wrong event in ses_handle"); } }
int SES_ScheduleReq(struct req *req) { struct sess *sp; struct sesspool *pp; CHECK_OBJ_NOTNULL(req, REQ_MAGIC); sp = req->sp; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); pp = sp->sesspool; CHECK_OBJ_NOTNULL(pp, SESSPOOL_MAGIC); AN(pp->pool); sp->task.func = ses_req_pool_task; sp->task.priv = req; if (Pool_Task(pp->pool, &sp->task, POOL_QUEUE_FRONT)) { AN (req->vcl); VCL_Rel(&req->vcl); SES_Delete(sp, SC_OVERLOAD, NAN); return (1); } return (0); }
ses_handle(struct waited *wp, enum wait_event ev, double now) { struct sess *sp; struct sesspool *pp; struct pool_task *tp; CHECK_OBJ_NOTNULL(wp, WAITED_MAGIC); CAST_OBJ_NOTNULL(sp, wp->ptr, SESS_MAGIC); AZ(sp->ws->r); switch (ev) { case WAITER_TIMEOUT: SES_Delete(sp, SC_RX_TIMEOUT, now); break; case WAITER_REMCLOSE: SES_Delete(sp, SC_REM_CLOSE, now); break; case WAITER_ACTION: pp = sp->sesspool; CHECK_OBJ_NOTNULL(pp, SESSPOOL_MAGIC); AN(pp->pool); assert(sizeof *tp == WS_Reserve(sp->ws, sizeof *tp)); tp = (void*)sp->ws->f; tp->func = SES_Proto_Sess; tp->priv = sp; if (Pool_Task(pp->pool, tp, POOL_QUEUE_FRONT)) SES_Delete(sp, SC_OVERLOAD, now); break; case WAITER_CLOSE: WRONG("Should not see WAITER_CLOSE on client side"); break; default: WRONG("Wrong event in ses_handle"); } }
void VBF_Fetch(struct worker *wrk, struct req *req, struct objcore *oc, struct objcore *oldoc, enum vbf_fetch_mode_e mode) { struct boc *boc; struct busyobj *bo; const char *how; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(req, REQ_MAGIC); CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC); AN(oc->flags & OC_F_BUSY); CHECK_OBJ_ORNULL(oldoc, OBJCORE_MAGIC); bo = VBO_GetBusyObj(wrk, req); CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); boc = HSH_RefBoc(oc); CHECK_OBJ_NOTNULL(boc, BOC_MAGIC); switch (mode) { case VBF_PASS: how = "pass"; bo->do_pass = 1; break; case VBF_NORMAL: how = "fetch"; break; case VBF_BACKGROUND: how = "bgfetch"; bo->is_bgfetch = 1; break; default: WRONG("Wrong fetch mode"); } VSLb(bo->vsl, SLT_Begin, "bereq %u %s", VXID(req->vsl->wid), how); VSLb(req->vsl, SLT_Link, "bereq %u %s", VXID(bo->vsl->wid), how); THR_SetBusyobj(bo); bo->sp = req->sp; SES_Ref(bo->sp); AN(bo->vcl); oc->boc->vary = req->vary_b; req->vary_b = NULL; HSH_Ref(oc); AZ(bo->fetch_objcore); bo->fetch_objcore = oc; AZ(bo->stale_oc); if (oldoc != NULL) { assert(oldoc->refcnt > 0); HSH_Ref(oldoc); bo->stale_oc = oldoc; } AZ(bo->req); bo->req = req; bo->fetch_task.priv = bo; bo->fetch_task.func = vbf_fetch_thread; if (Pool_Task(wrk->pool, &bo->fetch_task, TASK_QUEUE_BO)) { wrk->stats->fetch_no_thread++; (void)vbf_stp_fail(req->wrk, bo); if (bo->stale_oc != NULL) (void)HSH_DerefObjCore(wrk, &bo->stale_oc, 0); HSH_DerefBoc(wrk, oc); SES_Rel(bo->sp); VBO_ReleaseBusyObj(wrk, &bo); } else { bo = NULL; /* ref transferred to fetch thread */ if (mode == VBF_BACKGROUND) { ObjWaitState(oc, BOS_REQ_DONE); (void)VRB_Ignore(req); } else { ObjWaitState(oc, BOS_STREAM); if (oc->boc->state == BOS_FAILED) { AN((oc->flags & OC_F_FAILED)); } else { AZ(oc->flags & OC_F_BUSY); } } } AZ(bo); VSLb_ts_req(req, "Fetch", W_TIM_real(wrk)); assert(oc->boc == boc); HSH_DerefBoc(wrk, oc); if (mode == VBF_BACKGROUND) (void)HSH_DerefObjCore(wrk, &oc, HSH_RUSH_POLICY); THR_SetBusyobj(NULL); }
void VBF_Fetch(struct worker *wrk, struct req *req, struct objcore *oc, struct object *oldobj, enum vbf_fetch_mode_e mode) { struct busyobj *bo; const char *how; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(req, REQ_MAGIC); CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC); CHECK_OBJ_ORNULL(oldobj, OBJECT_MAGIC); switch(mode) { case VBF_PASS: how = "pass"; break; case VBF_NORMAL: how = "fetch"; break; case VBF_BACKGROUND: how = "bgfetch"; break; default: WRONG("Wrong fetch mode"); } bo = VBO_GetBusyObj(wrk, req); CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); VSLb(bo->vsl, SLT_Begin, "bereq %u %s ", VXID(req->vsl->wid), how); VSLb(req->vsl, SLT_Link, "bereq %u %s ", VXID(bo->vsl->wid), how); THR_SetBusyobj(bo); bo->refcount = 2; oc->busyobj = bo; CHECK_OBJ_NOTNULL(bo->vcl, VCL_CONF_MAGIC); if (mode == VBF_PASS) bo->do_pass = 1; bo->vary = req->vary_b; req->vary_b = NULL; if (mode != VBF_BACKGROUND) HSH_Ref(oc); bo->fetch_objcore = oc; AZ(bo->ims_obj); if (oldobj != NULL) { if (http_GetHdr(oldobj->http, H_Last_Modified, NULL) || http_GetHdr(oldobj->http, H_ETag, NULL)) { assert(oldobj->objcore->refcnt > 0); HSH_Ref(oldobj->objcore); bo->ims_obj = oldobj; } } AZ(bo->req); bo->req = req; bo->fetch_task.priv = bo; bo->fetch_task.func = vbf_fetch_thread; if (Pool_Task(wrk->pool, &bo->fetch_task, POOL_QUEUE_FRONT)) vbf_fetch_thread(wrk, bo); if (mode == VBF_BACKGROUND) { VBO_waitstate(bo, BOS_REQ_DONE); } else { VBO_waitstate(bo, BOS_STREAM); if (bo->state == BOS_FAILED) { AN((oc->flags & OC_F_FAILED)); } else { AZ(bo->fetch_objcore->flags & OC_F_BUSY); } } VSLb_ts_req(req, "Fetch", W_TIM_real(wrk)); THR_SetBusyobj(NULL); VBO_DerefBusyObj(wrk, &bo); }
static int cnt_fetchbody(struct worker *wrk, struct req *req) { struct http *hp, *hp2; char *b; uint16_t nhttp; unsigned l; struct vsb *vary = NULL; int varyl = 0, pass; struct busyobj *bo; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(req, REQ_MAGIC); bo = req->busyobj; CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); assert(req->handling == VCL_RET_DELIVER); if (req->objcore->objhead == NULL) { /* This is a pass from vcl_recv */ pass = 1; /* VCL may have fiddled this, but that doesn't help */ bo->exp.ttl = -1.; } else if (bo->do_pass) { pass = 1; } else { /* regular object */ pass = 0; } /* * The VCL variables beresp.do_g[un]zip tells us how we want the * object processed before it is stored. * * The backend Content-Encoding header tells us what we are going * to receive, which we classify in the following three classes: * * "Content-Encoding: gzip" --> object is gzip'ed. * no Content-Encoding --> object is not gzip'ed. * anything else --> do nothing wrt gzip * */ /* We do nothing unless the param is set */ if (!cache_param->http_gzip_support) bo->do_gzip = bo->do_gunzip = 0; bo->is_gzip = http_HdrIs(bo->beresp, H_Content_Encoding, "gzip"); bo->is_gunzip = !http_GetHdr(bo->beresp, H_Content_Encoding, NULL); /* It can't be both */ assert(bo->is_gzip == 0 || bo->is_gunzip == 0); /* We won't gunzip unless it is gzip'ed */ if (bo->do_gunzip && !bo->is_gzip) bo->do_gunzip = 0; /* If we do gunzip, remove the C-E header */ if (bo->do_gunzip) http_Unset(bo->beresp, H_Content_Encoding); /* We wont gzip unless it is ungziped */ if (bo->do_gzip && !bo->is_gunzip) bo->do_gzip = 0; /* If we do gzip, add the C-E header */ if (bo->do_gzip) http_SetHeader(bo->beresp, "Content-Encoding: gzip"); /* But we can't do both at the same time */ assert(bo->do_gzip == 0 || bo->do_gunzip == 0); /* ESI takes precedence and handles gzip/gunzip itself */ if (bo->do_esi) bo->vfp = &vfp_esi; else if (bo->do_gunzip) bo->vfp = &vfp_gunzip; else if (bo->do_gzip) bo->vfp = &vfp_gzip; else if (bo->is_gzip) bo->vfp = &vfp_testgzip; if (bo->do_esi || req->esi_level > 0) bo->do_stream = 0; if (!req->wantbody) bo->do_stream = 0; /* No reason to try streaming a non-existing body */ if (bo->body_status == BS_NONE) bo->do_stream = 0; l = http_EstimateWS(bo->beresp, pass ? HTTPH_R_PASS : HTTPH_A_INS, &nhttp); /* Create Vary instructions */ if (req->objcore->objhead != NULL) { CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC); vary = VRY_Create(req, bo->beresp); if (vary != NULL) { varyl = VSB_len(vary); assert(varyl > 0); l += varyl; } } /* * Space for producing a Content-Length: header including padding * A billion gigabytes is enough for anybody. */ l += strlen("Content-Length: XxxXxxXxxXxxXxxXxx") + sizeof(void *); if (bo->exp.ttl < cache_param->shortlived || req->objcore == NULL) req->storage_hint = TRANSIENT_STORAGE; AZ(bo->stats); bo->stats = &wrk->stats; req->obj = STV_NewObject(bo, &req->objcore, req->storage_hint, l, nhttp); if (req->obj == NULL) { /* * Try to salvage the transaction by allocating a * shortlived object on Transient storage. */ if (bo->exp.ttl > cache_param->shortlived) bo->exp.ttl = cache_param->shortlived; bo->exp.grace = 0.0; bo->exp.keep = 0.0; req->obj = STV_NewObject(bo, &req->objcore, TRANSIENT_STORAGE, l, nhttp); } bo->stats = NULL; if (req->obj == NULL) { req->err_code = 503; req->req_step = R_STP_ERROR; VDI_CloseFd(&bo->vbc); VBO_DerefBusyObj(wrk, &req->busyobj); return (0); } CHECK_OBJ_NOTNULL(req->obj, OBJECT_MAGIC); req->storage_hint = NULL; AZ(bo->fetch_obj); bo->fetch_obj = req->obj; if (bo->do_gzip || (bo->is_gzip && !bo->do_gunzip)) req->obj->gziped = 1; if (vary != NULL) { req->obj->vary = (void *)WS_Copy(req->obj->http->ws, VSB_data(vary), varyl); AN(req->obj->vary); VRY_Validate(req->obj->vary); VSB_delete(vary); } req->obj->vxid = bo->vsl->wid; req->obj->response = req->err_code; WS_Assert(req->obj->ws_o); /* Filter into object */ hp = bo->beresp; hp2 = req->obj->http; hp2->logtag = HTTP_Obj; http_FilterResp(hp, hp2, pass ? HTTPH_R_PASS : HTTPH_A_INS); http_CopyHome(hp2); if (http_GetHdr(hp, H_Last_Modified, &b)) req->obj->last_modified = VTIM_parse(b); else req->obj->last_modified = floor(bo->exp.entered); assert(WRW_IsReleased(wrk)); /* * If we can deliver a 304 reply, we don't bother streaming. * Notice that vcl_deliver{} could still nuke the headers * that allow the 304, in which case we return 200 non-stream. */ if (req->obj->response == 200 && req->http->conds && RFC2616_Do_Cond(req)) bo->do_stream = 0; /* * Ready to fetch the body */ bo->fetch_task.func = FetchBody; bo->fetch_task.priv = bo; assert(bo->refcount == 2); /* one for each thread */ if (req->obj->objcore->objhead != NULL) { EXP_Insert(req->obj); AN(req->obj->objcore->ban); AZ(req->obj->ws_o->overflow); HSH_Unbusy(&wrk->stats, req->obj->objcore); } if (!bo->do_stream || Pool_Task(wrk->pool, &bo->fetch_task, POOL_NO_QUEUE)) FetchBody(wrk, bo); if (req->obj->objcore->objhead != NULL) HSH_Ref(req->obj->objcore); if (bo->state == BOS_FINISHED) { VBO_DerefBusyObj(wrk, &req->busyobj); } else if (bo->state == BOS_FAILED) { /* handle early failures */ HSH_Deref(&wrk->stats, NULL, &req->obj); VBO_DerefBusyObj(wrk, &req->busyobj); req->err_code = 503; req->req_step = R_STP_ERROR; return (0); } assert(WRW_IsReleased(wrk)); req->req_step = R_STP_PREPRESP; return (0); }