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