varnish-cache/vmod/vmod_directors_shard_cfg.c
1
/*-
2
 * Copyright 2009-2016 UPLEX - Nils Goroll Systemoptimierung
3
 * All rights reserved.
4
 *
5
 * Authors: Nils Goroll <nils.goroll@uplex.de>
6
 *          Geoffrey Simmons <geoff@uplex.de>
7
 *
8
 * SPDX-License-Identifier: BSD-2-Clause
9
 *
10
 * Redistribution and use in source and binary forms, with or without
11
 * modification, are permitted provided that the following conditions
12
 * are met:
13
 * 1. Redistributions of source code must retain the above copyright
14
 *    notice, this list of conditions and the following disclaimer.
15
 * 2. Redistributions in binary form must reproduce the above copyright
16
 *    notice, this list of conditions and the following disclaimer in the
17
 *    documentation and/or other materials provided with the distribution.
18
 *
19
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
23
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
 * SUCH DAMAGE.
30
 */
31
32
#include "config.h"
33
34
#include <limits.h>
35
#include <stdlib.h>
36
#include <stdio.h>
37
#include <string.h>
38
39
#include "cache/cache.h"
40
41
#include "vmod_directors_shard_dir.h"
42
#include "vmod_directors_shard_cfg.h"
43
44
/*lint -esym(749,  shard_change_task_e::*) */
45
enum shard_change_task_e {
46
        _SHARD_TASK_E_INVALID = 0,
47
        CLEAR,
48
        ADD_BE,
49
        REMOVE_BE,
50
        _SHARD_TASK_E_MAX
51
};
52
53
struct shard_change_task {
54
        unsigned                                magic;
55
#define SHARD_CHANGE_TASK_MAGIC                 0x1e1168af
56
        enum shard_change_task_e                task;
57
        void                                    *priv;
58
        VCL_REAL                                weight;
59
        VSTAILQ_ENTRY(shard_change_task)        list;
60
};
61
62
struct shard_change {
63
        unsigned                                magic;
64
#define SHARD_CHANGE_MAGIC                      0xdff5c9a6
65
        struct vsl_log                          *vsl;
66
        struct sharddir                         *shardd;
67
        VSTAILQ_HEAD(,shard_change_task)        tasks;
68
};
69
70
struct backend_reconfig {
71
        struct sharddir * const shardd;
72
        unsigned                hint;   // on number of backends after reconfig
73
        unsigned                hole_n; // number of holes in backends array
74
        unsigned                hole_i; // index hint on first hole
75
};
76
77
/* forward decl */
78
static VCL_BOOL
79
change_reconfigure(VRT_CTX, struct shard_change *change, VCL_INT replicas);
80
81
/*
82
 * ============================================================
83
 * change / task list
84
 *
85
 * for backend reconfiguration, we create a change list on the VCL workspace in
86
 * a PRIV_TASK state, which we work in reconfigure.
87
 */
88
89
static void v_matchproto_(vmod_priv_fini_f)
90 399
shard_change_fini(VRT_CTX, void * priv)
91
{
92
        struct shard_change *change;
93
94 399
        if (priv == NULL)
95 0
                return;
96
97 399
        CAST_OBJ_NOTNULL(change, priv, SHARD_CHANGE_MAGIC);
98
99 399
        (void) change_reconfigure(ctx, change, 67);
100 399
}
101
102
static const struct vmod_priv_methods shard_change_priv_methods[1] = {{
103
        .magic = VMOD_PRIV_METHODS_MAGIC,
104
        .type = "vmod_directors_shard_cfg",
105
        .fini = shard_change_fini
106
}};
107
108
static struct shard_change *
109 4137
shard_change_get(VRT_CTX, struct sharddir * const shardd)
110
{
111
        struct vmod_priv *task;
112
        struct shard_change *change;
113 4137
        const void *id = (const char *)shardd + task_off_cfg;
114
115 4137
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
116
117 4137
        task = VRT_priv_task(ctx, id);
118 4137
        if (task == NULL) {
119 0
                shard_fail(ctx, shardd->name, "%s", "no priv_task");
120 0
                return (NULL);
121
        }
122
123 4137
        if (task->priv != NULL) {
124 3738
                CAST_OBJ_NOTNULL(change, task->priv, SHARD_CHANGE_MAGIC);
125 3738
                assert (change->vsl == ctx->vsl);
126 3738
                assert (change->shardd == shardd);
127 3738
                return (change);
128
        }
129
130 399
        change = WS_Alloc(ctx->ws, sizeof(*change));
131 399
        if (change == NULL) {
132 0
                shard_fail(ctx, shardd->name, "%s", "could not get workspace");
133 0
                return (NULL);
134
        }
135
136 399
        INIT_OBJ(change, SHARD_CHANGE_MAGIC);
137 399
        change->vsl = ctx->vsl;
138 399
        change->shardd = shardd;
139 399
        VSTAILQ_INIT(&change->tasks);
140 399
        task->priv = change;
141 399
        task->methods = shard_change_priv_methods;
142
143 399
        return (change);
144 4137
}
145
146
static void
147 840
shard_change_finish(struct shard_change *change)
148
{
149 840
        CHECK_OBJ_NOTNULL(change, SHARD_CHANGE_MAGIC);
150
151 840
        VSTAILQ_INIT(&change->tasks);
152 840
}
153
154
static struct shard_change_task *
155 3297
shard_change_task_add(VRT_CTX, struct shard_change *change,
156
    enum shard_change_task_e task_e, void *priv)
157
{
158
        struct shard_change_task *task;
159
160 3297
        CHECK_OBJ_NOTNULL(change, SHARD_CHANGE_MAGIC);
161
162 3297
        task = WS_Alloc(ctx->ws, sizeof(*task));
163 3297
        if (task == NULL) {
164 0
                shard_fail(ctx, change->shardd->name, "%s",
165
                    "could not get workspace for task");
166 0
                return (NULL);
167
        }
168 3297
        INIT_OBJ(task, SHARD_CHANGE_TASK_MAGIC);
169 3297
        task->task = task_e;
170 3297
        task->priv = priv;
171 3297
        VSTAILQ_INSERT_TAIL(&change->tasks, task, list);
172
173 3297
        return (task);
174 3297
}
175
176
static inline struct shard_change_task *
177 2982
shard_change_task_backend(VRT_CTX, struct sharddir *shardd,
178
    enum shard_change_task_e task_e, VCL_BACKEND be, VCL_STRING ident,
179
    VCL_DURATION rampup)
180
{
181
        struct shard_change *change;
182
        struct shard_backend *b;
183
184 2982
        CHECK_OBJ_NOTNULL(shardd, SHARDDIR_MAGIC);
185 2982
        assert(task_e == ADD_BE || task_e == REMOVE_BE);
186
187 2982
        change = shard_change_get(ctx, shardd);
188 2982
        if (change == NULL)
189 0
                return (NULL);
190
191 2982
        b = WS_Alloc(ctx->ws, sizeof(*b));
192 2982
        if (b == NULL) {
193 0
                shard_fail(ctx, change->shardd->name, "%s",
194
                    "could not get workspace for task");
195 0
                return (NULL);
196
        }
197
198 2982
        b->backend = be;
199 2982
        b->ident = ident != NULL && *ident != '\0' ? ident : NULL;
200 2982
        b->rampup = rampup;
201
202 2982
        return (shard_change_task_add(ctx, change, task_e, b));
203 2982
}
204
205
/*
206
 * ============================================================
207
 * director reconfiguration tasks
208
 */
209
VCL_BOOL
210 2373
shardcfg_add_backend(VRT_CTX, struct sharddir *shardd,
211
    VCL_BACKEND be, VCL_STRING ident, VCL_DURATION rampup, VCL_REAL weight)
212
{
213
        struct shard_change_task *task;
214
215 2373
        assert (weight >= 1);
216 2373
        AN(be);
217
218 4746
        task = shard_change_task_backend(ctx, shardd, ADD_BE,
219 2373
            be, ident, rampup);
220
221 2373
        if (task == NULL)
222 0
                return (0);
223
224 2373
        task->weight = weight;
225 2373
        return (1);
226 2373
}
227
228
VCL_BOOL
229 609
shardcfg_remove_backend(VRT_CTX, struct sharddir *shardd,
230
    VCL_BACKEND be, VCL_STRING ident)
231
{
232 1827
        return (shard_change_task_backend(ctx, shardd, REMOVE_BE,
233 1218
            be, ident, 0) != NULL);
234
}
235
236
VCL_BOOL
237 315
shardcfg_clear(VRT_CTX, struct sharddir *shardd)
238
{
239
        struct shard_change *change;
240
241 315
        CHECK_OBJ_NOTNULL(shardd, SHARDDIR_MAGIC);
242
243 315
        change = shard_change_get(ctx, shardd);
244 315
        if (change == NULL)
245 0
                return (0);
246
247 315
        return (shard_change_task_add(ctx, change, CLEAR, NULL) != NULL);
248 315
}
249
250
/*
251
 * ============================================================
252
 * consistent hashing cirle init
253
 */
254
255
typedef int (*compar)( const void*, const void* );
256
257
static int
258 218883
circlepoint_compare(const struct shard_circlepoint *a,
259
    const struct shard_circlepoint *b)
260
{
261 218883
        return ((a->point == b->point) ? 0 : ((a->point > b->point) ? 1 : -1));
262
}
263
264
static void
265 756
shardcfg_hashcircle(struct sharddir *shardd)
266
{
267
        const struct shard_backend *backends, *b;
268
        unsigned h;
269
        uint32_t i, j, n_points, r, rmax;
270
        const char *ident;
271 756
        const int len = 12; // log10(UINT32_MAX) + 2;
272
        char s[len];
273
        struct strands ss[1];
274
        const char *ssp[2];
275
276 756
        CHECK_OBJ_NOTNULL(shardd, SHARDDIR_MAGIC);
277 756
        AZ(shardd->hashcircle);
278
279 756
        assert(shardd->n_backend > 0);
280 756
        backends=shardd->backend;
281 756
        AN(backends);
282
283 756
        n_points = 0;
284 756
        rmax = (UINT32_MAX - 1) / shardd->n_backend;
285 3927
        for (b = backends; b < backends + shardd->n_backend; b++) {
286 3171
                CHECK_OBJ_NOTNULL(b->backend, DIRECTOR_MAGIC);
287 3171
                r = b->replicas;
288 3171
                if (r > rmax)
289 0
                        r = rmax;
290 3171
                n_points += r;
291 3171
        }
292
293 756
        assert(n_points < UINT32_MAX);
294
295 756
        shardd->n_points = n_points;
296 756
        shardd->hashcircle = calloc(n_points, sizeof(struct shard_circlepoint));
297 756
        AN(shardd->hashcircle);
298
299 756
        i = 0;
300 3927
        for (h = 0, b = backends; h < shardd->n_backend; h++, b++) {
301 3171
                ident = b->ident ? b->ident : VRT_BACKEND_string(b->backend);
302
303 3171
                AN(ident);
304 3171
                assert(ident[0] != '\0');
305
306 3171
                r = b->replicas;
307 3171
                if (r > rmax)
308 0
                        r = rmax;
309
310 38535
                for (j = 0; j < r; j++) {
311 35364
                        assert(snprintf(s, len, "%d", j) < len);
312 35364
                        ss->n = 2;
313 35364
                        ssp[0] = ident;
314 35364
                        ssp[1] = s;
315 35364
                        ss->p = ssp;
316 35364
                        assert (i < n_points);
317 35364
                        shardd->hashcircle[i].point = VRT_HashStrands32(ss);
318 35364
                        shardd->hashcircle[i].host = h;
319 35364
                        i++;
320 35364
                }
321 3171
        }
322 756
        assert (i == n_points);
323 756
        qsort( (void *) shardd->hashcircle, n_points,
324
            sizeof (struct shard_circlepoint), (compar) circlepoint_compare);
325
326 756
        if ((shardd->debug_flags & SHDBG_CIRCLE) == 0)
327 273
                return;
328
329 13209
        for (i = 0; i < n_points; i++)
330 12726
                SHDBG(SHDBG_CIRCLE, shardd,
331
                    "hashcircle[%5jd] = {point = %8x, host = %2u}\n",
332
                    (intmax_t)i, shardd->hashcircle[i].point,
333
                    shardd->hashcircle[i].host);
334 756
}
335
336
/*
337
 * ============================================================
338
 * configure the director backends
339
 */
340
341
static void
342 966
shardcfg_backend_free(struct shard_backend *f)
343
{
344 966
        if (f->freeptr)
345 735
                free (f->freeptr);
346 966
        memset(f, 0, sizeof(*f));
347 966
}
348
349
static void
350 2037
shardcfg_backend_copyin(struct shard_backend *dst,
351
    const struct shard_backend *src)
352
{
353 2037
        dst->backend = src->backend;
354 2037
        dst->ident = src->ident ? strdup(src->ident) : NULL;
355 2037
        dst->rampup = src->rampup;
356 2037
}
357
358
static int
359 14994
shardcfg_backend_cmp(const struct shard_backend *a,
360
    const struct shard_backend *b)
361
{
362
        const char *ai, *bi;
363
364 14994
        ai = a->ident;
365 14994
        bi = b->ident;
366
367 14994
        assert(ai || a->backend);
368 14994
        assert(bi || b->backend);
369
370
        /* vcl_names are unique, so we can compare the backend pointers */
371 14994
        if (ai == NULL && bi == NULL)
372 987
                return (a->backend != b->backend);
373
374 14007
        if (ai == NULL)
375 126
                ai = VRT_BACKEND_string(a->backend);
376
377 14007
        if (bi == NULL)
378 315
                bi = VRT_BACKEND_string(b->backend);
379
380 14007
        AN(ai);
381 14007
        AN(bi);
382 14007
        return (strcmp(ai, bi));
383 14994
}
384
385
/* for removal, we delete all instances if the backend matches */
386
static int
387 6825
shardcfg_backend_del_cmp(const struct shard_backend *task,
388
    const struct shard_backend *b)
389
{
390 6825
        assert(task->backend || task->ident);
391
392 6825
        if (task->ident == NULL)
393 189
                return (task->backend != b->backend);
394
395 6636
        return (shardcfg_backend_cmp(task, b));
396 6825
}
397
398
static const struct shard_backend *
399 2205
shardcfg_backend_lookup(const struct backend_reconfig *re,
400
    const struct shard_backend *b)
401
{
402 2205
        unsigned i, max = re->shardd->n_backend + re->hole_n;
403 2205
        const struct shard_backend *bb = re->shardd->backend;
404
405 2205
        if (max > 0)
406 1680
                AN(bb);
407
408 10521
        for (i = 0; i < max; i++) {
409 8484
                if (bb[i].backend == NULL)
410 126
                        continue;       // hole
411 8358
                if (!shardcfg_backend_cmp(b, &bb[i]))
412 168
                        return (&bb[i]);
413 8190
        }
414 2037
        return (NULL);
415 2205
}
416
417
static void
418 399
shardcfg_backend_expand(const struct backend_reconfig *re)
419
{
420 399
        unsigned min = re->hint;
421
422 399
        CHECK_OBJ_NOTNULL(re->shardd, SHARDDIR_MAGIC);
423
424 399
        if (min < 16)
425 378
                min = 16;
426
427 399
        if (re->shardd->l_backend < min)
428 399
                re->shardd->l_backend = min;
429
        else
430 0
                re->shardd->l_backend *= 2;
431
432 798
        re->shardd->backend = realloc(re->shardd->backend,
433 399
            re->shardd->l_backend * sizeof *re->shardd->backend);
434
435 399
        AN(re->shardd->backend);
436 399
}
437
438
static void
439 2037
shardcfg_backend_add(struct backend_reconfig *re,
440
    const struct shard_backend *b, uint32_t replicas)
441
{
442
        unsigned i;
443 2037
        struct shard_backend *bb = re->shardd->backend;
444
445 2037
        if (re->hole_n == 0) {
446 1953
                if (re->shardd->n_backend >= re->shardd->l_backend) {
447 399
                        shardcfg_backend_expand(re);
448 399
                        bb = re->shardd->backend;
449 399
                }
450 1953
                assert(re->shardd->n_backend < re->shardd->l_backend);
451 1953
                i = re->shardd->n_backend;
452 1953
        } else {
453 84
                assert(re->hole_i != UINT_MAX);
454 84
                do {
455 84
                        if (!bb[re->hole_i].backend)
456 84
                                break;
457 0
                } while (++(re->hole_i) < re->shardd->n_backend + re->hole_n);
458 84
                assert(re->hole_i < re->shardd->n_backend + re->hole_n);
459
460 84
                i = (re->hole_i)++;
461 84
                (re->hole_n)--;
462
        }
463
464 2037
        re->shardd->n_backend++;
465 2037
        shardcfg_backend_copyin(&bb[i], b);
466 2037
        bb[i].replicas = replicas;
467 2037
}
468
469
static void
470 273
shardcfg_backend_clear(struct sharddir *shardd)
471
{
472
        unsigned i;
473 588
        for (i = 0; i < shardd->n_backend; i++)
474 315
                shardcfg_backend_free(&shardd->backend[i]);
475 273
        shardd->n_backend = 0;
476 273
}
477
478
479
static void
480 609
shardcfg_backend_del(struct backend_reconfig *re,
481
    const struct shard_backend *spec)
482
{
483 609
        unsigned i, max = re->shardd->n_backend + re->hole_n;
484 609
        struct shard_backend * const bb = re->shardd->backend;
485
486 9996
        for (i = 0; i < max; i++) {
487 9387
                if (bb[i].backend == NULL)
488 2562
                        continue;       // hole
489 6825
                if (shardcfg_backend_del_cmp(spec, &bb[i]))
490 6174
                        continue;
491
492 651
                shardcfg_backend_free(&bb[i]);
493 651
                re->shardd->n_backend--;
494 651
                if (i < re->shardd->n_backend + re->hole_n) {
495 567
                        (re->hole_n)++;
496 567
                        if (i < re->hole_i)
497 210
                                re->hole_i = i;
498 567
                }
499 651
        }
500 609
}
501
502
static void
503 756
shardcfg_backend_finalize(struct backend_reconfig *re)
504
{
505
        unsigned i;
506 756
        struct shard_backend * const bb = re->shardd->backend;
507
508 882
        while (re->hole_n > 0) {
509
                // trim end
510 189
                i = re->shardd->n_backend + re->hole_n - 1;
511 546
                while (re->hole_n && bb[i].backend == NULL) {
512 357
                        (re->hole_n)--;
513 357
                        i--;
514
                }
515
516 189
                if (re->hole_n == 0)
517 63
                        break;
518
519 126
                assert(re->hole_i < i);
520
521 126
                do {
522 126
                        if (!bb[re->hole_i].backend)
523 126
                                break;
524 0
                } while (++(re->hole_i) <= i);
525
526 126
                assert(re->hole_i < i);
527 126
                assert(bb[re->hole_i].backend == NULL);
528 126
                assert(bb[i].backend != NULL);
529
530 126
                memcpy(&bb[re->hole_i], &bb[i], sizeof(*bb));
531 126
                memset(&bb[i], 0, sizeof(*bb));
532
533 126
                (re->hole_n)--;
534 126
                (re->hole_i)++;
535
        }
536
537 756
        assert(re->hole_n == 0);
538 756
}
539
540
/*
541
 * ============================================================
542
 * work the change tasks
543
 */
544
545
static void
546 840
shardcfg_apply_change(struct vsl_log *vsl, struct sharddir *shardd,
547
    const struct shard_change *change, VCL_INT replicas)
548
{
549
        struct shard_change_task *task, *clear;
550
        const struct shard_backend *b;
551
        uint32_t b_replicas;
552
553 2520
        struct backend_reconfig re = {
554 840
                .shardd = shardd,
555 840
                .hint = shardd->n_backend,
556
                .hole_n = 0,
557
                .hole_i = UINT_MAX
558
        };
559
560
        // XXX assert sharddir_locked(shardd)
561
562 840
        clear = NULL;
563 4137
        VSTAILQ_FOREACH(task, &change->tasks, list) {
564 3297
                CHECK_OBJ_NOTNULL(task, SHARD_CHANGE_TASK_MAGIC);
565 3297
                switch (task->task) {
566
                case CLEAR:
567 315
                        clear = task;
568 315
                        re.hint = 0;
569 315
                        break;
570
                case ADD_BE:
571 2373
                        re.hint++;
572 2373
                        break;
573
                case REMOVE_BE:
574 609
                        re.hint--;
575 609
                        break;
576
                default:
577 0
                        INCOMPL();
578 0
                }
579 3297
        }
580
581 840
        if (clear) {
582 273
                shardcfg_backend_clear(shardd);
583 273
                clear = VSTAILQ_NEXT(clear, list);
584 273
                if (clear == NULL)
585 84
                        return;
586 189
        }
587
588 756
        task = clear;
589 3570
        VSTAILQ_FOREACH_FROM(task, &change->tasks, list) {
590 2814
                CHECK_OBJ_NOTNULL(task, SHARD_CHANGE_TASK_MAGIC);
591 2814
                switch (task->task) {
592
                case CLEAR:
593 0
                        assert(task->task != CLEAR);
594 0
                        break;
595
                case ADD_BE:
596 2205
                        b = shardcfg_backend_lookup(&re, task->priv);
597
598 2205
                        if (b == NULL) {
599 2037
                                assert (task->weight >= 1);
600 2037
                                if (replicas * task->weight > UINT32_MAX)
601 0
                                        b_replicas = UINT32_MAX;
602
                                else
603 2037
                                        b_replicas = (uint32_t) // flint
604 2037
                                                (replicas * task->weight);
605
606 4074
                                shardcfg_backend_add(&re, task->priv,
607 2037
                                    b_replicas);
608 2037
                                break;
609
                        }
610
611 168
                        const char * const ident = b->ident;
612
613 168
                        shard_notice(vsl, shardd->name,
614
                            "backend %s%s%s already exists - skipping",
615
                            VRT_BACKEND_string(b->backend),
616
                            ident ? "/" : "",
617
                            ident ? ident : "");
618 168
                        break;
619
                case REMOVE_BE:
620 609
                        shardcfg_backend_del(&re, task->priv);
621 609
                        break;
622
                default:
623 0
                        INCOMPL();
624 0
                }
625 2814
        }
626 756
        shardcfg_backend_finalize(&re);
627 840
}
628
629
/*
630
 * ============================================================
631
 * top reconfiguration function
632
 */
633
634
static VCL_BOOL
635 1239
change_reconfigure(VRT_CTX, struct shard_change *change, VCL_INT replicas)
636
{
637
        struct sharddir *shardd;
638
639 1239
        CHECK_OBJ_NOTNULL(change, SHARD_CHANGE_MAGIC);
640 1239
        assert (replicas > 0);
641 1239
        shardd = change->shardd;
642 1239
        CHECK_OBJ_NOTNULL(shardd, SHARDDIR_MAGIC);
643
644 1239
        if (VSTAILQ_FIRST(&change->tasks) == NULL)
645 399
                return (1);
646
647 840
        sharddir_wrlock(shardd);
648
649 840
        shardcfg_apply_change(ctx->vsl, shardd, change, replicas);
650 840
        shard_change_finish(change);
651
652 840
        if (shardd->hashcircle)
653 378
                free(shardd->hashcircle);
654 840
        shardd->hashcircle = NULL;
655
656 840
        if (shardd->n_backend == 0) {
657 84
                shard_err0(ctx->vsl, shardd->name,
658
                    ".reconfigure() no backends");
659 84
                sharddir_unlock(shardd);
660 84
                return (0);
661
        }
662
663 756
        shardcfg_hashcircle(shardd);
664 756
        sharddir_unlock(shardd);
665 756
        return (1);
666 1239
}
667
668
VCL_BOOL
669 882
shardcfg_reconfigure(VRT_CTX, struct sharddir *shardd, VCL_INT replicas)
670
{
671
        struct shard_change *change;
672
673 882
        CHECK_OBJ_NOTNULL(shardd, SHARDDIR_MAGIC);
674 882
        if (replicas <= 0) {
675 42
                shard_err(ctx->vsl, shardd->name,
676
                    ".reconfigure() invalid replicas argument %ld", replicas);
677 42
                return (0);
678
        }
679
680 840
        change = shard_change_get(ctx, shardd);
681 840
        if (change == NULL)
682 0
                return (0);
683
684 840
        return (change_reconfigure(ctx, change, replicas));
685 882
}
686
687
/*
688
 * ============================================================
689
 * misc config related
690
 */
691
692
/* only for sharddir_delete() */
693
void
694 105
shardcfg_delete(const struct sharddir *shardd)
695
{
696
        unsigned i;
697
698 105
        for (i = 0; i < shardd->n_backend; i++)
699 0
                shardcfg_backend_free(&shardd->backend[i]);
700 105
        if (shardd->backend)
701 0
                free(shardd->backend);
702 105
        if (shardd->hashcircle)
703 0
                free(shardd->hashcircle);
704 105
}
705
706
VCL_VOID
707 42
shardcfg_set_warmup(struct sharddir *shardd, VCL_REAL ratio)
708
{
709 42
        CHECK_OBJ_NOTNULL(shardd, SHARDDIR_MAGIC);
710 42
        assert(ratio >= 0 && ratio < 1);
711 42
        sharddir_wrlock(shardd);
712 42
        shardd->warmup = ratio;
713 42
        sharddir_unlock(shardd);
714 42
}
715
716
VCL_VOID
717 42
shardcfg_set_rampup(struct sharddir *shardd, VCL_DURATION duration)
718
{
719 42
        CHECK_OBJ_NOTNULL(shardd, SHARDDIR_MAGIC);
720 42
        assert(duration >= 0);
721 42
        sharddir_wrlock(shardd);
722 42
        shardd->rampup_duration = duration;
723 42
        sharddir_unlock(shardd);
724 42
}
725
726
VCL_DURATION
727 3402
shardcfg_get_rampup(const struct sharddir *shardd, unsigned host)
728
{
729
        VCL_DURATION r;
730
731 3402
        CHECK_OBJ_NOTNULL(shardd, SHARDDIR_MAGIC);
732
        // assert sharddir_rdlock_held(shardd);
733 3402
        assert (host < shardd->n_backend);
734
735 3402
        if (isnan(shardd->backend[host].rampup))
736 3318
                r = shardd->rampup_duration;
737
        else
738 84
                r = shardd->backend[host].rampup;
739
740 3402
        return (r);
741
}