static enum req_fsm_nxt cnt_pipe(struct worker *wrk, struct req *req) { struct busyobj *bo; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(req, REQ_MAGIC); CHECK_OBJ_NOTNULL(req->vcl, VCL_CONF_MAGIC); wrk->stats.s_pipe++; bo = VBO_GetBusyObj(wrk, req); HTTP_Setup(bo->bereq, bo->ws, bo->vsl, SLT_BereqMethod); http_FilterReq(bo->bereq, req->http, 0); // XXX: 0 ? http_PrintfHeader(bo->bereq, "X-Varnish: %u", req->vsl->wid & VSL_IDENTMASK); http_SetHeader(bo->bereq, "Connection: close"); VCL_pipe_method(req->vcl, wrk, req, bo, req->http->ws); if (wrk->handling == VCL_RET_SYNTH) INCOMPL(); assert(wrk->handling == VCL_RET_PIPE); PipeRequest(req, bo); assert(WRW_IsReleased(wrk)); http_Teardown(bo->bereq); VBO_DerefBusyObj(wrk, &bo); return (REQ_FSM_DONE); }
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); }
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); }
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_lookup(struct worker *wrk, struct req *req) { struct objcore *oc; struct object *o; struct objhead *oh; struct busyobj *bo; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(req, REQ_MAGIC); AZ(req->objcore); CHECK_OBJ_NOTNULL(req->vcl, VCL_CONF_MAGIC); AZ(req->busyobj); VRY_Prep(req); AZ(req->objcore); oc = HSH_Lookup(req); if (oc == NULL) { /* * We lost the session to a busy object, disembark the * worker thread. We return to STP_LOOKUP when the busy * object has been unbusied, and still have the objhead * around to restart the lookup with. */ return (2); } AZ(req->objcore); CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC); oh = oc->objhead; CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC); /* If we inserted a new object it's a miss */ if (oc->flags & OC_F_BUSY) { AZ(req->busyobj); bo = VBO_GetBusyObj(wrk, req); req->busyobj = bo; /* One ref for req, one for FetchBody */ bo->refcount = 2; VRY_Finish(req, bo); oc->busyobj = bo; wrk->stats.cache_miss++; req->objcore = oc; req->req_step = R_STP_MISS; return (0); } /* We are not prepared to do streaming yet */ XXXAZ(req->busyobj); o = oc_getobj(&wrk->stats, oc); CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC); req->obj = o; VRY_Finish(req, NULL); if (oc->flags & OC_F_PASS) { wrk->stats.cache_hitpass++; VSLb(req->vsl, SLT_HitPass, "%u", req->obj->vxid); (void)HSH_Deref(&wrk->stats, NULL, &req->obj); AZ(req->objcore); req->req_step = R_STP_PASS; return (0); } wrk->stats.cache_hit++; VSLb(req->vsl, SLT_Hit, "%u", req->obj->vxid); req->req_step = R_STP_HIT; return (0); }
static int cnt_error(struct worker *wrk, struct req *req) { struct http *h; struct busyobj *bo; char date[40]; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(req, REQ_MAGIC); AZ(req->objcore); AZ(req->obj); AZ(req->busyobj); bo = VBO_GetBusyObj(wrk, req); req->busyobj = bo; AZ(bo->stats); bo->stats = &wrk->stats; req->objcore = HSH_NewObjCore(wrk); req->obj = STV_NewObject(bo, &req->objcore, TRANSIENT_STORAGE, cache_param->http_resp_size, (uint16_t)cache_param->http_max_hdr); bo->stats = NULL; if (req->obj == NULL) { req->doclose = SC_OVERLOAD; req->director = NULL; http_Teardown(bo->beresp); http_Teardown(bo->bereq); return(1); } CHECK_OBJ_NOTNULL(req->obj, OBJECT_MAGIC); req->obj->vxid = bo->vsl->wid; req->obj->exp.entered = req->t_req; h = req->obj->http; if (req->err_code < 100 || req->err_code > 999) req->err_code = 501; http_PutProtocol(h, "HTTP/1.1"); http_PutStatus(h, req->err_code); VTIM_format(W_TIM_real(wrk), date); http_PrintfHeader(h, "Date: %s", date); http_SetHeader(h, "Server: Varnish"); if (req->err_reason != NULL) http_PutResponse(h, req->err_reason); else http_PutResponse(h, http_StatusMessage(req->err_code)); VCL_error_method(req); if (req->handling == VCL_RET_RESTART && req->restarts < cache_param->max_restarts) { HSH_Drop(wrk, &req->obj); VBO_DerefBusyObj(wrk, &req->busyobj); req->req_step = R_STP_RESTART; return (0); } else if (req->handling == VCL_RET_RESTART) req->handling = VCL_RET_DELIVER; /* We always close when we take this path */ req->doclose = SC_TX_ERROR; req->wantbody = 1; assert(req->handling == VCL_RET_DELIVER); req->err_code = 0; req->err_reason = NULL; http_Teardown(bo->bereq); VBO_DerefBusyObj(wrk, &req->busyobj); req->req_step = R_STP_PREPRESP; return (0); }
static enum req_fsm_nxt cnt_error(struct worker *wrk, struct req *req) { struct http *h; struct busyobj *bo; char date[40]; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(req, REQ_MAGIC); AZ(req->objcore); AZ(req->obj); req->acct_req.error++; bo = VBO_GetBusyObj(wrk, req); AZ(bo->stats); bo->stats = &wrk->stats; bo->fetch_objcore = HSH_Private(wrk); bo->fetch_obj = STV_NewObject(bo, TRANSIENT_STORAGE, cache_param->http_resp_size, (uint16_t)cache_param->http_max_hdr); req->obj = bo->fetch_obj; bo->stats = NULL; if (req->obj == NULL) { req->doclose = SC_OVERLOAD; req->director = NULL; AZ(HSH_DerefObjCore(&wrk->stats, &bo->fetch_objcore)); bo->fetch_objcore = NULL; http_Teardown(bo->beresp); http_Teardown(bo->bereq); VBO_DerefBusyObj(wrk, &bo); return (REQ_FSM_DONE); } CHECK_OBJ_NOTNULL(req->obj, OBJECT_MAGIC); AZ(req->objcore); req->obj->vxid = bo->vsl->wid; req->obj->exp.entered = req->t_req; h = req->obj->http; if (req->err_code < 100 || req->err_code > 999) req->err_code = 501; http_PutProtocol(h, "HTTP/1.1"); http_PutStatus(h, req->err_code); VTIM_format(W_TIM_real(wrk), date); http_PrintfHeader(h, "Date: %s", date); http_SetHeader(h, "Server: Varnish"); CHECK_OBJ_NOTNULL(req->obj, OBJECT_MAGIC); HSH_Ref(req->obj->objcore); if (req->err_reason != NULL) http_PutResponse(h, req->err_reason); else http_PutResponse(h, http_StatusMessage(req->err_code)); VCL_error_method(req->vcl, wrk, req, NULL, req->http->ws); /* Stop the insanity before it turns "Hotel California" on us */ if (req->restarts >= cache_param->max_restarts) wrk->handling = VCL_RET_DELIVER; if (wrk->handling == VCL_RET_RESTART) { VBO_DerefBusyObj(wrk, &bo); HSH_Drop(wrk, &req->obj); req->req_step = R_STP_RESTART; return (REQ_FSM_MORE); } CHECK_OBJ_NOTNULL(req->obj, OBJECT_MAGIC); /* We always close when we take this path */ req->doclose = SC_TX_ERROR; req->wantbody = 1; assert(wrk->handling == VCL_RET_DELIVER); req->err_code = 0; req->err_reason = NULL; http_Teardown(bo->bereq); CHECK_OBJ_NOTNULL(req->obj, OBJECT_MAGIC); VBO_DerefBusyObj(wrk, &bo); req->req_step = R_STP_DELIVER; CHECK_OBJ_NOTNULL(req->obj, OBJECT_MAGIC); return (REQ_FSM_MORE); }
static int cnt_error(struct sess *sp) { struct http *h; char date[40]; struct worker *wrk; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); wrk = sp->wrk; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); if (wrk->obj == NULL) { HSH_Prealloc(sp); AZ(wrk->busyobj); wrk->busyobj = VBO_GetBusyObj(wrk); wrk->obj = STV_NewObject(wrk, NULL, cache_param->http_resp_size, (uint16_t)cache_param->http_max_hdr); if (wrk->obj == NULL) wrk->obj = STV_NewObject(wrk, TRANSIENT_STORAGE, cache_param->http_resp_size, (uint16_t)cache_param->http_max_hdr); if (wrk->obj == NULL) { sp->doclose = "Out of objects"; sp->director = NULL; http_Setup(wrk->busyobj->beresp, NULL); http_Setup(wrk->busyobj->bereq, NULL); sp->step = STP_DONE; return(0); } AN(wrk->obj); wrk->obj->xid = sp->xid; wrk->obj->exp.entered = sp->t_req; } else { CHECK_OBJ_NOTNULL(wrk->busyobj, BUSYOBJ_MAGIC); /* XXX: Null the headers ? */ } CHECK_OBJ_NOTNULL(wrk->obj, OBJECT_MAGIC); h = wrk->obj->http; if (sp->err_code < 100 || sp->err_code > 999) sp->err_code = 501; http_PutProtocol(wrk, sp->vsl_id, h, "HTTP/1.1"); http_PutStatus(h, sp->err_code); VTIM_format(W_TIM_real(wrk), date); http_PrintfHeader(wrk, sp->vsl_id, h, "Date: %s", date); http_SetHeader(wrk, sp->vsl_id, h, "Server: Varnish"); if (sp->err_reason != NULL) http_PutResponse(wrk, sp->vsl_id, h, sp->err_reason); else http_PutResponse(wrk, sp->vsl_id, h, http_StatusMessage(sp->err_code)); VCL_error_method(sp); if (sp->handling == VCL_RET_RESTART && sp->restarts < cache_param->max_restarts) { HSH_Drop(wrk); VBO_DerefBusyObj(wrk, &wrk->busyobj); sp->director = NULL; sp->restarts++; sp->step = STP_RECV; return (0); } else if (sp->handling == VCL_RET_RESTART) sp->handling = VCL_RET_DELIVER; /* We always close when we take this path */ sp->doclose = "error"; sp->wantbody = 1; assert(sp->handling == VCL_RET_DELIVER); sp->err_code = 0; sp->err_reason = NULL; http_Setup(wrk->busyobj->bereq, NULL); VBO_DerefBusyObj(wrk, &wrk->busyobj); sp->step = STP_PREPRESP; return (0); }
static int cnt_miss(struct sess *sp) { struct worker *wrk; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); wrk = sp->wrk; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC); AZ(wrk->obj); AN(wrk->objcore); CHECK_OBJ_NOTNULL(wrk->busyobj, BUSYOBJ_MAGIC); WS_Reset(wrk->ws, NULL); wrk->busyobj = VBO_GetBusyObj(wrk); http_Setup(wrk->busyobj->bereq, wrk->ws); http_FilterHeader(sp, HTTPH_R_FETCH); http_ForceGet(wrk->busyobj->bereq); if (cache_param->http_gzip_support) { /* * We always ask the backend for gzip, even if the * client doesn't grok it. We will uncompress for * the minority of clients which don't. */ http_Unset(wrk->busyobj->bereq, H_Accept_Encoding); http_SetHeader(wrk, sp->vsl_id, wrk->busyobj->bereq, "Accept-Encoding: gzip"); } wrk->connect_timeout = 0; wrk->first_byte_timeout = 0; wrk->between_bytes_timeout = 0; VCL_miss_method(sp); switch(sp->handling) { case VCL_RET_ERROR: AZ(HSH_Deref(wrk, wrk->objcore, NULL)); wrk->objcore = NULL; http_Setup(wrk->busyobj->bereq, NULL); VBO_DerefBusyObj(wrk, &wrk->busyobj); sp->step = STP_ERROR; return (0); case VCL_RET_PASS: AZ(HSH_Deref(wrk, wrk->objcore, NULL)); wrk->objcore = NULL; VBO_DerefBusyObj(wrk, &wrk->busyobj); sp->step = STP_PASS; return (0); case VCL_RET_FETCH: CHECK_OBJ_NOTNULL(wrk->busyobj, BUSYOBJ_MAGIC); sp->step = STP_FETCH; return (0); case VCL_RET_RESTART: AZ(HSH_Deref(wrk, wrk->objcore, NULL)); wrk->objcore = NULL; VBO_DerefBusyObj(wrk, &wrk->busyobj); INCOMPL(); default: WRONG("Illegal action in vcl_miss{}"); } }