static enum req_fsm_nxt cnt_fetch(struct worker *wrk, struct req *req) { CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(req, REQ_MAGIC); CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC); wrk->stats->s_fetch++; (void)VRB_Ignore(req); if (req->objcore->flags & OC_F_FAILED) { req->err_code = 503; req->req_step = R_STP_SYNTH; (void)HSH_DerefObjCore(wrk, &req->objcore); AZ(req->objcore); return (REQ_FSM_MORE); } req->req_step = R_STP_DELIVER; return (REQ_FSM_MORE); }
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); }
static enum req_fsm_nxt cnt_lookup(struct worker *wrk, struct req *req) { struct objcore *oc, *busy; enum lookup_e lr; int had_objhead = 0; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(req, REQ_MAGIC); AZ(req->objcore); AN(req->vcl); VRY_Prep(req); AZ(req->objcore); if (req->hash_objhead) had_objhead = 1; lr = HSH_Lookup(req, &oc, &busy, req->esi_level == 0 ? 1 : 0, req->hash_always_miss ? 1 : 0 ); if (lr == HSH_BUSY) { /* * 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 (REQ_FSM_DISEMBARK); } if (had_objhead) VSLb_ts_req(req, "Waitinglist", W_TIM_real(wrk)); if (busy == NULL) { VRY_Finish(req, DISCARD); } else { AN(busy->flags & OC_F_BUSY); VRY_Finish(req, KEEP); } AZ(req->objcore); if (lr == HSH_MISS) { /* Found nothing */ AZ(oc); AN(busy); AN(busy->flags & OC_F_BUSY); req->objcore = busy; req->req_step = R_STP_MISS; return (REQ_FSM_MORE); } CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC); AZ(oc->flags & OC_F_BUSY); req->objcore = oc; if ((oc->flags & OC_F_PASS) && busy != NULL) { /* Treat a graced Hit-For-Pass as a miss */ req->objcore = busy; req->stale_oc = oc; req->req_step = R_STP_MISS; return (REQ_FSM_MORE); } else if (oc->flags & OC_F_PASS) { /* Found a hit-for-pass */ VSLb(req->vsl, SLT_Debug, "XXXX HIT-FOR-PASS"); VSLb(req->vsl, SLT_HitPass, "%u", ObjGetXID(wrk, req->objcore)); (void)HSH_DerefObjCore(wrk, &req->objcore); wrk->stats->cache_hitpass++; req->req_step = R_STP_PASS; return (REQ_FSM_MORE); } VSLb(req->vsl, SLT_Hit, "%u", ObjGetXID(wrk, req->objcore)); VCL_hit_method(req->vcl, wrk, req, NULL, NULL); switch (wrk->handling) { case VCL_RET_DELIVER: if (busy != NULL) { AZ(oc->flags & OC_F_PASS); CHECK_OBJ_NOTNULL(busy->boc, BOC_MAGIC); VBF_Fetch(wrk, req, busy, oc, VBF_BACKGROUND); } else { (void)VRB_Ignore(req);// XXX: handle err } wrk->stats->cache_hit++; req->is_hit = 1; req->req_step = R_STP_DELIVER; return (REQ_FSM_MORE); case VCL_RET_FETCH: VSLb(req->vsl, SLT_VCL_Error, "change return(fetch) to return(miss) in vcl_hit{}"); /* FALL-THROUGH */ case VCL_RET_MISS: if (busy != NULL) { req->objcore = busy; req->stale_oc = oc; req->req_step = R_STP_MISS; } else { (void)HSH_DerefObjCore(wrk, &req->objcore); /* * We don't have a busy object, so treat this * like a pass */ VSLb(req->vsl, SLT_VCL_Error, "vcl_hit{} returns miss without busy object." " Doing pass."); req->req_step = R_STP_PASS; } return (REQ_FSM_MORE); case VCL_RET_RESTART: req->req_step = R_STP_RESTART; break; case VCL_RET_SYNTH: req->req_step = R_STP_SYNTH; break; case VCL_RET_PASS: wrk->stats->cache_hit++; req->is_hit = 1; req->req_step = R_STP_PASS; break; default: WRONG("Illegal return from vcl_hit{}"); } /* Drop our object, we won't need it */ (void)HSH_DerefObjCore(wrk, &req->objcore); if (busy != NULL) { (void)HSH_DerefObjCore(wrk, &busy); VRY_Clear(req); } return (REQ_FSM_MORE); }
static enum req_fsm_nxt cnt_synth(struct worker *wrk, struct req *req) { struct http *h; double now; struct vsb *synth_body; ssize_t sz, szl; uint8_t *ptr; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(req, REQ_MAGIC); wrk->stats->s_synth++; now = W_TIM_real(wrk); VSLb_ts_req(req, "Process", now); if (req->err_code < 100 || req->err_code > 999) req->err_code = 501; HTTP_Setup(req->resp, req->ws, req->vsl, SLT_RespMethod); h = req->resp; http_TimeHeader(h, "Date: ", now); http_SetHeader(h, "Server: Varnish"); http_PrintfHeader(req->resp, "X-Varnish: %u", VXID(req->vsl->wid)); http_PutResponse(h, "HTTP/1.1", req->err_code, req->err_reason); synth_body = VSB_new_auto(); AN(synth_body); VCL_synth_method(req->vcl, wrk, req, NULL, synth_body); AZ(VSB_finish(synth_body)); http_Unset(h, H_Content_Length); http_PrintfHeader(req->resp, "Content-Length: %zd", VSB_len(synth_body)); /* Discard any lingering request body before delivery */ (void)VRB_Ignore(req); if (wrk->handling == VCL_RET_RESTART) { HTTP_Setup(h, req->ws, req->vsl, SLT_RespMethod); VSB_destroy(&synth_body); req->req_step = R_STP_RESTART; return (REQ_FSM_MORE); } assert(wrk->handling == VCL_RET_DELIVER); req->objcore = HSH_Private(wrk); CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC); szl = -1; if (STV_NewObject(wrk, req->objcore, TRANSIENT_STORAGE, 1024)) { szl = VSB_len(synth_body); assert(szl >= 0); sz = szl; if (sz > 0 && ObjGetSpace(wrk, req->objcore, &sz, &ptr) && sz >= szl) { memcpy(ptr, VSB_data(synth_body), szl); ObjExtend(wrk, req->objcore, szl); } else if (sz > 0) { szl = -1; } } if (szl >= 0) AZ(ObjSetU64(wrk, req->objcore, OA_LEN, szl)); HSH_DerefBoc(wrk, req->objcore); VSB_destroy(&synth_body); if (szl < 0) { VSLb(req->vsl, SLT_Error, "Could not get storage"); req->doclose = SC_OVERLOAD; VSLb_ts_req(req, "Resp", W_TIM_real(wrk)); (void)HSH_DerefObjCore(wrk, &req->objcore); http_Teardown(req->resp); return (REQ_FSM_DONE); } req->req_step = R_STP_TRANSMIT; return (REQ_FSM_MORE); }
static enum req_fsm_nxt cnt_synth(struct worker *wrk, struct req *req) { char date[40]; struct http *h; double now; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(req, REQ_MAGIC); wrk->stats->s_synth++; now = W_TIM_real(wrk); VSLb_ts_req(req, "Process", now); if (req->err_code < 100 || req->err_code > 999) req->err_code = 501; HTTP_Setup(req->resp, req->ws, req->vsl, SLT_RespMethod); h = req->resp; VTIM_format(now, date); http_PrintfHeader(h, "Date: %s", date); http_SetHeader(h, "Server: Varnish"); http_PrintfHeader(req->resp, "X-Varnish: %u", VXID(req->vsl->wid)); http_PutResponse(h, "HTTP/1.1", req->err_code, req->err_reason); AZ(req->synth_body); req->synth_body = VSB_new_auto(); AN(req->synth_body); VCL_synth_method(req->vcl, wrk, req, NULL, req->http->ws); http_Unset(h, H_Content_Length); AZ(VSB_finish(req->synth_body)); if (wrk->handling == VCL_RET_RESTART) { HTTP_Setup(h, req->ws, req->vsl, SLT_RespMethod); VSB_delete(req->synth_body); req->synth_body = NULL; req->req_step = R_STP_RESTART; return (REQ_FSM_MORE); } assert(wrk->handling == VCL_RET_DELIVER); if (http_HdrIs(req->resp, H_Connection, "close")) req->doclose = SC_RESP_CLOSE; /* Discard any lingering request body before delivery */ (void)VRB_Ignore(req); V1D_Deliver_Synth(req); VSLb_ts_req(req, "Resp", W_TIM_real(wrk)); VSB_delete(req->synth_body); req->synth_body = NULL; req->err_code = 0; req->err_reason = NULL; return (REQ_FSM_DONE); }