source: bin/varnishd/cache_vrt.c @ b7839e

Revision b7839e, 14.4 KB checked in by Poul-Henning Kamp <phk@…>, 6 years ago (diff)

Finish (the "easy") part of degraded mode:

Add req.grace timer: We only serve degraded mode objects if both the
request and the object's grace timers are satisfied.

Sort expiry list on obj.ttl + obj.grace and fiddle list if either changes.

In the hash lookup: record if any objects still in grace by obj.grace which
match our Vary: criteria (if any).

If no in-ttl object was found AND we have a graced object AND it is also
graced by req.grace AND it is being fetched: serve the graced object.

Otherwise, mark us as successor to the graced object while we fetch to
give others the chance.

When we unbusy the object, clean the magic pointers between the two
objects again.

To play with this you need at least:

sub vcl_recv {

set req.grace = 2m;

}
sub vcl_fetch {

set obj.grace = 2m;

}

git-svn-id:  http://www.varnish-cache.org/svn/trunk/varnish-cache@2392 d4fa192b-c00b-0410-8231-f00ffab90ce4

  • Property mode set to 100644
Line 
1/*-
2 * Copyright (c) 2006 Verdens Gang AS
3 * Copyright (c) 2006-2007 Linpro AS
4 * All rights reserved.
5 *
6 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $Id$
30 *
31 * Runtime support for compiled VCL programs
32 */
33
34#include <sys/types.h>
35#include <sys/socket.h>
36
37#include <netinet/in.h>
38
39#include <stdio.h>
40#include <string.h>
41#include <stdlib.h>
42#include <stdarg.h>
43
44#include "shmlog.h"
45#include "heritage.h"
46#include "vrt.h"
47#include "vrt_obj.h"
48#include "vcl.h"
49#include "cache.h"
50
51/*--------------------------------------------------------------------*/
52
53void
54VRT_error(struct sess *sp, unsigned code, const char *reason)
55{
56
57        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
58        WSL(sp->wrk, SLT_Debug, 0, "VCL_error(%u, %s)", code, reason);
59        sp->err_code = code ? code : 503;
60        sp->err_reason = reason ? reason : http_StatusMessage(sp->err_code);
61}
62
63/*--------------------------------------------------------------------*/
64
65void
66VRT_count(const struct sess *sp, unsigned u)
67{
68
69        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
70        if (params->vcl_trace)
71                WSP(sp, SLT_VCL_trace, "%u %d.%d", u,
72                    sp->vcl->ref[u].line, sp->vcl->ref[u].pos);
73}
74
75/*--------------------------------------------------------------------*/
76
77static struct http *
78vrt_selecthttp(const struct sess *sp, enum gethdr_e where)
79{
80        struct http *hp;
81
82        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
83        switch (where) {
84        case HDR_REQ:
85                hp = sp->http;
86                break;
87        case HDR_BEREQ:
88                hp = sp->bereq->http;
89                break;
90        case HDR_RESP:
91                hp = sp->http;
92                break;
93        case HDR_OBJ:
94                hp = sp->obj->http;
95                break;
96        default:
97                INCOMPL();
98        }
99        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
100        return (hp);
101}
102
103char *
104VRT_GetHdr(const struct sess *sp, enum gethdr_e where, const char *n)
105{
106        char *p;
107        struct http *hp;
108
109        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
110        hp = vrt_selecthttp(sp, where);
111        if (!http_GetHdr(hp, n, &p))
112                return (NULL);
113        return (p);
114}
115
116/*--------------------------------------------------------------------*/
117
118static char *
119vrt_assemble_string(struct http *hp, const char *h, const char *p, va_list ap)
120{
121        char *b, *e;
122        unsigned u, x;
123
124        u = WS_Reserve(hp->ws, 0);
125        e = b = hp->ws->f;
126        e += u;
127        if (h != NULL) {
128                x = strlen(h);
129                if (b + x < e)
130                        memcpy(b, h, x);
131                b += x;
132                if (b + 1 < e) 
133                        *b++ = ' ';
134        }
135        while (p != NULL) {
136                x = strlen(p);
137                if (b + x < e)
138                        memcpy(b, p, x);
139                b += x;
140                p = va_arg(ap, const char *);
141        }
142        if (b + 1 < e) 
143                *b++ = '\0';
144        if (b > e) {
145                WS_Release(hp->ws, 0);
146                return (NULL);
147        } else {
148                e = b;
149                b = hp->ws->f;
150                WS_Release(hp->ws, 1 + e - b);
151                return (b);
152        }
153}
154
155/*--------------------------------------------------------------------*/
156
157void
158VRT_SetHdr(const struct sess *sp , enum gethdr_e where, const char *hdr, const char *p, ...)
159{
160        struct http *hp;
161        va_list ap;
162        char *b;
163
164        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
165        hp = vrt_selecthttp(sp, where);
166        va_start(ap, p);
167        if (p == NULL) {
168                http_Unset(hp, hdr);
169        } else {
170                b = vrt_assemble_string(hp, hdr + 1, p, ap);
171                if (b == NULL) {
172                        WSP(sp, SLT_LostHeader, "%s", hdr + 1);
173                } else {
174                        http_Unset(hp, hdr);
175                        http_SetHeader(sp->wrk, sp->fd, hp, b);
176                }
177        }
178        va_end(ap);
179}
180
181/*--------------------------------------------------------------------*/
182
183static void
184vrt_do_string(struct worker *w, int fd, struct http *hp, int fld, const char *err, const char *p, va_list ap)
185{
186        char *b;
187
188        AN(p);
189        AN(hp);
190        b = vrt_assemble_string(hp, NULL, p, ap);
191        if (b == NULL) {
192                WSL(w, SLT_LostHeader, fd, err);
193        } else {
194                http_SetH(hp, fld, b);
195        }
196        va_end(ap);
197}
198
199#define VRT_DO_HDR(obj, hdr, http, fld)                         \
200void                                                            \
201VRT_l_##obj##_##hdr(const struct sess *sp, const char *p, ...)  \
202{                                                               \
203        va_list ap;                                             \
204                                                                \
205        AN(p);                                                  \
206        va_start(ap, p);                                        \
207        vrt_do_string(sp->wrk, sp->fd,                          \
208            http, fld, #obj "." #hdr, p, ap);                   \
209        va_end(ap);                                             \
210}
211
212VRT_DO_HDR(req,   request,      sp->http,               HTTP_HDR_REQ)
213VRT_DO_HDR(req,   url,          sp->http,               HTTP_HDR_URL)
214VRT_DO_HDR(req,   proto,        sp->http,               HTTP_HDR_PROTO)
215VRT_DO_HDR(bereq, request,      sp->bereq->http,        HTTP_HDR_REQ)
216VRT_DO_HDR(bereq, url,          sp->bereq->http,        HTTP_HDR_URL)
217VRT_DO_HDR(bereq, proto,        sp->bereq->http,        HTTP_HDR_PROTO)
218VRT_DO_HDR(obj,   proto,        sp->obj->http,          HTTP_HDR_PROTO)
219VRT_DO_HDR(obj,   response,     sp->obj->http,          HTTP_HDR_RESPONSE)
220VRT_DO_HDR(resp,  proto,        sp->http,               HTTP_HDR_PROTO)
221VRT_DO_HDR(resp,  response,     sp->http,               HTTP_HDR_RESPONSE)
222
223void
224VRT_l_obj_status(const struct sess *sp, int num)
225{
226        char *p;
227
228        assert(num >= 100 && num <= 999);
229        p = WS_Alloc(sp->obj->http->ws, 4);
230        if (p == NULL)
231                WSP(sp, SLT_LostHeader, "%s", "obj.status");
232        else
233                sprintf(p, "%d", num);
234        http_SetH(sp->obj->http, HTTP_HDR_STATUS, p);
235}
236
237int
238VRT_r_obj_status(const struct sess *sp)
239{
240        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
241        CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
242        /* XXX: use http_GetStatus() */
243        if (sp->obj->http->status)
244                return (sp->obj->http->status);
245        return (atoi(sp->obj->http->hd[HTTP_HDR_STATUS].b));
246}
247
248void
249VRT_l_resp_status(const struct sess *sp, int num)
250{
251        char *p;
252
253        assert(num >= 100 && num <= 999);
254        p = WS_Alloc(sp->http->ws, 4);
255        if (p == NULL)
256                WSP(sp, SLT_LostHeader, "%s", "resp.status");
257        else
258                sprintf(p, "%d", num);
259        http_SetH(sp->http, HTTP_HDR_STATUS, p);
260}
261
262/*--------------------------------------------------------------------*/
263
264void
265VRT_handling(struct sess *sp, unsigned hand)
266{
267
268        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
269        assert(!(hand & (hand -1)));    /* must be power of two */
270        sp->handling = hand;
271}
272
273/*--------------------------------------------------------------------
274 * XXX: Working relative to t_req is maybe not the right thing, we could
275 * XXX: have spent a long time talking to the backend since then.
276 * XXX: It might make sense to cache a timestamp as "current time"
277 * XXX: before vcl_recv (== t_req) and vcl_fetch.
278 * XXX: On the other hand, that might lead to inconsistent behaviour
279 * XXX: where an object expires while we are running VCL code, and
280 * XXX: and that may not be a good idea either.
281 * XXX: See also related t_req use in cache_hash.c
282 */
283
284void
285VRT_l_obj_ttl(const struct sess *sp, double a)
286{
287
288        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
289        CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);       /* XXX */
290        WSP(sp, SLT_TTL, "%u VCL %.0f %.0f",
291            sp->obj->xid, a, sp->t_req);
292        if (a < 0)
293                a = 0;
294        sp->obj->ttl = sp->t_req + a;
295        if (sp->obj->timer_idx != 0)
296                EXP_TTLchange(sp->obj);
297}
298
299double
300VRT_r_obj_ttl(const struct sess *sp)
301{
302        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
303        CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);       /* XXX */
304        return (sp->obj->ttl - sp->t_req);
305}
306
307/*--------------------------------------------------------------------
308 * obj.grace is relative to obj.ttl, so no special magic is necessary.
309 */
310
311void
312VRT_l_obj_grace(const struct sess *sp, double a)
313{
314
315        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
316        CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);       /* XXX */
317        if (a < 0)
318                a = 0;
319        sp->obj->grace = a;
320        if (sp->obj->timer_idx != 0)
321                EXP_TTLchange(sp->obj);
322}
323
324double
325VRT_r_obj_grace(const struct sess *sp)
326{
327        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
328        CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);       /* XXX */
329        return (sp->obj->grace);
330}
331
332/*--------------------------------------------------------------------*/
333
334/* XXX: the VCL_info messages has unexpected fractions on the ttl */
335
336void
337VRT_l_obj_prefetch(const struct sess *sp, double a)
338{
339
340        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
341        CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);       /* XXX */
342        sp->obj->prefetch = 0.0;
343        if (a == 0.0)
344                sp->obj->prefetch = a;
345        else if (a > 0.0 && a + sp->t_req <= sp->obj->ttl)
346                sp->obj->prefetch = a + sp->t_req;
347        else if (a < 0.0 && a + sp->obj->ttl > sp->t_req)
348                sp->obj->prefetch = a;
349        else if (a > 0.0)
350                WSL(sp->wrk, SLT_VCL_info, sp->id,
351                    "XID %u: obj.prefetch (%g) after TTL (%g), ignored.",
352                    sp->obj->xid, a, sp->obj->ttl - sp->t_req);
353        else /* if (a < 0.0) */
354                WSL(sp->wrk, SLT_VCL_info, sp->id,
355                    "XID %u: obj.prefetch (%g) less than ttl (%g), ignored.",
356                    sp->obj->xid, a, sp->obj->ttl - sp->t_req);
357        if (sp->obj->timer_idx != 0)
358                EXP_TTLchange(sp->obj);
359}
360
361double
362VRT_r_obj_prefetch(const struct sess *sp)
363{
364        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
365        CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);       /* XXX */
366        return (sp->obj->prefetch - sp->t_req);
367}
368
369/*--------------------------------------------------------------------*/
370
371#define VOBJ(type,onm,field)                                            \
372void                                                                    \
373VRT_l_obj_##onm(const struct sess *sp, type a)                          \
374{                                                                       \
375        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);                              \
376        CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);       /* XXX */       \
377        sp->obj->field = a;                                             \
378}                                                                       \
379                                                                        \
380type                                                                    \
381VRT_r_obj_##onm(const struct sess *sp)                                  \
382{                                                                       \
383        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);                              \
384        CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);       /* XXX */       \
385        return (sp->obj->field);                                        \
386}
387
388VOBJ(unsigned, valid, valid)
389VOBJ(unsigned, cacheable, cacheable)
390
391/*--------------------------------------------------------------------*/
392
393void
394VRT_l_req_backend(struct sess *sp, struct backend *be)
395{
396        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
397        sp->backend = be;
398}
399
400struct backend *
401VRT_r_req_backend(struct sess *sp)
402{
403        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
404        return (sp->backend);
405}
406
407/*--------------------------------------------------------------------*/
408
409#define  VREQ(n1, n2)                                   \
410const char *                                            \
411VRT_r_req_##n1(const struct sess *sp)                           \
412{                                                       \
413        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);              \
414        CHECK_OBJ_NOTNULL(sp->http, HTTP_MAGIC);        \
415        return (sp->http->hd[n2].b);                    \
416}
417
418VREQ(request, HTTP_HDR_REQ)
419VREQ(url, HTTP_HDR_URL)
420VREQ(proto, HTTP_HDR_PROTO)
421
422/*--------------------------------------------------------------------*/
423
424int
425VRT_r_req_restarts(const struct sess *sp)
426{
427
428        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
429        return (sp->restarts);
430}
431
432/*--------------------------------------------------------------------
433 * req.grace
434 */
435
436void
437VRT_l_req_grace(struct sess *sp, double a)
438{
439
440        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
441        if (a < 0)
442                a = 0;
443        sp->grace = a;
444}
445
446double
447VRT_r_req_grace(struct sess *sp)
448{
449        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
450        return (sp->grace);
451}
452
453/*--------------------------------------------------------------------*/
454
455const char *
456VRT_r_resp_proto(const struct sess *sp)
457{
458        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
459        CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
460        return (sp->obj->http->hd[HTTP_HDR_PROTO].b);
461}
462
463const char *
464VRT_r_resp_response(const struct sess *sp)
465{
466        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
467        CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
468        return (sp->obj->http->hd[HTTP_HDR_RESPONSE].b);
469}
470
471int
472VRT_r_resp_status(const struct sess *sp)
473{
474        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
475        CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
476        return (atoi(sp->obj->http->hd[HTTP_HDR_STATUS].b));
477}
478
479/*--------------------------------------------------------------------*/
480
481struct sockaddr *
482VRT_r_client_ip(const struct sess *sp)
483{
484
485        return (sp->sockaddr);
486}
487
488struct sockaddr *
489VRT_r_server_ip(struct sess *sp)
490{
491
492        if (sp->mysockaddr->sa_family == AF_UNSPEC)
493                AZ(getsockname(sp->fd, sp->mysockaddr, &sp->mysockaddrlen));
494
495        return (sp->mysockaddr);
496}
497
498/*--------------------------------------------------------------------
499 * Add an element to the array/list of hash bits.
500 */
501
502void
503VRT_l_req_hash(struct sess *sp, const char *str)
504{
505        int l;
506
507        if (str == NULL)
508                str = "";
509        l = strlen(str);
510
511        /*
512         * XXX: handle this by bouncing sp->vcl->nhashcount when it fails
513         * XXX: and dispose of this request either by reallocating the
514         * XXX: hashptr (if possible) or restarting/error the request
515         */
516        xxxassert(sp->ihashptr < sp->nhashptr);
517
518        sp->hashptr[sp->ihashptr] = str;
519        sp->hashptr[sp->ihashptr + 1] = str + l;
520        sp->ihashptr += 2;
521        sp->lhashptr += l + 1;
522}
523
524/*--------------------------------------------------------------------*/
525
526double
527VRT_r_now(const struct sess *sp)
528{
529
530        (void)sp;
531        return (TIM_mono());
532}
533
534double
535VRT_r_obj_lastuse(const struct sess *sp)
536{
537
538        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
539        CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);       /* XXX */
540        return (TIM_mono() - sp->obj->lru_stamp);
541}
542
543int
544VRT_r_backend_health(const struct sess *sp)
545{
546       
547        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
548        CHECK_OBJ_NOTNULL(sp->backend, BACKEND_MAGIC);
549        return (sp->backend->health);
550}
551
552/*--------------------------------------------------------------------*/
553
554char *
555VRT_IP_string(const struct sess *sp, const struct sockaddr *sa)
556{
557        char h[64], p[8], *q;
558        socklen_t len = 0;
559
560        /* XXX can't rely on sockaddr.sa_len */
561        switch (sa->sa_family) {
562        case AF_INET:
563                len = sizeof(struct sockaddr_in);
564                break;
565        case AF_INET6:
566                len = sizeof(struct sockaddr_in6);
567                break;
568        default:
569                INCOMPL();
570        }
571        XXXAN(len);
572        TCP_name(sa, len, h, sizeof h, p, sizeof p);
573        q = WS_Alloc(sp->http->ws, strlen(h) + strlen(p) + 2);
574        AN(q);
575        strcpy(q, h);
576        strcat(q, ":");
577        strcat(q, p);
578        return (q);
579}
580
581char *
582VRT_int_string(const struct sess *sp, int num)
583{
584        char *p;
585        int size = 12;
586       
587        p = WS_Alloc(sp->http->ws, size);
588        AN(p);
589        assert(snprintf(p, size, "%d", num) < size);
590        return (p);
591}
592
593/*--------------------------------------------------------------------*/
594
595void
596VRT_Rollback(struct sess *sp)
597{
598
599        *sp->http = *sp->http0;
600        WS_Reset(sp->ws, sp->ws_req);
601}
602       
603/*--------------------------------------------------------------------*/
604
605void
606VRT_purge(const char *regexp, int hash)
607{
608       
609        AddBan(regexp, hash);
610}
611
612/*--------------------------------------------------------------------
613 * Simple stuff
614 */
615
616int
617VRT_strcmp(const char *s1, const char *s2)
618{
619        if (s1 == NULL || s2 == NULL)
620                return(1);
621        return (strcmp(s1, s2));
622}
623
624
625/*--------------------------------------------------------------------
626 * Backend stuff
627 */
628
629void
630VRT_fini_backend(struct backend *b)
631{
632
633        VBE_DropRef(b); 
634}
Note: See TracBrowser for help on using the repository browser.