varnish-cache/lib/libvmod_directors/vdir.c
1
/*-
2
 * Copyright (c) 2013-2015 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Poul-Henning Kamp <phk@FreeBSD.org>
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
20
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
 * SUCH DAMAGE.
27
 */
28
29
#include "config.h"
30
31
#include <stdlib.h>
32
33
#include "cache/cache.h"
34
35
#include "vbm.h"
36
37
#include "vdir.h"
38
39
static void
40 24
vdir_expand(struct vdir *vd, unsigned n)
41
{
42 24
        CHECK_OBJ_NOTNULL(vd, VDIR_MAGIC);
43
44 24
        vd->backend = realloc(vd->backend, n * sizeof *vd->backend);
45 24
        AN(vd->backend);
46 24
        vd->weight = realloc(vd->weight, n * sizeof *vd->weight);
47 24
        AN(vd->weight);
48 24
        vd->l_backend = n;
49 24
}
50
51
void
52 27
vdir_new(VRT_CTX, struct vdir **vdp, const char *vcl_name,
53
    const struct vdi_methods *m, void *priv)
54
{
55
        struct vdir *vd;
56
57 27
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
58 27
        CHECK_OBJ_NOTNULL(m, VDI_METHODS_MAGIC);
59 27
        AN(vcl_name);
60 27
        AN(vdp);
61 27
        AZ(*vdp);
62 27
        ALLOC_OBJ(vd, VDIR_MAGIC);
63 27
        AN(vd);
64 27
        *vdp = vd;
65 27
        AZ(pthread_rwlock_init(&vd->mtx, NULL));
66 27
        vd->dir = VRT_AddDirector(ctx, m, priv, "%s", vcl_name);
67 27
        vd->vbm = vbit_new(8);
68 27
        AN(vd->vbm);
69 27
}
70
71
void
72 5
vdir_delete(struct vdir **vdp)
73
{
74
        struct vdir *vd;
75
76 5
        TAKE_OBJ_NOTNULL(vd, vdp, VDIR_MAGIC);
77
78 5
        AZ(vd->dir);
79 5
        free(vd->backend);
80 5
        free(vd->weight);
81 5
        AZ(pthread_rwlock_destroy(&vd->mtx));
82 5
        vbit_destroy(vd->vbm);
83 5
        FREE_OBJ(vd);
84 5
}
85
86
void
87 70
vdir_rdlock(struct vdir *vd)
88
{
89 70
        CHECK_OBJ_NOTNULL(vd, VDIR_MAGIC);
90 70
        AZ(pthread_rwlock_rdlock(&vd->mtx));
91 70
}
92
93
void
94 140
vdir_wrlock(struct vdir *vd)
95
{
96 140
        CHECK_OBJ_NOTNULL(vd, VDIR_MAGIC);
97 140
        AZ(pthread_rwlock_wrlock(&vd->mtx));
98 140
}
99
100
void
101 210
vdir_unlock(struct vdir *vd)
102
{
103 210
        CHECK_OBJ_NOTNULL(vd, VDIR_MAGIC);
104 210
        AZ(pthread_rwlock_unlock(&vd->mtx));
105 210
}
106
107
108
void
109 61
vdir_add_backend(VRT_CTX, struct vdir *vd, VCL_BACKEND be, double weight)
110
{
111
        unsigned u;
112
113 61
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
114 61
        CHECK_OBJ_NOTNULL(vd, VDIR_MAGIC);
115 61
        if (be == NULL) {
116 3
                VRT_fail(ctx, "%s: NULL backend cannot be added",
117
                    VRT_BACKEND_string(vd->dir));
118 3
                return;
119
        }
120 58
        AN(be);
121 58
        vdir_wrlock(vd);
122 58
        if (vd->n_backend >= vd->l_backend)
123 24
                vdir_expand(vd, vd->l_backend + 16);
124 58
        assert(vd->n_backend < vd->l_backend);
125 58
        u = vd->n_backend++;
126 58
        vd->backend[u] = be;
127 58
        vd->weight[u] = weight;
128 58
        vd->total_weight += weight;
129 58
        vdir_unlock(vd);
130
}
131
132
void
133 12
vdir_remove_backend(VRT_CTX, struct vdir *vd, VCL_BACKEND be, unsigned *cur)
134
{
135
        unsigned u, n;
136
137 12
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
138 12
        CHECK_OBJ_NOTNULL(vd, VDIR_MAGIC);
139 12
        if (be == NULL) {
140 0
                VRT_fail(ctx, "%s: NULL backend cannot be removed",
141
                    VRT_BACKEND_string(vd->dir));
142 0
                return;
143
        }
144 12
        CHECK_OBJ(be, DIRECTOR_MAGIC);
145 12
        vdir_wrlock(vd);
146 17
        for (u = 0; u < vd->n_backend; u++)
147 17
                if (vd->backend[u] == be)
148 12
                        break;
149 12
        if (u == vd->n_backend) {
150 0
                vdir_unlock(vd);
151 0
                return;
152
        }
153 12
        vd->total_weight -= vd->weight[u];
154 12
        n = (vd->n_backend - u) - 1;
155 12
        memmove(&vd->backend[u], &vd->backend[u+1], n * sizeof(vd->backend[0]));
156 12
        memmove(&vd->weight[u], &vd->weight[u+1], n * sizeof(vd->weight[0]));
157 12
        vd->n_backend--;
158
159 12
        if (cur) {
160 4
                assert(*cur <= vd->n_backend);
161 4
                if (u < *cur)
162 1
                        (*cur)--;
163 3
                else if (*cur == vd->n_backend)
164 1
                        *cur = 0;
165
        }
166 12
        vdir_unlock(vd);
167
}
168
169
VCL_BOOL
170 30
vdir_any_healthy(VRT_CTX, struct vdir *vd, VCL_TIME *changed)
171
{
172 30
        unsigned retval = 0;
173
        VCL_BACKEND be;
174
        unsigned u;
175
        double c;
176
177 30
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
178 30
        CHECK_OBJ_NOTNULL(vd, VDIR_MAGIC);
179 30
        vdir_rdlock(vd);
180 30
        if (changed != NULL)
181 0
                *changed = 0;
182 40
        for (u = 0; u < vd->n_backend; u++) {
183 36
                be = vd->backend[u];
184 36
                CHECK_OBJ_NOTNULL(be, DIRECTOR_MAGIC);
185 36
                retval = VRT_Healthy(ctx, be, &c);
186 36
                if (changed != NULL && c > *changed)
187 0
                        *changed = c;
188 36
                if (retval)
189 26
                        break;
190
        }
191 30
        vdir_unlock(vd);
192 30
        return (retval);
193
}
194
195
static unsigned
196 46
vdir_pick_by_weight(const struct vdir *vd, double w,
197
    const struct vbitmap *blacklist)
198
{
199 46
        double a = 0.0;
200 46
        VCL_BACKEND be = NULL;
201
        unsigned u;
202
203 46
        AN(blacklist);
204 71
        for (u = 0; u < vd->n_backend; u++) {
205 71
                be = vd->backend[u];
206 71
                CHECK_OBJ_NOTNULL(be, DIRECTOR_MAGIC);
207 71
                if (vbit_test(blacklist, u))
208 4
                        continue;
209 67
                a += vd->weight[u];
210 67
                if (w < a)
211 92
                        return (u);
212
        }
213 0
        WRONG("");
214
}
215
216
VCL_BACKEND
217 47
vdir_pick_be(VRT_CTX, struct vdir *vd, double w)
218
{
219
        unsigned u;
220 47
        double tw = 0.0;
221 47
        VCL_BACKEND be = NULL;
222
223 47
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
224 47
        CHECK_OBJ_NOTNULL(vd, VDIR_MAGIC);
225 47
        vdir_wrlock(vd);
226 139
        for (u = 0; u < vd->n_backend; u++) {
227 92
                if (VRT_Healthy(ctx, vd->backend[u], NULL)) {
228 85
                        vbit_clr(vd->vbm, u);
229 85
                        tw += vd->weight[u];
230
                } else
231 7
                        vbit_set(vd->vbm, u);
232
        }
233 47
        if (tw > 0.0) {
234 46
                u = vdir_pick_by_weight(vd, w * tw, vd->vbm);
235 46
                assert(u < vd->n_backend);
236 46
                be = vd->backend[u];
237 46
                CHECK_OBJ_NOTNULL(be, DIRECTOR_MAGIC);
238
        }
239 47
        vdir_unlock(vd);
240 47
        return (be);
241
}